2013-01-01 18 views
5

हर कोई!एलडी_PRELOADed पुस्तकालयों और बाल प्रक्रिया

छवि मैं इस तरह एक कार्यक्रम (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; 
} 

जैसा कि आप देख कि, वहाँ एक बंद-एक करके बग जो एक स्मृति अतिप्रवाह हो जाती है। मैं रनटाइम पर ऐसी बग का पता लगाना चाहता हूं। एलडी_PRELOADED पुस्तकालय मेरे काम करने के लिए उचित हैं। मैंने असली malloc पर कॉल को हाइजैक करने के लिए libhijack.so नामक एक लाइब्रेरी का निर्माण किया है और इसे अपने स्वयं के कस्टम मैलोक पर कॉल के साथ प्रतिस्थापित किया है जो वास्तविक मॉलोक को कॉल करता है और वास्तविक मॉलोक द्वारा आवंटित मेमोरी स्ट्रिप्स के सिरों पर लाल जोनों को जोड़ता है। इस तरह 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); 
} 

मैं इस आदेश का उपयोग पुस्तकालय के साथ मुख्य कार्यक्रम चलाने उन्हें स्मृति अतिप्रवाह बग के रूप में समझाओ।

यह एलडी_PRELOAD समाधान अच्छी तरह से काम करता है जब मुख्य प्रक्रिया में मॉलोक को कॉल किया जाता है लेकिन जब फोर्कड बाल प्रक्रिया उसमें विफल होती है तो विफल हो जाती है।

#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 पुस्तकालय द्वारा की पहचान नहीं की जाएगी:

उदाहरण के लिए, हम "usemalloc" इस प्रकार बदल जाते हैं।

तो मेरे प्रश्न हैं: मैं एलडी_PRELOADed पुस्तकालयों का उपयोग कर बाल प्रक्रिया में ओवरफ्लो बग का पता कैसे लगा सकता हूं? क्या वह (एलडी_PRELOADed पुस्तकालयों का उपयोग कर) संभव है? यदि नहीं, तो कोई विकल्प? किसी भी सुझाव की सराहना की !!!

+1

क्या आपने 'वालग्रींड '(और कंपाइलर्स में एएसएएन विकल्प) का उपयोग करने पर विचार किया था जो संभवतः आप जो कुछ भी चाहते हैं, वह बिना किसी' एलडी_PRELOAD' चाल के प्रदान करता है। –

+0

वाल्ग्रिंड या पिन मेरे उपकरण के लिए बहुत भारी है। मैं सिर्फ कुछ हल्के समाधानों को हाइजैक करने के लिए LD_PRELOAD जैसे हल्के समाधान चाहता हूं। वैसे भी, टिप्पणी के लिए धन्यवाद! –

+0

आपके पास विश्वसनीय हल्के समाधान नहीं हो सकते हैं: ऐसे बफर ओवरफ़्लो बग के लिए कोई हार्डवेयर सहायता नहीं है, और आपको कंपाइलर को पैच करने की आवश्यकता होगी। जीएससी (भविष्य 4.8) या क्लैंग (3.2) –

उत्तर

0

मुझे आशा है कि मैं यह बताकर नाइट-पिकि नहीं कर रहा हूं कि libhijack कोड वास्तव में किसी भी स्मृति को आवंटित नहीं करता है? pthread_mutex_lock को pthread_mutex_t * तर्क की आवश्यकता होती है, और म्यूटेक्स लॉक सफल होने पर या नहीं, इस पर एक पूर्णांक संचार/विफलता संचारित करता है?

इसके अलावा, आप एक बच्चे की प्रक्रिया में फोर्क() 'हैं, जो थ्रेड बनाने के लिए थोड़ा अलग है और इसलिए pthread फ़ंक्शन वास्तव में आपके बाद के बाद नहीं हो सकते हैं ...?

दूसरी चाल यह है कि समस्या उत्पन्न करने वाले कोड का प्रदर्शन किया गया है, तो आप अपने "लाल क्षेत्र" की जांच कैसे कर रहे हैं? शायद पहचान quirk पहचान कोड में निहित है?

+0

संपादन गलती के लिए खेद है। dlsym को कॉल में "mthoc" के साथ "pthread_mutex_lock" को प्रतिस्थापित किया जाना चाहिए। मैंने इसे सही किया है। मेरा सवाल यह है कि मैं बाल प्रक्रिया में अतिप्रवाह बग का पता लगाने के लिए एलडी_PRELOADED पुस्तकालयों का उपयोग कैसे कर सकता हूं? क्या आप जानते हैं कि? –

0

मेमोरी लीक और अन्य मेमोरी समस्याओं का पता लगाने के लिए वालग्रिंड का उपयोग करें। यह बहुत अच्छा काम करता है और आपको कुछ भी लागू नहीं करना पड़ेगा।

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 (संस्करण 2.15-0ubuntu10.4 libc)।

संबंधित मुद्दे