Finden Sie heraus, welche Dateideskriptoren dieselbe "offene Dateibeschreibung" haben.

17

Wenn ich das tue (in einer Bourne-ähnlichen Shell):

exec 3> file 4>&3 5> file 6>> file

Die Dateideskriptoren 3 und 4 haben dup()dieselbe offene Dateibeschreibung (gleiche Eigenschaften, gleicher Versatz in der Datei ...) , da 4 von 3 abgeleitet wurde . Während sich die Dateideskriptoren 5 und 6 dieses Prozesses in einer anderen offenen Dateibeschreibung befinden (z. B. haben sie jeweils einen eigenen Zeiger in der Datei).

In der lsofAusgabe sehen wir nur:

zsh     21519 stephane    3w   REG  254,2        0 10505865 /home/stephane/file
zsh     21519 stephane    4w   REG  254,2        0 10505865 /home/stephane/file
zsh     21519 stephane    5w   REG  254,2        0 10505865 /home/stephane/file
zsh     21519 stephane    6w   REG  254,2        0 10505865 /home/stephane/file

Es ist ein bisschen besser mit lsof +fg:

zsh     21519 stephane    3w   REG          W,LG  254,2        0 10505865 /home/stephane/file
zsh     21519 stephane    4w   REG          W,LG  254,2        0 10505865 /home/stephane/file
zsh     21519 stephane    5w   REG          W,LG  254,2        0 10505865 /home/stephane/file
zsh     21519 stephane    6w   REG       W,AP,LG  254,2        0 10505865 /home/stephane/file

(hier unter Linux 3.16) Da fd 6 unterschiedliche Flags hat, muss es sich um eine andere offene Dateibeschreibung handeln als fd 3, 4 oder 5, von der wir jedoch nicht sagen können, dass fd 5 auf a liegt andere offene Dateibeschreibung . Mit -okönnten wir auch den Versatz sehen, aber der gleiche Versatz garantiert nicht, dass es die gleiche offene Dateibeschreibung ist .

Gibt es einen nicht-intrusive 1 Weg , das herauszufinden? Extern oder für eigene Dateideskriptoren eines Prozesses?


1 . Ein heuristischer Ansatz könnte darin bestehen, die Flags einer FD zu ändern fcntl()und zu sehen, welche anderen Dateideskriptoren ihre Flags als Ergebnis aktualisieren, aber das ist offensichtlich weder ideal noch narrensicher

Stéphane Chazelas
quelle
Dieser Ansatz sollte im Prinzip funktionieren und in den meisten Szenarien nicht zu störend sein: Zuerst ein Kind gabeln (mit ptrace, wenn es von außen gemacht wird). Führen Sie dann im untergeordneten Element einen Vorgang mit dem Dateideskriptor aus, der keine Auswirkungen auf andere Prozesse hat. Unter Linux sollten Leases dafür funktionieren.
Gilles 'SO- hör auf böse zu sein'
@Gilles, danke, aber das ist mehr oder weniger der Ansatz, den ich in der Frage bereits vorschlage. Leases (vorausgesetzt, Sie meinen das F_SETLEASE fcntl, danke, dass Sie mich darüber informiert haben, BTW) funktionieren nur für reguläre Dateien, die Sie besitzen, und nicht, wenn es eine andere "schreibe" offene Dateibeschreibung für dieselbe Datei (EBUSY) gibt -aufdringlich.
Stéphane Chazelas
Hast du diese Frage aufgegeben? Ich habe einige Informationen dazu gepostet, wie SystemTap das tun kann, was Sie wollen, aber Sie haben keine Antwort als vollständig markiert ...?
Azhrei

Antworten:

2

Ab Linux 3.5 kann dies mit kcmp (3) erreicht werden :

KCMP_FILE

  • Prüfen Sie, ob ein Dateideskriptor idx1 im Prozess pid1 auf dieselbe offene Dateibeschreibung (siehe open (2) ) verweist wie der Dateideskriptor idx2 im Prozess pid2 . Das Vorhandensein von zwei Dateideskriptoren, die auf dieselbe offene Dateibeschreibung verweisen, kann darauf zurückzuführen sein, dass dup (2) (und ähnliche) fork (2) oder Dateideskriptoren über einen Domain-Socket übergeben werden (siehe Unix (7) ).

Die Manpage enthält ein Beispiel speziell für den angeforderten Anwendungsfall OP. Beachten Sie, dass für diesen Systemaufruf der Kernel mit CONFIG_CHECKPOINT_RESTOREset kompiliert werden muss .

minmaxavg
quelle
Vielen Dank. Genau das, wonach ich gesucht habe. Beachten Sie, dass es zwei Prozesse von Ihnen sein müssen (und nicht setuid / setgid ...) (verständlicherweise), es sei denn, Sie sind Superuser
Stéphane Chazelas
@ StéphaneChazelas Genau. Wenn die CPIU-Unterstützung aus irgendeinem Grund nicht in Ihrem Kernel integriert ist und Sie sie nicht neu erstellen möchten, können Sie vermutlich immer ein Kernelmodul schreiben, das eine Benutzeroberfläche exportiert, mit der Sie struct file *Zeiger vergleichen können .
Minmaxavg
3

Was Sie vergleichen struct filemöchten, sind die Zeiger, auf die die Dateideskriptoren verweisen. (Innerhalb des Kernels ist eine task_structDatenstruktur für jeden Thread. Es enthält einen Zeiger auf eine andere Struktur genannt files_struct. Und die Struktur enthält ein Array von Zeigern, die jeweils einem struct file. Es ist das ist , struct filedass die Such Offset hält, die offenen Fahnen und ein einige andere Felder.)

Ich kenne keine vom Benutzer sichtbare Möglichkeit, die Zeiger in files_structanderen als der Verwendung einiger aufdringlicher Tools zu sehen. Beispielsweise könnte SystemTap eine PID erhalten und die entsprechende finden task_structund den Zeigern folgen. Wenn Sie auf der Suche nach passiven sind, denke ich, ist das auch schon alles. Dell hat vor langer Zeit ein Tool namens KME (Kernel Memory Editor) veröffentlicht, das eine spreadsheet-ähnliche Oberfläche für den Live-Kernel-Speicher bietet und das alles kann, was Sie wollen, aber es wurde nie auf 64-Bit portiert. (Ich habe es versucht und nie ganz zum Laufen gebracht und war mir nicht sicher warum.)

Ein Grund, warum Sie sich nicht lsofals hilfreich erweisen, ist, dass diese Zeiger ebenfalls nicht angezeigt werden (sehen Sie sich jedoch die +fOption für Nicht-Linux-Systeme an). Sie könnten theoretisch alle Felder in der vergleichen struct fileund die beiden Strukturen für gleich halten, sie könnten jedoch immer noch von getrennten open(2)Aufrufen stammen.

Schauen Sie sich das pfiles- SystemTap-Skript an, um Ideen zu erhalten. Wenn Sie es geändert haben, um die Adresse der auszudrucken struct file, hätten Sie Ihre Lösung. Sie können auch die Datei "opens_file_by_pid.stp" überprüfen, da sie eine Funktion enthält, die die Zeichenfolge "ie" ausführtfiles_struct . die Dateideskriptortabelle, die die struct fileObjekte betrachtet ...

Darf ich fragen, was Sie erreichen wollen?

Azhrei
quelle
Ich muss zugeben, dass ich mich nicht genau an den Fall erinnern kann, in dem ich das gebraucht habe. Einige Debugging- oder forensische Aufgaben ohne Zweifel.
Stéphane Chazelas
Ich freue mich auf den PoC-Systemtap-Code :-)
Stéphane Chazelas
Bevor ich die Frage gestellt habe, habe ich mir die Ansätze systemtap oder / proc / kcore angesehen. Der schwierige Teil war, die Informationen für jeden FD jeder Aufgabe zu bekommen . Der vielversprechendste Ansatz, den ich gefunden habe, war das Einbinden in die Funktionen, die den Inhalt des Verzeichnisses / proc / * / task / fd generieren, aber die einzigen brauchbaren Dinge, die ich finden konnte, waren das Einbinden an bestimmten Zeilennummern in der Quelldatei, also nicht portierbar von einer Kernelversion zur nächsten. Sie können die Aufgabenliste in systemtap nicht wirklich durchlaufen. Möglicherweise über / proc / kcore, aber zu aufwändig und wahrscheinlich unzuverlässig.
Stéphane Chazelas
Vielen Dank für die bisher beste Antwort. Ich werde einen Blick auf Ihre Hinweise werfen.
Stéphane Chazelas
Sicher kannst du! Richten Sie einen probe beginBlock ein und lassen Sie ihn das for_each_processMakro in einem Block von C-Code verwenden, der in das Skript eingebettet ist (Sie müssen SystemTap im "Guru" -Modus verwenden, um C-Code einzubetten). Um dies interessant (!) Zu machen, können Sie eines der assoziativen Arrays von SystemTap verwenden. Verwenden Sie die files_structAdresse als Schlüssel und eine Liste von PIDs / TIDs als Werte. Sie haben jetzt eine Liste aller geöffneten Dateien und der Aufgaben, die sie gemeinsam nutzen (sie können von Eltern / Kindern gemeinsam genutzt werden). Antworten Sie erneut, wenn Sie über SystemTap sprechen möchten.
Azhrei
0

Hier ist eine linuxspezifische Lösung: / proc / self / fd ist ein Verzeichnis symbolischer Links für offene Dateihandles im aktuellen Prozess. Sie können nur die Linkwerte vergleichen. Bei der Verwendung eines untergeordneten Prozesses wird es komplizierter, da das untergeordnete Element ein anderes / proc / self hat, da es eine pid-abhängige symbolische Verknüpfung ist. Sie können dieses Problem umgehen, indem Sie / proc / $$ / fd verwenden, wobei $$ die gewünschte PID ist.

hildred
quelle
Vielen Dank. Aber das frage ich nicht. Unter Linux verwendet lsof in der Tat / proc / pid / fd, um Pfade für jeden Dateideskriptor und / proc / pid / fdinfo für die Flags abzurufen. Aber was ich will ist, dass für zwei fds auf die gleiche Datei, ob sie auf die gleiche offene Dateibeschreibung verweisen oder ob die beiden Dateideskriptoren unabhängig voneinander geöffnet waren.
Stéphane Chazelas
OK, nachdem Sie Paare von Dateideskriptoren gefunden haben, die mit demselben Dateinamen geöffnet sind, machen Sie einen Tell für beide und vergleichen Sie die Ergebnisse, wenn sie unterschiedlich sind. Wenn sie identisch sind, suchen Sie nach einem Dateideskriptor und wiederholen Sie die Suche. Wenn sie immer noch übereinstimmen, sind sie identisch.
Hildred
Nun, das ist eine aufdringlichere Variante des heuristischen Ansatzes, auf den ich mich in der Frage beziehe, und das funktioniert nur für reguläre Dateien (keine Sockets, Geräte (wie Terminals), Pipes ...).
Stéphane Chazelas