Stack smashing detected

2019-01-01 12:17发布

I am executing my a.out file. After execution the program runs for some time then exits with the message:

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

What could be the possible reasons for this and how do I rectify it?

9条回答
明月照影归
2楼-- · 2019-01-01 12:36

I got this error while using malloc() to allocate some memory to a struct * after spending some this debugging the code, I finally used free() function to free the allocated memory and subsequently the error message gone :)

查看更多
路过你的时光
3楼-- · 2019-01-01 12:38

What could be the possible reasons for this and how do I rectify it?

One scenario would be in the following example:

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

In this program you can reverse a String or a part of the string if you for example call reverse() with something like this:

reverse( arr + 2 );

If you decide to pass the length of the array like this:

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

Works fine too.

But when you do this:

revSTR( arr + 2, len );

You get get:

==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)

And this happens because in the first code, the length of arr is checked inside of revSTR() which is fine, but in the second code where you pass the length:

revSTR( arr + 2, len );

the Length is now longer then the actually length you pass when you say arr + 2.

Length of strlen ( arr + 2 ) != strlen ( arr ).

查看更多
人间绝色
4楼-- · 2019-01-01 12:42

Stack Smashing here is actually caused due to a protection mechanism used by gcc to detect buffer overflow errors. For example in the following snippet:

#include <stdio.h>

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

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

The compiler, (in this case gcc) adds protection variables (called canaries) which have known values. An input string of size greater than 10 causes corruption of this variable resulting in SIGABRT to terminate the program.

To get some insight, you can try disabling this protection of gcc using option -fno-stack-protector while compiling. In that case you will get a different error, most likely a segmentation fault as you are trying to access an illegal memory location. Note that -fstack-protector should always be turned on for release builds as it is a security feature.

You can get some information about the point of overflow by running the program with a debugger. Valgrind doesn't work well with stack-related errors, but like a debugger, it may help you pin-point the location and reason for the crash.

查看更多
浅入江南
5楼-- · 2019-01-01 12:42

Stack corruptions ususally caused by buffer overflows. You can defend against them by programming defensively.

Whenever you access an array, put an assert before it to ensure the access is not out of bounds. For example:

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

This makes you think about array bounds and also makes you think about adding tests to trigger them if possible. If some of these asserts can fail during normal use turn them into a regular if.

查看更多
孤独寂梦人
6楼-- · 2019-01-01 12:44

Another source of stack smashing is (incorrect) use of vfork() instead of fork().

I just debugged a case of this, where the child process was unable to execve() the target executable and returned an error code rather than calling _exit().

Because vfork() had spawned that child, it returned while actually still executing within the parent's process space, not only corrupting the parent's stack, but causing two disparate sets of diagnostics to be printed by "downstream" code.

Changing vfork() to fork() fixed both problems, as did changing the child's return statement to _exit() instead.

But since the child code precedes the execve() call with calls to other routines (to set the uid/gid, in this particular case), it technically does not meet the requirements for vfork(), so changing it to use fork() is correct here.

(Note that the problematic return statement was not actually coded as such -- instead, a macro was invoked, and that macro decided whether to _exit() or return based on a global variable. So it wasn't immediately obvious that the child code was nonconforming for vfork() usage.)

For more information, see:

The difference between fork(), vfork(), exec() and clone()

查看更多
泪湿衣
7楼-- · 2019-01-01 12:46

Please look at the following situation:

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:$ 

When I disabled the stack smashing protector no errors were detected, which should have happened when I used "./a.out wepassssssssssssssssss"

So to answer your question above, the message "** stack smashing detected : xxx" was displayed because your stack smashing protector was active and found that there is stack overflow in your program.

Just find out where that occurs, and fix it.

查看更多
登录 后发表回答