在C/C++语言中,由于代码书写人员能够直接通过指针来操作内存的内容,在通常的时候没有可靠的方法来防止对数组的越界访问读写操作。但是,我们可以在发生了越界访问的时候,在没有造成任何有害结果之前,尝试检测到他。栈保护机制是在栈帧中任何局部缓冲区与栈状态之间存储一个特殊的“金丝雀值”,也称为“哨兵值”。
用以下代码来验证gcc编译时默认带有栈溢出检测机制。
#include <string.h>
#include <stdio.h>
char *gets(char *s)
{
int c;
char *dest = s;
while((c = getchar()) != '\n' && c != EOF)
*dest++ = c ;
if(c == EOF && dest == s)
{
return NULL;
}
*dest++ = '\0';
return s;
}
void echo()
{
char buf[8];
gets(buf);
puts(buf);
}
int main(void)
{
echo();
return 0;
}
编译时用命令
g++ test.cpp -o test
运行后输入:
zzzzzzzzzzzzzz
程序core掉后生成的core文件解析
(gdb) bt
#0 0x00007f49dcb4ec37 in __GI_raise (sig=sig@entry=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:56
#1 0x00007f49dcb52028 in __GI_abort () at abort.c:89
#2 0x00007f49dcb8b2a4 in __libc_message (do_abort=do_abort@entry=1, fmt=fmt@entry=0x7f49dcc9adb0 "*** %s ***: %s terminated\n") at ../sysdeps/posix/libc_fatal.c:175
#3 0x00007f49dcc2687c in __GI___fortify_fail (msg=<optimized out>, msg@entry=0x7f49dcc9ad98 "stack smashing detected") at fortify_fail.c:38
#4 0x00007f49dcc26820 in __stack_chk_fail () at stack_chk_fail.c:28
#5 0x00000000004006c7 in echo() ()
#6 0x00000000004006d2 in main ()
可以看到是由于__stack_chk_fail导致程序被终止了,这时我们就能及时发现栈溢出发生在echo()函数中。
用gcc编译时也是同样的结果,所以可以直到编译时栈溢出保护机制默认是打开的。
如果不想打开栈溢出保护机制怎么办?编译时加入如下编译选项即可
-fno-stack-protector