Ich habe einen Prozess, dessen Umgebung wie folgt ist:
root@a-vm:/proc/1363# hexdump -C environ
00000000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
0000016c
Ich habe so etwas noch nie gesehen. Ich erwarte environ
, keine terminierten key=value
Paare zu enthalten , daher verletzt diese Ausgabe alle Arten von Behauptungen. Betrachte ich einen bekannten Kernel-Fehler oder gibt es unter Unix / Linux einen legitimen Weg, dies zu erreichen? (… Und wenn ja, warum? Warum lässt der Kernel diesen Unsinn überhaupt zu?)
(unter Linux, 3.13.0 / Ubuntu Trusty)
(Ich lief dies in bei dem Versuch , herauszufinden, warum dieser Prozess ist nicht eine vorübergehende Ausgabe an die richtige Stelle zu schreiben, es ist Angenommen , ein bestimmtes Verzeichnis für temporäre Speicherung zu verwenden, und es informiert dieses Verzeichnisses die env Variable über die Einstellung TMP
, aber ich‘ m Einstellung TMP
zu etwas , das aussieht wie ein ganz normaler Weg, nicht ein Haufen von nuls, und ich habe nie sowieso ein völlig leer env gesehen.)
quelle
Antworten:
Dies ist kein Unsinn, es gibt unter Linux einen legitimen Weg, dies zu erreichen, und Ihre Erwartungen sind falsch.
Die Argument- und Umgebungszeichenfolgen, die vom Kernel an den Startcode eines Programms übergeben werden, werden wie alle anderen Programmdaten im normalen virtuellen Speicher des Anwendungsbereichs gespeichert. und wie alle anderen Programmdatenvariablen können sie geändert werden. Es ist durchaus legitim, dass Programme sie ändern.
(Beachten Sie, dass dies unter dem Gesichtspunkt erfolgt, was der Kernel bereitstellt und erzwingt. Was die Standards für bestimmte Programmiersprachen möglicherweise aussagen, ist nicht unbedingt dasselbe. Was den Kernel betrifft, ist dies nur ein Bereich des Anwendungsbereichs virtueller Speicher für Programmdaten, die lesbar und beschreibbar sind. Dem Kernel ist es egal, aus welcher Programmiersprache Sie Ihren Maschinencode kompiliert haben.)
Die
/proc/${PID}/environ
Datei ist nur ein Fenster zu diesem virtuellen Speicher im Anwendungsbereich. Anstatt sich an die tatsächlichen Umgebungsdaten des Prozesses zu erinnern, merkt sich Linux nur die Start- und Endadressen des Umgebungsbereichs, mit dem der Prozess gestartet wurde, und die/proc/${PID}/environ
Datei liest nur das aus, was sich gerade in diesem Speicher befindet. Sie sollten nicht erwarten, dass diese Datei eine Liste von ␀-terminierten Zeichenfolgen enthält. Das ist eine falsche Erwartung.Es gibt keine GNU C-Bibliotheksfunktion zum Ändern des Speichers, der diese Zeichenfolgen enthält. Dafür haben verschiedene Programme ihre eigenen Funktionen.
Betrachten Sie als Beispiel OpenSSH. Der OpenSSH-Server ändert, was
ps
für seinen Argumentvektor angezeigt wird, um Dinge wie zu lesensshd: JdeBP [priv]
.Der OpenSSH-Server enthält Code, der versucht, unter Linux nachzuahmen, was er mit der BSD C-Bibliothek unter OpenBSD tun kann. Unter OpenBSD gibt es eine BSD C-Bibliotheksfunktion mit dem Namen
setproctitle()
, die den vomps
Befehl angegebenen Prozessargumentvektor neu schreibt . Es wird aufgerufensysctl()
, einen neuen Argumentvektor an den Kernel zu übergeben, derps
mit auslesen kannsysctl()
. FreeBSD hat eine ähnliche Funktion.Unter Linux erinnert sich der Kernel, wie erläutert, nicht an tatsächliche Argumente und Umgebungen, sondern lediglich an die Start- und Endadressen der Speicherbereiche, in denen er sie beim Starten des Prozesses ursprünglich platziert hat. Der Linux-Port von OpenSSH verfügt also über eine Kompatibilitätsfunktion
setproctitle()
, die stattdessen den oben genannten Speicherbereich überschreibt.Diese Kompatibilitätsfunktion berechnet die Gesamtgröße des Umgebungsbereichs und des Argumentbereichs und überschreibt alles mit der neuen Argumentzeichenfolge. Dies geschieht, weil Programme, die aufrufen
setproctitle()
, im Normalfall einen längeren Satz von Argumentdaten schreiben möchten als ursprünglich.sshd
oft tut. Auf diese Weise können die neuen Argumente den Umgebungsbereich überschreiben, der dem Argumentbereich folgt, und den Programmen mehr Platz für längere Sätze von Argumentzeichenfolgen geben.Wichtig ist auch , dass der nicht verwendete Teil des Bereichs , den es nicht zum Überschreiben benötigt hat, auf die ursprüngliche Länge der gesamten Argument- und Umgebungsdaten mit ␀s aufgefüllt wird.
Und was Sie sehen, ist das genaue Ergebnis davon. Wenn Sie einen OpenSSH-Serverprozess auf Ihrem System finden, werden Sie feststellen, dass auch dieser viele ␀s enthält
/proc/${PID}/environ
.Weiterführende Literatur
setproctitle
. FreeBSD 11.0 Handbuch.setproctitle
. OpenBSD-Handbuch.setproctitle()
. OpenSSH Portable Release.environ_read()
. fs / proc / base. Linux Kernel. Freie Elektronen.quelle
setproctitle
Implementierungen, die einige Projekte unter Linux durchführen (z. B. über libbsd), alle von schwerwiegendem undefiniertem Verhalten geprägt sind und nicht verwendet werden sollten. Der Speicher, der Ihnen nicht gehört (z. B. auf den die Standardbibliothek, der dynamische Linker usw. möglicherweise verweisen), um hübsche Nachrichten in der ps / top-Ausgabe anzuzeigen, ist absolut nicht zu rechtfertigen.environ
Zeiger gibt, mit dem man überhaupt in den Speicher gelangen kann. Inenviron
POSIX heißt es: "Jede Anwendung, die die Zeiger, auf die die Umgebungsvariable zeigt, direkt ändert, weist ein undefiniertes Verhalten auf." Es scheint zulässig zu sein, die Zeichenfolgen, auf die verwiesen wird, zu ändern (vorbehaltlich Einschränkungen bei der Speichersynchronisierung), aber es ist nicht klar, ob definiert ist, sie in einem Formular zu belassen, in dem sie keine gültigen Umgebungseinträge ("X=Y"
Formular) sind.environ[0]
und / oder sich darauf zu verlassen, dass sie bis zum Ende stößt (und als kombiniertes Objekt betrachtet werden kann)environ[1]
. Insbesondere wenn dieenviron[0]
Änderung nach einer Änderung nicht auf Null gesetzt wird (wie diessetproctitle
dazu führen kann, dass der Nachrichtentext darüber gelegt wird), erfolgt die Zeigerarithmetik außerhalb der Grenzen später, wenn auf die Zeichenfolge zugegriffen wird.Dies ist völlig machbar, indem Sie
NUL
s in den Speicherort schreiben, in dem sich die Umgebungsvariablen befinden:Wenn Sie stattdessen ein Programm mit einer leeren Umgebung starten, ist die
environ
Datei vollständig leer:Dieser Fall wird also von oder mit dem Prozess ausgeführt, sobald er ausgeführt wird (und es gibt wenig, was dies verhindern kann, es sei denn, Sie haben diesen Speicher irgendwie gesperrt und
setenv(3)
Aufrufe könnten problematisch sein ...).quelle
/proc/$pid/environ
spürt dasenviron
Objekt nicht auf (und hat keine Möglichkeit dazu, da die ausführbare Datei möglicherweise nicht einmal Symbole enthält) und folgt Zeigern. Es gibt einfach den Inhalt des Speicherbereichs aus, den der Kernel zum Übergeben der anfänglichen Umgebungswerte verwendet hat.hexdump
auf Centos 6 genau 10 angezeigt,NUL
die über den Start der Umgebung für den Prozess geschrieben wurden?environ[0]
, nicht die Zeiger anenviron[]
sich.