2010-07-18 6 views
5

mein Code ist wie folgt: preload.c, mit folgendem Inhalt:LD_PRELOAD betrifft neues Kind auch nach unsetenv ("LD_PRELOAD")

#include <stdio.h> 
#include <stdlib.h> 

int __attribute__((constructor)) main_init(void) 
{ 
    printf("Unsetting LD_PRELOAD: %x\n",unsetenv("LD_PRELOAD")); 
    FILE *fp = popen("ls", "r"); 
    pclose(fp); 
} 

dann in der Schale (vorsichtig den zweiten Befehl tun !!):

gcc preload.c -shared -Wl,-soname,mylib -o mylib.so -fPIC 
    LD_PRELOAD=./mylib.so bash 

!!! Seien Sie vorsichtig mit dem letzten Befehl wird es mit Endlosschleife der Gabelung "sh-c ls" ergeben. Stoppen Sie es nach 2 Sekunden mit^C, (oder besser^Z und dann siehe ps).

Mehr Infos

  1. Dieses Problem beziehen sich in irgendeiner Weise einzuschlagen; Entweder als der Befehl, den der Benutzer ausführt, oder als bash der popen ausgeführt wird.
  2. zusätzliche Schlüsselfaktoren: 1) Führen Sie die popen aus der vorinstallierten Bibliothek, 2) Wahrscheinlich müssen Sie den Popen im Abschnitt Initialisierung der Bibliothek tun.
  3. wenn Sie verwenden:

    LD_DEBUG=all LD_DEBUG_OUTPUT=/tmp/ld-debug LD_PRELOAD=./mylib.so bash 
    

    anstelle des letzten Befehls, werden Sie viele ld-Debug-Dateien erhalten, mit dem Namen /tmp/ld-debug.*. Eine für jeden gegabelten Prozess. IN ALLEN DIESEN DATEIEN sehen Sie, dass Symbole in mylib.so zuerst durchsucht werden, obwohl LD_PRELOAD aus der Umgebung entfernt wurde.

+0

In welcher Sprache sprechen wir? – mvds

+0

wir sprechen über die C-Sprache – avner

+0

@ user395074, dann sollten Sie Ihre Tags möglicherweise an die Sprache angepasst haben (klicken Sie auf den Link "Bearbeiten"). Außerdem scheint das [preloader] -Tag nicht die OS-Komponente zu reflektieren, über die wir sprechen. –

Antwort

8

edit: so das Problem/Frage tatsächlich war: howcome kann nicht Sie deaktivieren LD_PRELOAD zuverlässig mit einem vorinstallierten main_init() aus bash.

Der Grund dafür ist, dass execve, die aufgerufen wird, nachdem Sie popen, von der Umwelt nimmt (wahrscheinlich)

extern char **environ; 

die einige globale Zustandsgröße ist, die auf Ihre Umgebung zeigt. unsetenv() ändert normalerweise Ihre Umgebung und wirkt sich daher auf den Inhalt von **environ aus.

Wenn bash versucht, etwas Besonderes mit der Umgebung zu tun (naja ... wäre es eine Shell?), Dann könnten Sie in Schwierigkeiten geraten.

Offensichtlich bash überlastet unsetenv() noch vor main_init(). Ändern des Beispielcodes zu:

extern char**environ; 

int __attribute__((constructor)) main_init(void) 
{ 
int i; 
printf("Unsetting LD_PRELOAD: %x\n",unsetenv("LD_PRELOAD")); 
printf("LD_PRELOAD: \"%s\"\n",getenv("LD_PRELOAD")); 
printf("Environ: %lx\n",environ); 
printf("unsetenv: %lx\n",unsetenv); 
for (i=0;environ[i];i++) printf("env: %s\n",environ[i]); 
fflush(stdout); 
FILE *fp = popen("ls", "r"); 
pclose(fp); 
} 

zeigt das Problem. Im Normal läuft (Lauf cat, ls, etc.) erhalte ich diese Version von unsetenv:

unsetenv: 7f4c78fd5290 
unsetenv: 7f1127317290 
unsetenv: 7f1ab63a2290 

jedoch bash oder sh ausgeführt wird:

unsetenv: 46d170 

So, da haben Sie es. bash hat bekam man getäuscht ;-)

So ändern nur die Umwelt, Ihre eigenen unsetenv verwenden, wirkt auf **environ:

for (i=0;environ[i];i++) 
{ 
    if (strstr(environ[i],"LD_PRELOAD=")) 
    { 
     printf("hacking out LD_PRELOAD from environ[%d]\n",i); 
     environ[i][0] = 'D'; 
    } 
} 

, die in der strace gesehen werden kann arbeiten:

execve("/bin/sh", ["sh", "-c", "ls"], [... "DD_PRELOAD=mylib.so" ...]) = 0 

QED

+0

LD_PRELOAD ist nicht in der Umgebung des Child-Prozesses (weder in der Eltern nach der Unsetenv). Pavels Antwort deutet auf den Grund hin: LD_PRELOAD wird vom Loader verwendet und nicht von meinem Programm. mylib.so ist bereits geladen und der Loader behält wahrscheinlich sein Verhalten bei, ohne LD_PRELOAD erneut zu lesen. fork & execle ist eine Option; popen ist jedoch sehr bevorzugt, da es mir ermöglicht, die Ausgabe des Kindprozesses auf einfache Weise zu lesen. strace gace eine Menge von Informationen, die mir nicht geholfen haben. Ich habe verwendet: LD_DEBUG exportieren = symnols und sah klar, dass alle Symbole in mylib.so vor jeder anderen lib gesucht werden. – avner

+0

das wird immer interessanter, nur aktualisiert meine Antwort mit einigen mehr Anregungen – mvds

+0

@avner: noch mehr Vorschläge in der Antwort, baute meine eigenen '.so' und immer noch nicht sehen, was Sie sehen ... – mvds

2

(Die Antwort ist eine reine Spekulation, und kann falsch ist).

Vielleicht, wenn Sie Ihren Prozess forkieren, bleibt der Kontext der geladenen Bibliotheken bestehen. So wurde mylib.so geladen, wenn Sie das Hauptprogramm über LD_PRELOAD aufgerufen haben. Wenn Sie die Variable aufheben und verzweigen, wurde sie nicht erneut geladen. aber es wurde bereits durch den übergeordneten Prozess geladen. Vielleicht sollten Sie es nach dem Abzweigen explizit entladen.

Sie können auch versuchen, Symbole in mylib.so zu "degradieren". Um dies zu tun, öffnen Sie es über dlopen mit Fahnen, die es bis zum Ende der Symbol Auflösung Warteschlange stellen:

dlopen("mylib.so", RTLD_NOLOAD | RTLD_LOCAL); 

+0

Danke für Pavels Kommentar. Das klingt vernünftig; In meinem Fall ist diese Problemumgehung jedoch nicht möglich. Ich kann nichts nach der Gabel ändern, da ich Popen verwende, die die Gabel/Exec für mich tut. (Noch, Gabel und Exec sind Fallback-Option, wenn ich es nicht mit Popen tun kann). Der übergeordnete Prozess muss in der LD_PRELOAD-Umgebung verbleiben (es handelt sich um einen Kundenprozess mit mehreren Threads). – avner

+0

sagst du, dass nach 'exec' die geladenen Bibliotheken bestehen bleiben? Ich sehe in einem strace, dass sogar libc nach exec wieder geöffnet wird, kann mir nicht vorstellen, dass eine andere Bibliothek sich durchsetzen wird. – mvds

+0

@mvds, wieder geöffnet werden und entladen/geladen sind verschiedene Dinge. Sie können eine bereits geladene Bibliothek erneut öffnen. –

0

die Antwort von mvds ist falsch!

popen() erzeugt einen Child-Prozess, der das vorgeladene .so im übergeordneten Prozess geerbt hat. Dieser untergeordnete Prozess kümmert sich nicht um die LD_PRELOAD-Umgebung.

Verwandte Themen