2013-01-01 9 views
5

alle!LD_PRELOADed Bibliotheken und Kindprozess

Bild, das ich habe ein Programm (usemalloc) wie folgt aus:

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

#define USER_BYTES_SIZE 100 

int main(void){ 
    char* userbytes = (char*)malloc(USER_BYTES_SIZE*sizeof(char)); 
    if(!userbytes) 
     return 1; 

    for(int i = 0; i <= USER_BYTES_SIZE; i++){ // "i <= USER_BYTES_SIZE" leads to an off-by-one memory overrun. 
     userbytes[i] = 0; 
    } 
    return 0; 
} 

Wie Sie sehen, dass es eine ist off-by-one Fehler, der zu einem Speicherüberlauf führt. Ich möchte solche Fehler zur Laufzeit erkennen. LD_PRELOADed Bibliotheken sind geeignet, um meine Arbeit zu erledigen. Ich habe eine Bibliothek namens libhijack.so hergestellt, um den Anruf zu echten malloc Hijack und ersetzen Sie sie durch den Aufruf an meine eigenen customed malloc, die das echte malloc aufrufen und rote Zonen an den Enden der Speicherstreifen von der realen malloc zugewiesen. Der Code des libhijack.so wie folgt aus:

void* (*real_malloc) (size_t size); 
void* malloc(size_t size){ 
    real_malloc = ((void*)(*)(size_t))dlsym(RTLD_NEXT, "malloc"); 
    void* allocbytes = (void*)real_malloc(size + 4); //put 2 bytes at each end, call them red zones 
    return (allocbytes + 2); 
} 

Ich betreibe das Hauptprogramm mit der Bibliothek mit diesem Befehl:

LD_PRELOAD=./libhijack.so ./usemalloc 

Dann, wenn es Zugriff auf den Speicher in den roten Zonen sind, werde ich sie erkennen und betrachte sie als Speicherüberlauffehler.

Diese LD_PRELOAD-Lösung funktioniert gut, wenn der Hauptprozess Aufrufe von malloc enthält, aber fehlschlägt, wenn der untergeordnete untergeordnete Prozess dies ausführt.

Zum Beispiel ändern wir die „usemalloc“ wie folgt:

#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> // + 

#define USER_BYTES_SIZE 100 

int main(void){ 
    pid_t child = fork(); 
    if(child < 0) 
     exit(1); 

    if(child == 0){ //child process 
     char* userbytes = (char*)malloc(USER_BYTES_SIZE*sizeof(char)); 
     if(!userbytes) 
      return 1; 

     for(int i = 0; i <= USER_BYTES_SIZE; i++){ // "i <= USER_BYTES_SIZE" leads to an off-by-one memory overrun. 
      userbytes[i] = 0; 
     } 
    } 
    else { //the current process 
     wait(NULL); 
    } 
    return 0; 
} 

Der Überlauf Fehler in Kindprozess aufgetreten wird nicht durch LD_PRELOADed Bibliothek erkennen werden.

Also meine Fragen sind: Wie kann ich den Überlauf Fehler im untergeordneten Prozess mit LD_PRELOADed Bibliotheken erkennen? Ist das möglich (mit LD_PRELOADed Bibliotheken)? Wenn nicht, irgendwelche Alternativen? Alle Vorschläge werden geschätzt !!!

+1

Hast du mit 'valgrind' (in Compiler & ASAN Option) berücksichtigen, die wahrscheinlich die meisten bietet, was Sie schon wollen, ohne' LD_PRELOAD' Trick. –

+0

Valgrind oder Pin ist zu schwer für meine Instrumentierung. Ich möchte nur eine leichte Lösung wie LD_PRELOAD, um einige interessante Funktionen zu entführen. Wie auch immer, danke für's Kommentieren! –

+0

Sie können keine zuverlässige leichte Lösung haben: Es gibt keine Hardwareunterstützung für solche Pufferüberlauffehler, und Sie müssen den Compiler patchen. Siehe ASAN und andere aktuelle Bemühungen in GCC (Zukunft 4.8) oder Clang (3.2) –

Antwort

0

Ich hoffe, ich bin nicht pingelig, indem ich darauf hinweise, dass der libhijack-Code tatsächlich keinen Speicher zuweist? pthread_mutex_lock benötigt ein pthread_mutex_t * -Argument und gibt eine Integer-Meldung über Erfolg/Misserfolg zurück, ob die Mutex-Sperre erfolgreich war oder nicht?

Auch Sie sind fork() 'ein Kind-Prozess, der ein bisschen anders ist, als einen Thread zu erstellen und so die Pthread-Funktionen möglicherweise nicht wirklich, was Sie suchen ...?

Der andere Trick ist, dass, während der Code, der das Problem verursacht, demonstriert wurde, wie überprüfen Sie Ihre "roten Zonen"? Vielleicht liegt die Erkennungsschwankung im Erkennungscode?

+0

Entschuldigung für Bearbeitungsfehler. "pthread_mutex_lock" sollte im Aufruf von dlsym durch "malloc" ersetzt werden. Ich habe es korrigiert. Meine Frage ist, wie kann ich LD_PRELOADed Bibliotheken verwenden, um Überlauffehler im Kindprozess zu erkennen? Weißt du, dass? –

0

Verwenden Sie Valgrind, um Speicherverluste und andere Speicherprobleme zu erkennen. Es funktioniert großartig und Sie müssen nichts implementieren.

0

Ich glaube nicht, Ihr Problem etwas mit fork() vs. LD_PRELOAD zu tun hat. Ich denke, es könnte ein Fehler irgendwo anders in Ihrem Code sein. Ich habe versucht, Ihr Problem mit dem folgenden Testfall zu reproduzieren:

// preloadlib.c 
#define _GNU_SOURCE 
#include <dlfcn.h> 
#include <unistd.h> 
void* malloc(size_t size) 
{ 
     write(1, "malloc\n", 7); 
     void *(*real_malloc)(size_t) = dlsym(RTLD_NEXT, "malloc"); 
     return real_malloc(size); 
} 

.

// example.c 
#include <unistd.h> 
#include <stdlib.h> 
int main() 
{ 
     if (fork()) { 
       write(1, "A\n", 2); 
       malloc(1337); 
       write(1, "B\n", 2); 
     } else { 
       write(1, "C\n", 2); 
       malloc(1337); 
       write(1, "D\n", 2); 
     } 
     return 0; 
} 

.

# run.sh 
gcc -Wall -Wextra -o example example.c 
gcc -Wall -Wextra -fPIC -o preloadlib.so -shared preloadlib.c -ldl 
LD_PRELOAD=$PWD/preloadlib.so ./example 

Und dies ist die Ausgabe erhalte ich:

$ bash run.sh 
A 
malloc 
C 
B 
malloc 
D 

Dies ist auf 64-Bit-Kubuntu 12.04 (libc Version 2.15-0ubuntu10.4).