2013-01-01 50 views
5

大家好!LD_PRELOed庫和子進程

圖片,我有一個程序(usemalloc)所示:

#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; 
} 

正如所看到的是,有一個斷接一個錯誤,這導致了存儲器溢出。我想在運行時檢測這些錯誤。 LD_PRELOAD庫適合於我的工作。我製作了一個名爲libhijack.so的庫來劫持真正的malloc 的調用,並將其替換爲調用我自己定製的malloc的調用實際的malloc,並在由真實的malloc分配的內存條末尾添加紅色區域 。該libhijack.so的這樣的代碼:

LD_PRELOAD=./libhijack.so ./usemalloc 

其次,如果有訪問內存中的紅色區域,我會發現他們和:

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); 
} 

我使用此命令運行主程序與庫認爲它們是內存溢出錯誤。

此LD_PRELOAD解決方案在主進程包含對malloc的調用時工作正常,但當分叉的子進程執行該操作時失敗。

例如,我們改變「usemalloc」如下:

#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; 
} 

兒童過程中出現溢出漏洞不會被LD_PRELOADed庫檢測。

所以我的問題是:如何檢測使用LD_PRELOADed庫的子進程中的溢出錯誤?那(使用LD_PRELOADed庫)是可能的嗎?如果沒有,還有其他的選擇 任何建議ar eappreciated !!!

+1

您是否考慮過使用'valgrind'(在編譯器中爲&ASAN選項),它可能提供了大部分您已經想要的內容,而沒有任何'LD_PRELOAD'技巧。 –

+0

valgrind或pin對我的儀器來說太重了。我只想要一個輕量級的解決方案,比如LD_PRELOAD來劫持一些有趣的功能。無論如何,感謝評論! –

+0

您不可能擁有可靠的輕量級解決方案:對於此類緩衝區溢出錯誤沒有硬件幫助,您需要修補編譯器。看到ASAN和GCC(未來4.8)或鏗鏘(3.2) –

回答

0

我希望我不是挑剔指出libhijack代碼實際上沒有分配任何內存? pthread_mutex_lock需要一個pthread_mutex_t *參數,並返回一個整數,表示互斥鎖是否成功通信成功/失敗?另外,你是fork()的一個子進程,這與創建一個線程有點不同,所以pthread函數可能並不是真的是你在...之後的東西嗎?

另一個訣竅是雖然已經證明導致問題的代碼,但您如何檢查「紅色區域」?也許檢測怪癖在於檢測代碼?

+0

抱歉編輯錯誤。應在dlsym調用中將「pthread_mutex_lock」替換爲「malloc」。我已糾正它。我的問題是我如何使用LD_PRELOADed庫來檢測子進程中的溢出錯誤?你知道嗎? –

0

使用valgrind來檢測內存泄漏和其他內存問題。它效果很好,你不需要執行任何操作。

0

我不認爲你的問題與fork()LD_PRELOAD有任何關係。我認爲這可能是你代碼中其他地方的錯誤。我嘗試使用以下測試用例重現您的問題:

// 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 

這是輸出我得到:

$ bash run.sh 
A 
malloc 
C 
B 
malloc 
D 

這是64位的Kubuntu 12.04(libc的2.15-0ubuntu10.4版)。