Mahlzeit!
Eigentlich sollte mein Programm nur /proc/self/exe lesen. Und dann finde
ich das[1]:
1
a) /proc might not be mounted at all, or it might be mounted somewhere
2
other than /proc.
3
b) / might not be / (e.g. chroot, containers, etc.), and so /proc might
4
be inaccessible.
5
c) There are a variety of situations where the called process's binary
6
is not directly accessible to the called process as a regular file,
7
and /proc/self/exe appears to be a broken symlink.
a) egal, das sollte sich leicht beheben lassen.
b) funktioniert etwa "mount -t proc proc /proc" in so einem Container
nicht? Was funktioniert ohne /proc überhaupt noch?
c) wenn das Programm auf einer anderen Partition liegt, ist die busy,
umount wird verweigert. Das einzige, was mir einfällt: das Programm
liegt auf einem NFS-Server und der hat sich verabschiedet. Das mag bei
kleinen Programmen und viel RAM zunächst nicht auffallen, nur der Link
ist kaputt. Aber was könnte noch alles hinter "variety" stecken?
[1] https://lwn.net/Articles/883113/
Bauform B. schrieb:> b) funktioniert etwa "mount -t proc proc /proc" in so einem Container> nicht? Was funktioniert ohne /proc überhaupt noch?
Kommt drauf an, es gibt tatsächlich fälle, wo das innerhalb eines mount
user namespaces nicht mehr erlaubt ist. Aber alle container manager, die
ich kenne, mounten es sowieso von Anfang an.
> c) wenn das Programm auf einer anderen Partition liegt, ist die busy,> umount wird verweigert. Das einzige, was mir einfällt: das Programm> liegt auf einem NFS-Server und der hat sich verabschiedet. Das mag bei> kleinen Programmen und viel RAM zunächst nicht auffallen, nur der Link> ist kaputt. Aber was könnte noch alles hinter "variety" stecken?
Und auch wenn ich es lösche kann ich noch darauf zugreifen:
x.sh
Daniel A. schrieb:> + ls -la /proc/self/fd/4> lr-x------ 1 dpa users 64 19. Apr 14:05 /proc/self/fd/4 -> '/home/dpa/sh> (deleted)
Aha, readlink liefert den Pfad mit angehängtem " (deleted)", was ja
formal ein gültiger Dateiname ist. Also kann man den nicht mehr 1:1
verwenden. Das gleiche passiert nach einem mv auf eine andere Partition.
Ein mv auf der gleichen Partition aktualisiert auch den Link.
Mit NFS dazwischen gibt es erst dann ein (deleted), wenn der Cache
aktualisiert wurde. Solange liefert stat -L Daten aus dem Cache,
anschließend dann "Stale file handle".
Alles ziemlich normal, nicht perfekt, nicht tragisch. Unmittelbar nach
dem execve() muss der Link einfach gültig sein. Anschließend gibt es
viele Möglichkeiten, alles kaputt zu spielen. Zuverlässiger als argv[0]
ist /proc/self/exe auf jeden Fall.
Bauform B. schrieb:> Daniel A. schrieb:>> + ls -la /proc/self/fd/4>> lr-x------ 1 dpa users 64 19. Apr 14:05 /proc/self/fd/4 -> '/home/dpa/sh>> (deleted)>> Aha, readlink liefert den Pfad mit angehängtem " (deleted)", was ja> formal ein gültiger Dateiname ist. Also kann man den nicht mehr 1:1> verwenden.
Das interessante ist aber, wie man oben sieht, folgt es dem Link nicht,
wenn man /proc/self/exe öffnet, sondern öffnet direkt die gelöschte
Datei als wäre nichts gewesen.
> Zuverlässiger als argv[0] ist /proc/self/exe auf jeden Fall.
Naja, popen("/proc/self/exe foo bar", "r") geht schon mal schief -
"self" ist "/bin/sh". Entspr. auch system(). NFS-Server könnten ein
Problem sein (Datei verschwindet) und in wieweit Sachen über z.B. fuse
funktionieren, weiß ich nicht. Ebenso wenn Privilegien gedropt oder uid
geändert werden.
Das Problem, seinen eigenen Pfad/Namen zu finden, war schon von (Unix)
Anfang an ... problematisch[1]. Linux kam dann mit dem /proc/self/exe
Symlink und das schien die Lösung zu sein - das " (deleted)" hat's dann
doch wieder kaputt gemacht (tatsächlicher Name oder nur Metainfo?).
Falls mehrere Pfade zum exe existieren (ggf mit unterschiedlichen
Zugriffsrechten), weiß man auch nicht, welcher angezeigt wird. Also
benutzen die meisten weiterhin das ebenfalls unperfekte aber portable
argv[0].
PS: Soviel ich weiß, war das vom Verhalten her immer ein Hardlink - die
Präsentation als Softlink ist nur Informationshalber, eine erneute
Pfadauflösung findet nicht statt.
Irgendwie ist /proc/self/exe ne Schmuddelecke :-)
PPS: Im verlinkten Thread geht es um einen Security-Bug falls argc==0
ist. Ist halt einfach ein Bug - die meisten Programme vertragen es auch
nicht, wenn stdin/out/err geschlossen sind ...
[1] Ähnlich problematisch ist es, den Pfad des aktuellen Verzeichnisses
(CWD) herauszufinden (Rekursiv ".." hochwandern und nach einem Namen
durchsuchen, der die gleiche Inode wie "." hat).
--
Sorry für die Schwafelei.
Foobar schrieb:>> Zuverlässiger als argv[0] ist /proc/self/exe auf jeden Fall.>> Naja, popen("/proc/self/exe foo bar", "r") geht schon mal schief -> "self" ist "/bin/sh". Entspr. auch system().
Warum gibt es eigentlich kein popen() ohne die shell dazwischen?
> Das Problem, seinen eigenen Pfad/Namen zu finden, war schon von (Unix)> Anfang an ... problematisch[1]. Linux kam dann mit dem /proc/self/exe> Symlink und das schien die Lösung zu sein - das " (deleted)" hat's dann> doch wieder kaputt gemacht (tatsächlicher Name oder nur Metainfo?).
Kaputt macht es der User, der sein Programm löscht. Dann existiert die
Datei und existiert gleichzeitig nicht. Nur wer weiß, was er tut, darf
sie noch benutzen ;) Dafür ist (deleted) doch eine gute Beschreibung.
> Falls mehrere Pfade zum exe existieren (ggf mit unterschiedlichen> Zugriffsrechten), weiß man auch nicht, welcher angezeigt wird.
Doch; der Pfad, der beim execve() benutzt wurde. Aber innen drin ist
viel Magie im Spiel: ein rename(2) ändert auch den Link.
> Also benutzen die meisten weiterhin das ebenfalls unperfekte> aber portable argv[0].
für Fehlermeldungen ist argv[0] ja auch richtig - und unbrauchbar, wenn
man wissen will, wo das Programm installiert ist.
> PS: Soviel ich weiß, war das vom Verhalten her immer ein Hardlink - die> Präsentation als Softlink ist nur Informationshalber, eine erneute> Pfadauflösung findet nicht statt.
Ursprünglich (sagt 'man proc') lieferte /proc/*/exe die inode, das war
natürlich viel einfacher und übersichtlicher und dann siegte die
Bequemlichkeit...
> Irgendwie ist /proc/self/exe ne Schmuddelecke :-)> PPS: Im verlinkten Thread geht es um einen Security-Bug falls argc==0> ist. Ist halt einfach ein Bug
Da hatte mich nur diese Aussage schockiert: "There are a variety of
situations where the called process's binary is not directly accessible
to the called process as a regular file". Was ja zunächst völlig
unmöglich erscheint. Alle Beispiele dafür funktionieren ja auch erst
hinterher und/oder sind mehr oder weniger illegal.
Foobar schrieb:>> Zuverlässiger als argv[0] ist /proc/self/exe auf jeden Fall.>> Naja, popen("/proc/self/exe foo bar", "r") geht schon mal schief -> "self" ist "/bin/sh".
Gut, aber warum sollte man das machen wollen?
Foobar schrieb:> Falls mehrere Pfade zum exe existieren (ggf mit unterschiedlichen> Zugriffsrechten), weiß man auch nicht, welcher angezeigt wird.
Ich hätte gedacht, es wird der angezeigt, über den das Programm
gestartet wurde.
> Also benutzen die meisten weiterhin das ebenfalls unperfekte aber> portable argv[0].
Naja, was bei einen popen(argv[0], …) rauskommt, ist dann eher
Glückssache, weil der Aufrufer beim exec() da reinschreiben kann, was
immer er will, und das ist mitnichten immer nur der Name des Executables
inklusive vollständigem Pfad.
Das genannte Problem mit mehreren Pfaden zum Executable hat man da
übrigens genauso.
> PPS: Im verlinkten Thread geht es um einen Security-Bug falls argc==0> ist. Ist halt einfach ein Bug - die meisten Programme vertragen es auch> nicht, wenn stdin/out/err geschlossen sind ...
Ein Bug im Aufrufer.
Bauform B. schrieb:> Warum gibt es eigentlich kein popen() ohne die shell dazwischen?
Das ist halt eine vereinfachte Komfort-Funktion auf Ebene der
Standardlib (in dem Sinne, dass es FILE* für die Kommunikation nutzt).
Du kannst natürlich immer fork/exec*/pipe/dup2 verwenden, um sowas auch
ohne Shell zu implementieren. Genauso gibt es auch kein system() ohne
Shell. Wenn man das braucht, nimmt man eben fork und execl.
>> Das Problem, seinen eigenen Pfad/Namen zu finden, war schon von (Unix)>> Anfang an ... problematisch[1]. Linux kam dann mit dem /proc/self/exe>> Symlink und das schien die Lösung zu sein - das " (deleted)" hat's dann>> doch wieder kaputt gemacht (tatsächlicher Name oder nur Metainfo?).>> Kaputt macht es der User, der sein Programm löscht. Dann existiert die> Datei und existiert gleichzeitig nicht.
In Unix löscht man als User/Programm eigentlich keine Dateien. Man löst
nur Verzeichniseinträge (unlink). Und wenn kein Eintrag mehr existiert
und die Datei auch von keinem Programm mehr geöffnet ist, d.h. der
Referenz-Zähler wird 0, dann wird auch der Inhalt gelöscht. Deshalb kann
man unter Linux Dateien "löschen", auch wenn ein Programm sie noch offen
hat, was unter Windows so nicht geht, weil ihm dieser Mechanismus fehlt.