Linux Applications Debugging Techniques/Stack corruption

From Wikibooks, open books for an open world
Jump to navigation Jump to search

Stack corruption is rather hard to diagnose. Luckily, gcc 4.x can instrument the code to check for stack corruption:

  • -fstack-protector Add stack protection to functions that have “alloca” or have a (signed or unsigned) char array with size > 8 (SSP_BUFFER_SIZE)
  • -fstack-protector-strong To more functions, see below
  • -fstack-protector-all To ALL functions

gcc will add guard variables and code to check for buffer overflows upon exiting a function. A quick example:

/* Compile with: gcc -ggdb -fstack-protector-all stacktest.c */

#include <stdio.h>
#include <string.h>
 
void bar(char* str) 
{
    char buf[4];
    strcpy(buf, str);
}
	 
void foo() 
{
    printf("It survived!");
}
	 
int main(void) 
{
    bar("Longer than 4.");
    foo();
    return 0;
}

When run, the program will dump core:

$ ./a.out 
*** stack smashing detected ***: ./a.out terminated
Aborted (core dumped)
Core was generated by `./a.out'.
Program terminated with signal 6, Aborted.
#0  0x0000003684030265 in raise () from /lib64/libc.so.6
(gdb) bt full
#0  0x0000003684030265 in raise () from /lib64/libc.so.6
No symbol table info available.
#1  0x0000003684031d10 in abort () from /lib64/libc.so.6
No symbol table info available.
#2  0x000000368406a84b in __libc_message () from /lib64/libc.so.6
No symbol table info available.
#3  0x00000036840e8ebf in __stack_chk_fail () from /lib64/libc.so.6
No symbol table info available.
#4  0x0000000000400584 in bar (str=0x400715 "Longer than 4.") at stacktest.c:10
        buf =           "Long"
#5  0x00000000004005e3 in main () at stacktest.c:19
No locals.

-fstack-protector-strong[edit | edit source]

Added by google to gcc.

Benefit - gain big performance while sacrificing little security (for scenarios using -fstack-protector-all)

Background - some times stack-protector is too-simple while stack-protector-all over-kills, for example, to build one of our core systems, we forcibly add "-fstack-protector-all" to all compile commands, which brings big performance penalty (due to extra stack guard/check insns on function prologue and epilogue) on both atom and arm. To use "-fstack-protector" is just regarded as not secure enough (only "protects" <2% functions) by the system secure team. "-fstack-protector-strong" hits the balance between "-fstack-protector" and "-fstack-protector-all".

Adds the check to a function:

  • if any of its local variable’s address is taken, as part of the RHS of an assignment
  • or if any of its local variable’s address is taken as part of a function argument.
  • or if it has an array, regardless of array type or length
  • or if it has a struct/union which contains an array, regardless of array type or length.
  • or if function has register local variables

See http://gcc.gnu.org/ml/gcc-patches/2012-06/msg00974.html

Further reading[edit | edit source]


Starting with gcc 4.9 and later, you can use the ubsan sanitizer for bounds checking.