X86 में - लिनक्स खंड रजिस्टरों बफर अतिप्रवाह जांच करने के लिए उपयोग किया जाता है [नीचे कोड स्निपेट देखना जिसने stac में कुछ चार सरणी परिभाषित की है के]:
static void
printint(int xx, int base, int sgn)
{
char digits[] = "ABCDEF";
char buf[16];
int i, neg;
uint x;
neg = 0;
if(sgn && xx < 0){
neg = 1;
x = -xx;
} else {
x = xx;
}
i = 0;
do{
buf[i++] = digits[x % base];
}while((x /= base) != 0);
if(neg)
buf[i++] = '-';
while(--i >= 0)
my_putc(buf[i]);
}
अब यदि हम कोड जीसीसी-जेनरेट कोड के असेंबली को देखते हैं। समारोह printint के लिए कोडांतरक कोड के
डंप:
0x00000000004005a6 <+0>: push %rbp
0x00000000004005a7 <+1>: mov %rsp,%rbp
0x00000000004005aa <+4>: sub $0x50,%rsp
0x00000000004005ae <+8>: mov %edi,-0x44(%rbp)
0x00000000004005b1 <+11>: mov %esi,-0x48(%rbp)
0x00000000004005b4 <+14>: mov %edx,-0x4c(%rbp)
0x00000000004005b7 <+17>: mov %fs:0x28,%rax ------> obtaining an 8 byte guard from based on a fixed offset from fs segment register [from the descriptor base in the corresponding gdt entry]
0x00000000004005c0 <+26>: mov %rax,-0x8(%rbp) -----> pushing it as the first local variable on to stack
0x00000000004005c4 <+30>: xor %eax,%eax
0x00000000004005c6 <+32>: movl $0x33323130,-0x20(%rbp)
0x00000000004005cd <+39>: movl $0x37363534,-0x1c(%rbp)
0x00000000004005d4 <+46>: movl $0x42413938,-0x18(%rbp)
0x00000000004005db <+53>: movl $0x46454443,-0x14(%rbp)
...
...
// function end
0x0000000000400686 <+224>: jns 0x40066a <printint+196>
0x0000000000400688 <+226>: mov -0x8(%rbp),%rax -------> verifying if the stack was smashed
0x000000000040068c <+230>: xor %fs:0x28,%rax --> checking the value on stack is matching the original one based on fs
0x0000000000400695 <+239>: je 0x40069c <printint+246>
0x0000000000400697 <+241>: callq 0x400460 <[email protected]>
0x000000000040069c <+246>: leaveq
0x000000000040069d <+247>: retq
अब अगर हम इस समारोह से ढेर आधारित चार सरणियों निकालने के लिए, जीसीसी यह गार्ड की जांच नहीं होगी।
मैंने कर्नेल मॉड्यूल के लिए भी जीसीसी द्वारा उत्पन्न किया है। असल में मैं कुछ कर्नेल कोड को बोट्रैप करते समय एक क्रैश देख रहा था और यह वर्चुअल एड्रेस 0x28 के साथ गलती कर रहा था। बाद में मैंने सोचा कि मैंने सोचा था कि मैंने स्टैक पॉइंटर को सही तरीके से शुरू किया है और प्रोग्राम को सही तरीके से लोड किया है, मेरे पास जीडीटी में सही प्रविष्टियां नहीं हैं, जो एफएस आधारित ऑफ़सेट को वैध आभासी पते में अनुवादित करेगी।
हालांकि कर्नेल कोड के मामले में यह केवल अनदेखा कर रहा था, __stack_chk_fail @ plt> जैसे कुछ पर कूदने की बजाय त्रुटि।
प्रासंगिक कंपाइलर विकल्प जो इस गार्ड को जीसीसी में जोड़ता है -फस्टैक-रक्षक है। मुझे लगता है कि यह डिफ़ॉल्ट रूप से सक्षम है जो उपयोगकर्ता ऐप को संकलित करता है।
कर्नेल के लिए, हम कॉन्फ़िगरेशन CC_STACKPROTECTOR विकल्प के माध्यम से इस जीसीसी ध्वज को सक्षम कर सकते हैं।
config CC_STACKPROTECTOR
699 bool "Enable -fstack-protector buffer overflow detection (EXPERIMENTAL)"
700 depends on SUPERH32
701 help
702 This option turns on the -fstack-protector GCC feature. This
703 feature puts, at the beginning of functions, a canary value on
704 the stack just before the return address, and validates
705 the value just before actually returning. Stack based buffer
706 overflows (that need to overwrite this return address) now also
707 overwrite the canary, which gets detected and the attack is then
708 neutralized via a kernel panic.
709
710 This feature requires gcc version 4.2 or above.
प्रासंगिक गिरी फ़ाइल जहां इस जी एस/FS है linux/चाप/86/शामिल/ASM/stackprotector.h
ठीक है, तो डीपीएल प्रत्येक खंड के लिए न्यूनतम सुरक्षा स्तर सेट, लेकिन ऐसा लगता है जैसे कि मैं किसी भी रैखिक पते को उपयोगकर्ता के रूप में एक्सेस कर सकता हूं, तो कर्नेल के लिए अतिरिक्त सेगमेंट क्यों है? यदि, उपयोगकर्ता के रूप में, मैं मेमोरी एड्रेस एक्स एक्सेस करना चाहता हूं, तो मैं एक्स के ऑफसेट के साथ उपयोगकर्ता डेटा सेगमेंट का उपयोग करता हूं। कर्नेल कर्नेल डेटा सेगमेंट का एक्स के ऑफसेट के साथ उपयोग कर सकता है, लेकिन यह एक ही रैखिक पते पर नक्शा कर सकता है, इस प्रकार भौतिक स्मृति में एक ही पता है, तो यह कोई सुरक्षा कैसे प्रदान करता है? –
@anjruu: कुछ असेंबली निर्देशों को एक निश्चित विशेषाधिकार स्तर की आवश्यकता होती है या फिर एक सामान्य सुरक्षा (जीपी) गलती उठाई जाती है। उदाहरण के लिए, बंदरगाह से बाइट पढ़ने के लिए 'IN' निर्देश के लिए वर्तमान पीएल (सीपीएल) इनपुट/आउटपुट पीएल (आईओपीएल; बिट्स 12 और 13' फ्लैग्स रजिस्टर के बराबर या उससे कम होने की आवश्यकता होती है, जो कि लिनक्स के लिए 0 है। सीपीएल 'सीएस' (कोड सेगमेंट) रजिस्टर से संबंधित सेगमेंट डिस्क्रिप्टर का डीपीएल है। –
@ Daniel: Gotcha, यह समझ में आता है। धन्यवाद! –