স্ট্যাক স্ম্যাশিং সনাক্ত হয়েছে


246

আমি আমার a.out ফাইল এক্সিকিউট করছি। মৃত্যুদন্ড কার্যকর করার পরে প্রোগ্রামটি কিছু সময়ের জন্য চলে এবং তারপরে বার্তাটি দিয়ে বের হয়:

**** stack smashing detected ***: ./a.out terminated*
*======= Backtrace: =========*
*/lib/tls/i686/cmov/libc.so.6(__fortify_fail+0x48)Aborted*

এর সম্ভাব্য কারণগুলি কী হতে পারে এবং আমি কীভাবে এটি সংশোধন করব?


2
আপনি সম্ভবত কোন কোডটির কোন অংশটি স্ট্যাককে বিপর্যয়ের কারণ হিসাবে চিহ্নিত করতে এবং এটি পোস্ট করতে পারেন? তারপরে আমরা সম্ভবত এটি কেন ঘটতে পারে এবং কীভাবে এটি সংশোধন করতে পারে তা নির্দিষ্টভাবে উল্লেখ করতে সক্ষম হব।
বার্জার ফ্রেন্ড-হানসেন

আমি মনে করি এটি ওভারফ্লো ত্রুটির সমার্থক শব্দ। উদাহরণস্বরূপ আপনি যদি 5 টি উপাদানকে আরম্ভ এবং অ্যারে করেন তবে 6 তম উপাদানটি বা অ্যারের সীমানার বাইরে কোনও উপাদান লেখার চেষ্টা করার সময় এই ত্রুটিটি উপস্থিত হবে।
ডোরিনপপেস্কু

উত্তর:


349

বাফার ওভারফ্লো ত্রুটিগুলি সনাক্ত করতে জিসিসি দ্বারা ব্যবহৃত সুরক্ষা ব্যবস্থার কারণে এখানে স্ট্যাক স্ম্যাশিং আসলে ঘটে। উদাহরণস্বরূপ নিম্নলিখিত স্নিপেটে:

#include <stdio.h>

void func()
{
    char array[10];
    gets(array);
}

int main(int argc, char **argv)
{
    func();
}

সংকলক, (এই ক্ষেত্রে জিসিসি) সুরক্ষা ভেরিয়েবল যুক্ত করে (ক্যানারি বলে) যা জ্ঞাত মান রয়েছে। 10 টিরও বেশি আকারের একটি ইনপুট স্ট্রিং এই পরিবর্তনশীলটির দুর্নীতির কারণ সিগাবআরটি প্রোগ্রামটি বন্ধ করে দেয়।

কিছুটা অন্তর্দৃষ্টি পেতে, -fno-stack-protector সংকলনের সময় আপনি বিকল্পটি ব্যবহার করে জিসিসির এই সুরক্ষাটি অক্ষম করার চেষ্টা করতে পারেন । সেক্ষেত্রে আপনি একটি অন্যর ত্রুটি পাবেন, সম্ভবত আপনি কোনও অবৈধ মেমরির অবস্থান অ্যাক্সেস করার চেষ্টা করার কারণে একটি বিভাজন ত্রুটি সম্ভবত। -fstack-protectorএটি সুরক্ষা বৈশিষ্ট্য হিসাবে প্রকাশিত বিল্ডগুলির জন্য সর্বদা চালু করা উচিত নোট ।

আপনি কোনও ডিবাগার দিয়ে প্রোগ্রামটি চালিয়ে ওভারফ্লো এর পয়েন্ট সম্পর্কে কিছু তথ্য পেতে পারেন। ভালগ্রাইন্ড স্ট্যাক-সম্পর্কিত ত্রুটিগুলি দিয়ে ভাল কাজ করে না তবে একটি ডিবাগারের মতো এটি ক্রাশের অবস্থান এবং কারণটি পিন-পয়েন্ট করতে সহায়তা করতে পারে।


3
এই উত্তরের জন্য ধন্যবাদ! আমি দেখতে পেলাম যে আমার ক্ষেত্রে আমি যে পরিবর্তনশীলটি লিখতে
চাইছিলাম


7
এই উত্তরটি ভুল, এবং বিপজ্জনক পরামর্শ সরবরাহ করে। প্রথমত, স্ট্যাক প্রটেক্টর অপসারণ করা সঠিক সমাধান নয় - আপনি যদি স্ট্যাকের স্ম্যাশিংয়ের ত্রুটি পেয়ে থাকেন তবে আপনার কোডটিতে সম্ভবত আপনার একটি গুরুতর সুরক্ষা দুর্বলতা রয়েছে। সঠিক প্রতিক্রিয়া হ'ল বাগী কোডটি ঠিক করা । দ্বিতীয়ত, গ্রেসগেন্ডারমে উল্লেখ করেছেন যে, ভালগ্রাইন্ডের চেষ্টা করার পরামর্শটি কার্যকর হবে না। Valgrind সাধারণত স্ট্যাক-বরাদ্দকৃত ডেটা অবৈধ মেমরির প্রবেশাধিকার সনাক্ত করার জন্য কাজ করে না।
DW

22
ওপি এই আচরণের সম্ভাব্য কারণ জিজ্ঞাসা করে, আমার উত্তর একটি উদাহরণ দেয় এবং এটি কীভাবে যুক্তিসঙ্গতভাবে পরিচিত ত্রুটির সাথে সম্পর্কিত rela এছাড়াও, স্ট্যাক-প্রটেক্টর অপসারণ কোনও সমাধান নয়, এটি সমস্যার আরও অন্তর্দৃষ্টি পাওয়ার জন্য এটি করা এক ধরনের পরীক্ষা। আসলে পরামর্শটি হ'ল ত্রুটিটি কোনওভাবে সংশোধন করা উচিত, ভালগ্রাইন্ড সম্পর্কে নির্দেশ করার জন্য ধন্যবাদ, আমি আমার উত্তরটি এটি সম্পাদন করতে সম্পাদনা করব।
Sud03r

4
@ ডিডাব্লু স্ট্যাক সুরক্ষা একটি রিলিজ সংস্করণে বন্ধ করা উচিত, কারণ প্রথমে - স্ট্যাকের স্ম্যাশিং সনাক্ত করা বার্তা কেবল একটি বিকাশকারীদের জন্য সহায়তা; দ্বিতীয়ত - একটি অ্যাপ্লিকেশন এখনও বেঁচে থাকার সম্ভাবনা থাকতে পারে; এবং তৃতীয় স্থানে - এটি একটি ক্ষুদ্রতর অনুকূলতা।
হাই-অ্যাঞ্জেল

33

অপ্রয়োজনীয় বিশ্লেষণ সহ ন্যূনতম প্রজনন উদাহরণ

main.c

void myfunc(char *const src, int len) {
    int i;
    for (i = 0; i < len; ++i) {
        src[i] = 42;
    }
}

int main(void) {
    char arr[] = {'a', 'b', 'c', 'd'};
    int len = sizeof(arr);
    myfunc(arr, len + 1);
    return 0;
}

গিটহাব উজানের দিকে

সংকলন এবং চালান:

gcc -fstack-protector -g -O0 -std=c99 main.c
ulimit -c unlimited && rm -f core
./a.out

কাঙ্ক্ষিত হিসাবে ব্যর্থ:

*** stack smashing detected ***: ./a.out terminated
Aborted (core dumped)

উবুন্টু 16.04, জিসিসি 6.4.0 এ পরীক্ষিত।

disassembly

এখন আমরা বিচ্ছিন্নতা তাকান:

objdump -D a.out

যেটা বহন করে:

int main (void){
  400579:       55                      push   %rbp
  40057a:       48 89 e5                mov    %rsp,%rbp

  # Allocate 0x10 of stack space.
  40057d:       48 83 ec 10             sub    $0x10,%rsp

  # Put the 8 byte canary from %fs:0x28 to -0x8(%rbp),
  # which is right at the bottom of the stack.
  400581:       64 48 8b 04 25 28 00    mov    %fs:0x28,%rax
  400588:       00 00 
  40058a:       48 89 45 f8             mov    %rax,-0x8(%rbp)

  40058e:       31 c0                   xor    %eax,%eax
    char arr[] = {'a', 'b', 'c', 'd'};
  400590:       c6 45 f4 61             movb   $0x61,-0xc(%rbp)
  400594:       c6 45 f5 62             movb   $0x62,-0xb(%rbp)
  400598:       c6 45 f6 63             movb   $0x63,-0xa(%rbp)
  40059c:       c6 45 f7 64             movb   $0x64,-0x9(%rbp)
    int len = sizeof(arr);
  4005a0:       c7 45 f0 04 00 00 00    movl   $0x4,-0x10(%rbp)
    myfunc(arr, len + 1);
  4005a7:       8b 45 f0                mov    -0x10(%rbp),%eax
  4005aa:       8d 50 01                lea    0x1(%rax),%edx
  4005ad:       48 8d 45 f4             lea    -0xc(%rbp),%rax
  4005b1:       89 d6                   mov    %edx,%esi
  4005b3:       48 89 c7                mov    %rax,%rdi
  4005b6:       e8 8b ff ff ff          callq  400546 <myfunc>
    return 0;
  4005bb:       b8 00 00 00 00          mov    $0x0,%eax
}
  # Check that the canary at -0x8(%rbp) hasn't changed after calling myfunc.
  # If it has, jump to the failure point __stack_chk_fail.
  4005c0:       48 8b 4d f8             mov    -0x8(%rbp),%rcx
  4005c4:       64 48 33 0c 25 28 00    xor    %fs:0x28,%rcx
  4005cb:       00 00 
  4005cd:       74 05                   je     4005d4 <main+0x5b>
  4005cf:       e8 4c fe ff ff          callq  400420 <__stack_chk_fail@plt>

  # Otherwise, exit normally.
  4005d4:       c9                      leaveq 
  4005d5:       c3                      retq   
  4005d6:       66 2e 0f 1f 84 00 00    nopw   %cs:0x0(%rax,%rax,1)
  4005dd:       00 00 00 

objdumpএর কৃত্রিম বুদ্ধিমত্তা মডিউল দ্বারা স্বয়ংক্রিয়ভাবে যুক্ত মন্তব্যগুলি লক্ষ্য করুন ।

আপনি যদি জিডিবির মাধ্যমে একাধিকবার এই প্রোগ্রামটি চালান, আপনি দেখতে পাবেন:

  • ক্যানারি প্রতিবার একটি ভিন্ন এলোমেলো মান পায়
  • শেষ লুপটি myfuncহ'ল ক্যানারিটির ঠিকানা পরিবর্তন করে

ক্যানারিটি সেট করে এটি এলোমেলো করে রেখেছে, এতে বর্ণিত %fs:0x28একটি এলোমেলো মান রয়েছে:

ডিবাগ প্রচেষ্টা

এখন থেকে, আমরা কোডটি পরিবর্তন করেছি:

    myfunc(arr, len + 1);

পরিবর্তে হতে:

    myfunc(arr, len);
    myfunc(arr, len + 1); /* line 12 */
    myfunc(arr, len);

আরও আকর্ষণীয় হতে।

এরপরে আমরা চেষ্টা করব যে আমরা + 1পুরো সোর্স কোডটি পড়ার এবং বোঝার চেয়ে কোনও স্বয়ংক্রিয় পদ্ধতিতে অপরাধীর কলটিকে চিহ্নিত করতে পারি কিনা ।

gcc -fsanitize=address গুগলের ঠিকানা স্যানিটাইজার (আসান) সক্ষম করতে

আপনি যদি এই পতাকাটির সাথে পুনরায় সংকলন করে এবং প্রোগ্রামটি চালনা করেন তবে এটি আউটপুট দেয়:

#0 0x4008bf in myfunc /home/ciro/test/main.c:4
#1 0x40099b in main /home/ciro/test/main.c:12
#2 0x7fcd2e13d82f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
#3 0x400798 in _start (/home/ciro/test/a.out+0x40079

এর পরে আরও কিছু রঙিন আউটপুট আসে।

এটি স্পষ্টভাবে সমস্যাযুক্ত লাইনটি 12 চিহ্নিত করে।

এর উত্স কোডটি এখানে রয়েছে: https://github.com/google/sanitizers তবে উদাহরণ থেকে আমরা দেখেছি এটি ইতিমধ্যে জিসিসিতে উত্থিত হয়েছে।

আসান মেমরি ফাঁসের মতো অন্যান্য মেমরি সমস্যাও সনাক্ত করতে পারে: একটি সি ++ কোড / প্রকল্পে মেমরি ফাঁস কীভাবে পাওয়া যায়?

ভালগ্রাইন্ড এসজিচেক

অন্যদের দ্বারা যেমন উল্লেখ করা হয়েছে , ভালগ্র্যান্ড এই ধরণের সমস্যা সমাধানে ভাল নয়।

এটিতে এসজিচেক নামে একটি পরীক্ষামূলক সরঞ্জাম রয়েছে :

এসজিচেক স্ট্যাক এবং গ্লোবাল অ্যারেগুলির ওভাররানগুলি অনুসন্ধান করার জন্য একটি সরঞ্জাম। এটি স্ট্যাক এবং বিশ্বব্যাপী অ্যারে অ্যাক্সেসের সম্ভাব্য ফর্মগুলি সম্পর্কে একটি পর্যবেক্ষণ থেকে প্রাপ্ত হিউরিস্টিক পদ্ধতির ব্যবহার করে কাজ করে।

সুতরাং ত্রুটিটি না পেয়ে আমি খুব অবাক হইনি:

valgrind --tool=exp-sgcheck ./a.out

ত্রুটি বার্তাটি আপাতদৃষ্টিতে দেখতে হবে: ভালগ্র্যান্ড রেকর্ডিং ত্রুটি

, GDB

একটি গুরুত্বপূর্ণ পর্যবেক্ষণটি হ'ল আপনি যদি প্রোগ্রামটি জিডিবির মাধ্যমে পরিচালনা করেন বা coreফাইলটি পরীক্ষা করে দেখেন:

gdb -nh -q a.out core

তারপরে, আমরা সমাবেশে দেখেছি, জিডিবি আপনাকে ক্যানারি চেক করে ফাংশনটির শেষের দিকে নির্দেশ করবে:

(gdb) bt
#0  0x00007f0f66e20428 in __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:54
#1  0x00007f0f66e2202a in __GI_abort () at abort.c:89
#2  0x00007f0f66e627ea in __libc_message (do_abort=do_abort@entry=1, fmt=fmt@entry=0x7f0f66f7a49f "*** %s ***: %s terminated\n") at ../sysdeps/posix/libc_fatal.c:175
#3  0x00007f0f66f0415c in __GI___fortify_fail (msg=<optimized out>, msg@entry=0x7f0f66f7a481 "stack smashing detected") at fortify_fail.c:37
#4  0x00007f0f66f04100 in __stack_chk_fail () at stack_chk_fail.c:28
#5  0x00000000004005f6 in main () at main.c:15
(gdb) f 5
#5  0x00000000004005f6 in main () at main.c:15
15      }
(gdb)

এবং তাই এই ফাংশনটি করেছে যে কলগুলির মধ্যে একটিতে সম্ভবত সমস্যা।

এরপরে আমরা ক্যানারি স্থাপনের ঠিক পরে প্রথম একক পদক্ষেপের মাধ্যমে সঠিক ব্যর্থ কলটি চিহ্নিত করার চেষ্টা করব:

  400581:       64 48 8b 04 25 28 00    mov    %fs:0x28,%rax
  400588:       00 00 
  40058a:       48 89 45 f8             mov    %rax,-0x8(%rbp)

এবং ঠিকানাটি দেখছেন:

(gdb) p $rbp - 0x8
$1 = (void *) 0x7fffffffcf18
(gdb) watch 0x7fffffffcf18
Hardware watchpoint 2: *0x7fffffffcf18
(gdb) c
Continuing.

Hardware watchpoint 2: *0x7fffffffcf18

Old value = 1800814336
New value = 1800814378
myfunc (src=0x7fffffffcf14 "*****?Vk\266", <incomplete sequence \355\216>, len=5) at main.c:3
3           for (i = 0; i < len; ++i) {
(gdb) p len
$2 = 5
(gdb) p i
$3 = 4
(gdb) bt
#0  myfunc (src=0x7fffffffcf14 "*****?Vk\266", <incomplete sequence \355\216>, len=5) at main.c:3
#1  0x00000000004005cc in main () at main.c:12

এখন, এটি আমাদের আপত্তিজনক সঠিক নির্দেশে ফেলেছে: len = 5এবং i = 4, এবং এই বিশেষ ক্ষেত্রে, আমাদের দোষী রেখার দিকে 12 নির্দেশ করেছে।

তবে, ব্যাকট্রিসটি দূষিত এবং এতে কিছু আবর্জনা রয়েছে। একটি সঠিক ব্যাকট্রেস দেখতে পাবেন:

#0  myfunc (src=0x7fffffffcf14 "abcd", len=4) at main.c:3
#1  0x00000000004005b8 in main () at main.c:11

সুতরাং এটি স্ট্যাকটিকে দূষিত করতে পারে এবং ট্রেসটি দেখতে বাধা দিতে পারে।

এছাড়াও, এই পদ্ধতিটি ক্যানারি চেকিং ফাংশনটির শেষ কলটি কী তা জেনে রাখা দরকার অন্যথায় আপনার কাছে মিথ্যা ধনাত্মকতা থাকবে, যা আপনি সর্বদা সম্ভব হবে না, যদি না আপনি বিপরীত ডিবাগিং ব্যবহার করেন


16

দয়া করে নীচের পরিস্থিতিটি দেখুন:

ab@cd-x:$ cat test_overflow.c 
#include <stdio.h>
#include <string.h>

int check_password(char *password){
    int flag = 0;
    char buffer[20];
    strcpy(buffer, password);

    if(strcmp(buffer, "mypass") == 0){
        flag = 1;
    }
    if(strcmp(buffer, "yourpass") == 0){
        flag = 1;
    }
    return flag;
}

int main(int argc, char *argv[]){
    if(argc >= 2){
        if(check_password(argv[1])){
            printf("%s", "Access granted\n");
        }else{
            printf("%s", "Access denied\n");
        }
    }else{
        printf("%s", "Please enter password!\n");
    }
}
ab@cd-x:$ gcc -g -fno-stack-protector test_overflow.c 
ab@cd-x:$ ./a.out mypass
Access granted
ab@cd-x:$ ./a.out yourpass
Access granted
ab@cd-x:$ ./a.out wepass
Access denied
ab@cd-x:$ ./a.out wepassssssssssssssssss
Access granted

ab@cd-x:$ gcc -g -fstack-protector test_overflow.c 
ab@cd-x:$ ./a.out wepass
Access denied
ab@cd-x:$ ./a.out mypass
Access granted
ab@cd-x:$ ./a.out yourpass
Access granted
ab@cd-x:$ ./a.out wepassssssssssssssssss
*** stack smashing detected ***: ./a.out terminated
======= Backtrace: =========
/lib/tls/i686/cmov/libc.so.6(__fortify_fail+0x48)[0xce0ed8]
/lib/tls/i686/cmov/libc.so.6(__fortify_fail+0x0)[0xce0e90]
./a.out[0x8048524]
./a.out[0x8048545]
/lib/tls/i686/cmov/libc.so.6(__libc_start_main+0xe6)[0xc16b56]
./a.out[0x8048411]
======= Memory map: ========
007d9000-007f5000 r-xp 00000000 08:06 5776       /lib/libgcc_s.so.1
007f5000-007f6000 r--p 0001b000 08:06 5776       /lib/libgcc_s.so.1
007f6000-007f7000 rw-p 0001c000 08:06 5776       /lib/libgcc_s.so.1
0090a000-0090b000 r-xp 00000000 00:00 0          [vdso]
00c00000-00d3e000 r-xp 00000000 08:06 1183       /lib/tls/i686/cmov/libc-2.10.1.so
00d3e000-00d3f000 ---p 0013e000 08:06 1183       /lib/tls/i686/cmov/libc-2.10.1.so
00d3f000-00d41000 r--p 0013e000 08:06 1183       /lib/tls/i686/cmov/libc-2.10.1.so
00d41000-00d42000 rw-p 00140000 08:06 1183       /lib/tls/i686/cmov/libc-2.10.1.so
00d42000-00d45000 rw-p 00000000 00:00 0 
00e0c000-00e27000 r-xp 00000000 08:06 4213       /lib/ld-2.10.1.so
00e27000-00e28000 r--p 0001a000 08:06 4213       /lib/ld-2.10.1.so
00e28000-00e29000 rw-p 0001b000 08:06 4213       /lib/ld-2.10.1.so
08048000-08049000 r-xp 00000000 08:05 1056811    /dos/hacking/test/a.out
08049000-0804a000 r--p 00000000 08:05 1056811    /dos/hacking/test/a.out
0804a000-0804b000 rw-p 00001000 08:05 1056811    /dos/hacking/test/a.out
08675000-08696000 rw-p 00000000 00:00 0          [heap]
b76fe000-b76ff000 rw-p 00000000 00:00 0 
b7717000-b7719000 rw-p 00000000 00:00 0 
bfc1c000-bfc31000 rw-p 00000000 00:00 0          [stack]
Aborted
ab@cd-x:$ 

আমি যখন স্ট্যাকের স্ম্যাশিং প্রোটেক্টরকে অক্ষম করেছিলাম তখন কোনও ত্রুটি সনাক্ত করা যায় নি, যা আমি যখন "./a.out ওয়েপাসসসসসসএসএসএসএসএস ব্যবহার করি তখন হওয়া উচিত ছিল"

সুতরাং উপরের আপনার প্রশ্নের উত্তর দেওয়ার জন্য, "** স্ট্যাকের স্ম্যাশিং সনাক্ত হয়েছে: xxx" বার্তাটি প্রদর্শিত হয়েছিল কারণ আপনার স্ট্যাকের স্ম্যাশিং প্রোটেক্টর সক্রিয় ছিল এবং আপনার প্রোগ্রামে স্ট্যাকের ওভারফ্লো রয়েছে।

এটি কোথায় ঘটে তা সন্ধান করুন এবং এটি ঠিক করুন।


7

আপনি ভালগ্র্যান্ড ব্যবহার করে সমস্যাটি ডিবাগ করার চেষ্টা করতে পারেন :

ভালগ্র্যান্ড বিতরণে বর্তমানে ছয়টি উত্পাদন-মানের সরঞ্জাম রয়েছে: একটি মেমরি ত্রুটি সনাক্তকারী, দুটি থ্রেড ত্রুটি সনাক্তকারী, একটি ক্যাশে এবং শাখা-পূর্বাভাস প্রোফাইলার, একটি কল-গ্রাফ উত্সাহক ক্যাশে প্রোফাইলার এবং একটি হিপ প্রোফাইলার। এটিতে দুটি পরীক্ষামূলক সরঞ্জামও অন্তর্ভুক্ত রয়েছে: একটি হিপ / স্ট্যাক / গ্লোবাল অ্যারে ওভাররন ডিটেক্টর এবং একটি সিমপয়েন্ট বেসিক ব্লক ভেক্টর জেনারেটর। এটি নিম্নলিখিত প্ল্যাটফর্মগুলিতে চলছে: এক্স 86 / লিনাক্স, এএমডি 64 / লিনাক্স, পিপিসি 32 / লিনাক্স, পিপিসি 64 / লিনাক্স এবং এক্স 86 / ডারউইন (ম্যাক ওএস এক্স)।


2
হ্যাঁ, তবে ভালগ্র্যান্ড স্ট্যাক-বরাদ্দ করা বাফারগুলির অতিরিক্ত প্রবাহের জন্য ভাল কাজ করে না, যা এই ত্রুটি বার্তাকে বোঝায় এমন পরিস্থিতি।
DW

4
আমরা কীভাবে সেই স্ট্যাক অ্যারে ওভাররান ডিটেক্টরটি ব্যবহার করতে পারি ? তুমি কি বিস্তারিত বলতে পারো?
ক্রেগ ম্যাককুইন

আমি Valgrind এর পরীক্ষামূলক অনুসন্ধানমূলক SGCheck স্ট্যাক একটি ন্যূনতম উদাহরণ মর্মান্তিক আবিষ্কারক ব্যবহার করার চেষ্টা করেছি @CraigMcQueen: stackoverflow.com/a/51897264/895245 কিন্তু এটি ব্যর্থ হয়েছে।
সিরো সান্তিলি 郝海东 冠状 病 六四 事件 法轮功

4

এর মানে আপনি একটি অবৈধ ভাবে স্ট্যাক কিছু ভেরিয়েবল লিখেছেন, একটি ফল হিসাবে সম্ভবত বাফার ওভারফ্লো


9
স্ট্যাক ওভারফ্লো হ'ল স্ট্যাকটি অন্য কোনও কিছুর মধ্যে ছড়িয়ে পড়ে। এখানে এটি অন্যান্য উপায়ে: কিছু স্ট্যাকের মধ্যে ছড়িয়ে পড়েছে।
পিটার মর্টেনসেন

5
আসলে তা না. এটি স্ট্যাকের একটি অংশ অন্য অংশে ছড়িয়ে পড়ে। সুতরাং এটি সত্যিই একটি বাফার ওভারফ্লো, কেবল স্ট্যাকের শীর্ষের উপরে নয়, স্ট্যাকের অন্য অংশে "কেবল"।
বাস উইজেনেন

2

এর সম্ভাব্য কারণগুলি কী হতে পারে এবং আমি কীভাবে এটি সংশোধন করব?

একটি দৃশ্য নিম্নলিখিত উদাহরণে হবে:

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

void swap ( char *a , char *b );
void revSTR ( char *const src );

int main ( void ){
    char arr[] = "A-B-C-D-E";

    revSTR( arr );
    printf("ARR = %s\n", arr );
}

void swap ( char *a , char *b ){
    char tmp = *a;
    *a = *b;
    *b = tmp;
}

void revSTR ( char *const src ){
    char *start = src;
    char *end   = start + ( strlen( src ) - 1 );

    while ( start < end ){
        swap( &( *start ) , &( *end ) );
        start++;
        end--;
    }
}

এই প্রোগ্রামে আপনি একটি স্ট্রিং বা স্ট্রিংয়ের একটি অংশ বিপরীত করতে পারেন যদি আপনি উদাহরণস্বরূপ এর reverse()মতো কিছু দিয়ে কল করেন:

reverse( arr + 2 );

আপনি যদি অ্যারের দৈর্ঘ্যটি এভাবে পাস করার সিদ্ধান্ত নেন:

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

void swap ( char *a , char *b );
void revSTR ( char *const src, size_t len );

int main ( void ){
    char arr[] = "A-B-C-D-E";
    size_t len = strlen( arr );

    revSTR( arr, len );
    printf("ARR = %s\n", arr );
}

void swap ( char *a , char *b ){
    char tmp = *a;
    *a = *b;
    *b = tmp;
}

void revSTR ( char *const src, size_t len ){
    char *start = src;
    char *end   = start + ( len - 1 );

    while ( start < end ){
        swap( &( *start ) , &( *end ) );
        start++;
        end--;
    }
}

খুব ভাল কাজ করে।

তবে আপনি যখন এটি করেন:

revSTR( arr + 2, len );

আপনি পাবেন:

==7125== Command: ./program
==7125== 
ARR = A-
*** stack smashing detected ***: ./program terminated
==7125== 
==7125== Process terminating with default action of signal 6 (SIGABRT)
==7125==    at 0x4E6F428: raise (raise.c:54)
==7125==    by 0x4E71029: abort (abort.c:89)
==7125==    by 0x4EB17E9: __libc_message (libc_fatal.c:175)
==7125==    by 0x4F5311B: __fortify_fail (fortify_fail.c:37)
==7125==    by 0x4F530BF: __stack_chk_fail (stack_chk_fail.c:28)
==7125==    by 0x400637: main (program.c:14)

এবং এটি ঘটে কারণ প্রথম arrকোডটিতে দৈর্ঘ্যটি ভালভাবে পরীক্ষা করা revSTR()হয় তবে দ্বিতীয় কোডে যেখানে আপনি দৈর্ঘ্যটি পাস করেন:

revSTR( arr + 2, len );

দৈর্ঘ্যটি এখন আর লম্বা হবে যখন আপনি বলবেন তখন আসল দৈর্ঘ্যটি আপনার পাস হবে arr + 2

দৈর্ঘ্য strlen ( arr + 2 )! = strlen ( arr )


1
আমি এই উদাহরণটি পছন্দ করি কারণ এটি স্ট্যান্ডার্ড লাইব্রেরি ফাংশনের মতো getsএবং এর উপর নির্ভর করে না scrcpy। আমি অবাক হই যদি আমরা আরও কিছুটা কমাতে পারি তাহলে। আমি অন্তত পরিত্রাণ পেতে হবে string.hসঙ্গে size_t len = sizeof( arr );। Gcc 6.4, উবুন্টু 16.04 এ পরীক্ষিত। arr + 2কপি পেস্ট কমিয়ে আনার জন্য আমি ব্যর্থ উদাহরণ দিয়ে দেব ।
সিরো সান্তিলি 郝海东 冠状 病 六四 事件 法轮功

1

বাফার ওভারফ্লো প্রসারণের কারণে স্ট্যাকের দুর্নীতির ঘটনা ঘটে। আপনি তাদের বিরুদ্ধে ডিফেন্সিভ প্রোগ্রামিং করে ডিফেন্ড করতে পারেন।

আপনি যখনই কোনও অ্যারে অ্যাক্সেস করেন, অ্যাক্সেসের সীমা অতিক্রম না হয় তা নিশ্চিত করার জন্য এটির আগে একটি দৃsert়তা রাখুন। উদাহরণ স্বরূপ:

assert(i + 1 < N);
assert(i < N);
a[i + 1] = a[i];

এটি আপনাকে অ্যারে সীমানা সম্পর্কে চিন্তাভাবনা করে এবং যদি সম্ভব হয় তবে তাদের ট্রিগার করতে পরীক্ষা যুক্ত করার বিষয়ে ভাবনা তৈরি করে। যদি সাধারণ ব্যবহারের সময় এগুলির কিছু দৃ fail় ব্যর্থ হতে পারে তবে এগুলিকে নিয়মিত রূপান্তর করুন if


0

এই ডিবাগিং কোডটি কিছু ব্যয় করার পরে স্ট্রাক্টকে কিছু মেমরি বরাদ্দ করার জন্য malloc () ব্যবহার করার সময় আমি এই ত্রুটিটি পেয়েছি, অবশেষে বরাদ্দ হওয়া মেমরিটি মুক্ত করার জন্য আমি ফ্রি () ফাংশন ব্যবহার করেছি এবং পরবর্তীকালে ত্রুটি বার্তাটি গিয়েছে :)


0

স্ট্যাক স্ম্যাশিংয়ের আর একটি উত্স হ'ল এর vfork()পরিবর্তে (ভুল) ব্যবহার fork()

আমি সবেমাত্র এর একটি কেস ডিবাগ করেছি, যেখানে শিশু প্রক্রিয়া কার্যকর করতে সক্ষম execve()টার্গেটে অক্ষম ছিল এবং কল করার পরিবর্তে একটি ত্রুটি কোড ফেরত দেয় _exit()

যেহেতু vfork()এই শিশুটিকে উত্সাহিত করেছে, এটি পিতামাতার প্রক্রিয়া স্পেসের মধ্যে এখনও কার্যকর করার সময় এটি ফিরে এসেছিল, কেবল পিতামাতার স্ট্যাককেই ক্ষতিগ্রস্থ করে না, তবে ডায়াগনস্টিকসের দুটি পৃথক সেটকে "ডাউন স্ট্রিম" কোড দ্বারা মুদ্রিত করে তোলে।

পরিবর্তন vfork()করার জন্য fork()সংশোধন করা হয়েছে উভয় সমস্যা, যেমন সন্তানের পরিবর্তন করেনি returnথেকে বিবৃতি _exit()পরিবর্তে।

তবে যেহেতু চাইল্ড কোডটি execve()অন্যান্য রুটিনগুলিতে কল করার আগে কল করেছিল (ইউআইড / গিড সেট করতে, এই বিশেষ ক্ষেত্রে), এটি প্রযুক্তিগতভাবে প্রয়োজনীয়তা পূরণ করে না vfork(), তাই এটি ব্যবহারের fork()জন্য পরিবর্তন করা এখানে সঠিক।

(নোট যে সমস্যাযুক্ত returnবিবৃতি আসলে যেমন কোডেড হয়েছে না - পরিবর্তে, একটি ম্যাক্রো চালানো হয়েছিল, এবং যে ম্যাক্রো সিদ্ধান্ত নিয়েছে কিনা _exit()বা returnএকটি বিশ্বব্যাপী পরিবর্তনশীল উপর ভিত্তি করে সুতরাং এটি অবিলম্বে সুস্পষ্ট যে সন্তান কোড প্রথাবিরোধী হয় নি। vfork()ব্যবহার সঞ্চয় করুন। )

আরও তথ্যের জন্য, দেখুন:

কাঁটাচামচ (), ভিফোর্ক (), এক্সিকিউট () এবং ক্লোন () এর মধ্যে পার্থক্য

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.