Linux Applications Debugging Techniques/Stack corruption
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.