असेंबली फ़ाइलों को प्रोजेक्ट में शामिल करते समय mmap से अनपेक्षित निष्पादन अनुमति


94

मैं इसके साथ दीवार में अपना सिर पीट रहा हूं।

मेरी परियोजना में, जब मैं mmapमैपिंग के साथ मेमोरी आवंटित कर रहा हूं ( /proc/self/maps) दिखाता है कि यह केवल पढ़ने योग्य मेमोरी का अनुरोध करने के बावजूद एक पठनीय और निष्पादन योग्य क्षेत्र है ।

स्ट्रेस (जो अच्छा लग रहा था) और अन्य डिबगिंग में देखने के बाद, मैं इस अजीब समस्या से बचने के लिए केवल एक चीज की पहचान करने में सक्षम था: प्रोजेक्ट से असेंबली फ़ाइलों को हटाने और केवल शुद्ध सी (क्या ?!)

तो यहाँ मेरा अजीब उदाहरण है, मैं Ubunbtu 19.04 और डिफ़ॉल्ट gcc पर काम कर रहा हूँ।

यदि आप ASM फ़ाइल के साथ निष्पादन योग्य लक्ष्य को संकलित करते हैं (जो खाली है) तो mmapएक पठनीय और निष्पादन योग्य क्षेत्र देता है, यदि आप बिना निर्माण करते हैं तो यह सही व्यवहार करता है। इसका आउटपुट देखें, /proc/self/mapsजिसे मैंने अपने उदाहरण में एम्बेड किया है।

example.c

#include <stdio.h>
#include <string.h>
#include <sys/mman.h>

int main()
{
    void* p;
    p = mmap(NULL, 8192,PROT_READ,MAP_ANONYMOUS|MAP_PRIVATE,-1,0);

    {
        FILE *f;
        char line[512], s_search[17];
        snprintf(s_search,16,"%lx",(long)p);
        f = fopen("/proc/self/maps","r");
        while (fgets(line,512,f))
        {
            if (strstr(line,s_search)) fputs(line,stderr);
        }

        fclose(f);
    }

    return 0;
}

example.s : एक खाली फ़ाइल है!

आउटपुट

ASM के साथ संस्करण भी शामिल है

VirtualBox:~/mechanics/build$ gcc example.c example.s -o example && ./example
7f78d6e08000-7f78d6e0a000 r-xp 00000000 00:00 0 

ASM के बिना संस्करण शामिल है

VirtualBox:~/mechanics/build$ gcc example.c -o example && ./example
7f1569296000-7f1569298000 r--p 00000000 00:00 0 

5
यह गंभीर रूप से अजीब है।
फ़ूज

6
मैं इसे केवल जीसीसी (कोई सीएमके) के साथ पुन: पेश करने में कामयाब रहा, इसलिए मैंने उदाहरण को अधिक न्यूनतम बनाने के लिए प्रश्न को संपादित किया।
जोसेफ सेबल-मोनिका


आप सही हो सकते हैं, वह जवाब का हिस्सा READ_IMPLIES_EXEC व्यक्तित्व के आसपास होना चाहिए
बेन Hirschberg

के साथ अपने स्रोत फ़ाइलों को इकट्ठा करो -Wa,--noexecstack
jww

जवाबों:


90

लिनक्स में एक निष्पादन डोमेन कहा जाता है READ_IMPLIES_EXEC, जिसके कारण आवंटित सभी पृष्ठ PROT_READभी दिए जा सकते हैं PROT_EXEC। यह कार्यक्रम आपको दिखाएगा कि क्या यह स्वयं के लिए सक्षम है:

#include <stdio.h>
#include <sys/personality.h>

int main(void) {
    printf("Read-implies-exec is %s\n", personality(0xffffffff) & READ_IMPLIES_EXEC ? "true" : "false");
    return 0;
}

यदि आप .sइसे एक खाली फ़ाइल के साथ संकलित करते हैं , तो आप देखेंगे कि यह सक्षम है, लेकिन एक के बिना, यह अक्षम हो जाएगा। इसका प्रारंभिक मूल्य आपके बाइनरी में ईएलएफ मेटा-सूचना से आता है । करते हैं readelf -Wl example। खाली .sफ़ाइल के बिना संकलित करने पर आपको यह रेखा दिखाई देगी :

  GNU_STACK      0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW  0x10

लेकिन यह एक जब आप इसके साथ संकलित:

  GNU_STACK      0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RWE 0x10

RWEसिर्फ के बजाय ध्यान दें RW। इसका कारण यह है कि लिंकर यह मानता है कि आपकी असेंबली फ़ाइलों को रीड-इंप्लीज़-एग्ज़ाम्पल की आवश्यकता होती है जब तक कि यह स्पष्ट रूप से नहीं बताया जाता है कि वे नहीं करते हैं, और यदि आपके प्रोग्राम के किसी भी हिस्से को रीड-इम्पी-एक्ज़ीक्यूट की आवश्यकता है, तो यह आपके पूरे प्रोग्राम के लिए सक्षम है। । असेंबली फ़ाइलें जो GCC संकलित करती हैं, वे बताती हैं कि इस पंक्ति के साथ इसकी आवश्यकता नहीं है (यदि आप इसका संकलन करते हैं तो आप इसे देखेंगे -S):

        .section        .note.GNU-stack,"",@progbits

उस लाइन को डालें example.s, और यह लिंकर को यह बताने के लिए काम करेगा कि उसे इसकी कोई आवश्यकता नहीं है, और आपका प्रोग्राम तब उम्मीद के मुताबिक काम करेगा।


13
पवित्र बकवास, यह एक अजीब डिफ़ॉल्ट है। मुझे लगता है कि टूलकिन noexec से पहले मौजूद था, और noexec बनाने से डिफ़ॉल्ट टूटी हुई चीजें हो सकती थीं। अब मैं उत्सुक हूं कि अन्य असेंबलर जैसे NASM / YASM कैसे .oफाइलें बनाते हैं ! लेकिन वैसे भी, मुझे लगता है कि यह वह तंत्र है जो gcc -zexecstackउपयोग करता है, और क्यों यह न केवल स्टैक बनाता है, बल्कि सब कुछ निष्पादन योग्य है।
पीटर कॉर्ड्स

23
@ पेटर - यही कारण है कि बोटन, क्रिप्टो ++ और ओपनएसएसएल जैसी परियोजनाएं, जो कोडांतरक का उपयोग करती हैं, जोड़ती हैं -Wa,--noexecstack। मुझे लगता है कि यह बहुत बुरा तेज धार है। Nx-stacks का साइलेंट लॉस सुरक्षा भेद्यता होना चाहिए। बिनुतिल लोगों को इसे ठीक करना चाहिए।
jww

14
@jww यह वास्तव में एक सुरक्षा समस्या है, अजीब बात है कि इससे पहले किसी ने भी इसकी सूचना नहीं दी थी
बेन हिर्शबर्ग

4
+1, लेकिन यह उत्तर बहुत बेहतर होगा यदि पंक्ति के अर्थ / तर्क .note.GNU-stack,"",@progbitsको समझाया गया था - अभी यह अपारदर्शी है, "वर्णों के इस जादुई स्ट्रिंग के समान" यह प्रभाव पैदा करता है ", लेकिन स्ट्रिंग स्पष्ट रूप से ऐसा लगता है कि यह किसी प्रकार का है अर्थ विज्ञान।
mtraceur

33

जीएनयू-विशिष्ट अनुभाग निर्देशक वेरिएंट के साथ अपनी विधानसभा फ़ाइलों को संशोधित करने के विकल्प के रूप में, आप -Wa,--noexecstackविधानसभा फ़ाइलों के निर्माण के लिए अपनी कमांड लाइन में जोड़ सकते हैं । उदाहरण के लिए, देखें कि मैं इसे मसल में कैसे करूँ configure:

https://git.musl-libc.org/cgit/musl/commit/configure?id=adefe830dd376be386df5650a09c313c483adf1a

मेरा मानना ​​है कि एकीकृत-असेंबलर के साथ क्लैंग के कम से कम कुछ संस्करणों को इसे --noexecstack(बिना -Wa) के पास किए जाने की आवश्यकता हो सकती है , इसलिए आपकी कॉन्फ़िगर स्क्रिप्ट को संभवतः दोनों की जांच करनी चाहिए और देखना चाहिए जो स्वीकार किया गया है।

आप परिणाम प्राप्त करने के लिए -Wl,-z,noexecstackलिंक समय (इन LDFLAGS) पर भी उपयोग कर सकते हैं । इसका नुकसान यह है कि यह मदद नहीं करता है अगर आपकी परियोजना .aअन्य सॉफ़्टवेयर द्वारा उपयोग के लिए स्थिर ( ) लाइब्रेरी फ़ाइलों का उत्पादन करती है , क्योंकि आप तब लिंक-टाइम विकल्पों को नियंत्रित नहीं करते हैं जब यह अन्य कार्यक्रमों द्वारा उपयोग किया जाता है।


1
हम्म ... मुझे नहीं पता था कि आप इस पोस्ट को पढ़ने से पहले रिच फेलकर थे। आपका प्रदर्शन नाम डलिया क्यों नहीं है?
एसएस ऐनी
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.