使用 -fstack-protector 选项的编译脚本
[root@Betty stack_smash_test]# cat mk.sh
#!/bin/bash
g++ -O2 -Wall -m32 -shared -Wl,-fpic captureexception.cpp -o libcaptureexception.so
gcc -g -fstack-protector -Wall -U_FORTIFY_SOURCE -m32 stack_smash.c -o stack_smash_debug -L. -lcaptureexception
strip --strip-debug stack_smash_debug -o stack_smash
[root@Betty stack_smash_test]#
测试程序
[
]void func()
{
char array[10];
gets(array);
}
int main(int argc, char **argv)
{
func();
}
编译
[root@Betty stack_smash_test]# ./mk.sh
captureexception.cpp: In function ‘void TsSigHandler(int, siginfo_t*, void*)’:
captureexception.cpp:565: 警告:‘sigaction::<anonymous union>’的初始值设定周围缺少花括号
captureexception.cpp: In function ‘s32 CaptureExceptionInit()’:
captureexception.cpp:628: 警告:‘sigaction::<anonymous union>’的初始值设定周围缺少花括号
stack_smash.c: 在函数‘main’中:
stack_smash.c:19: 警告:在有返回值的函数中,控制流程到达函数尾
/tmp/ccybKl4m.o: In function `func':
/root/workspace/CODE_TEST/Cpp/stack_smash_test/stack_smash.c:13: warning: the `gets' function is dangerous and should not be used.
[root@Betty stack_smash_test]# ll
总用量 64
-rw-r--r-- 1 root root 19348 5月 12 19:34 captureexception.cpp
-rwxr-xr-x 1 root root 13728 5月 12 19:36 libcaptureexception.so
-rwxr-xr-x 1 root root 262 5月 12 19:36 mk.sh
-rwxr-xr-x 1 root root 51 5月 12 19:36 run.sh
-rwxr-xr-x 1 root root 4993 5月 12 19:36 stack_smash
-rw-r--r-- 1 root root 388 5月 12 19:16 stack_smash.c
-rwxr-xr-x 1 root root 6450 5月 12 19:36 stack_smash_debug
[root@Betty stack_smash_test]#
运行
[root@Betty stack_smash_test]# ./run.sh
aaaaabbbbbccc
*** stack smashing detected ***: ./stack_smash terminated
======= Backtrace: =========
/lib/libc.so.6(__fortify_fail+0x4d)[0x768e1d]
/lib/libc.so.6[0x768dca]
./stack_smash[0x8048511]
./stack_smash[0x804851e]
/lib/libc.so.6(__libc_start_main+0xe6)[0x682d36]
./stack_smash[0x8048451]
======= Memory map: ========
001ae000-0028d000 r-xp 00000000 fd:00 919870 /usr/lib/libstdc++.so.6.0.13
0028d000-00291000 r--p 000de000 fd:00 919870 /usr/lib/libstdc++.so.6.0.13
00291000-00292000 rw-p 000e2000 fd:00 919870 /usr/lib/libstdc++.so.6.0.13
00292000-00299000 rw-p 00000000 00:00 0
00442000-0045f000 r-xp 00000000 fd:00 1323084 /lib/libgcc_s-4.4.7-20120601.so.1
0045f000-00460000 rw-p 0001d000 fd:00 1323084 /lib/libgcc_s-4.4.7-20120601.so.1
0064a000-00668000 r-xp 00000000 fd:00 1316933 /lib/ld-2.12.so
00668000-00669000 r--p 0001d000 fd:00 1316933 /lib/ld-2.12.so
00669000-0066a000 rw-p 0001e000 fd:00 1316933 /lib/ld-2.12.so
0066c000-007fc000 r-xp 00000000 fd:00 1315201 /lib/libc-2.12.so
007fc000-007fd000 ---p 00190000 fd:00 1315201 /lib/libc-2.12.so
007fd000-007ff000 r--p 00190000 fd:00 1315201 /lib/libc-2.12.so
007ff000-00800000 rw-p 00192000 fd:00 1315201 /lib/libc-2.12.so
00800000-00803000 rw-p 00000000 00:00 0
0090b000-00933000 r-xp 00000000 fd:00 1318051 /lib/libm-2.12.so
00933000-00934000 r--p 00027000 fd:00 1318051 /lib/libm-2.12.so
00934000-00935000 rw-p 00028000 fd:00 1318051 /lib/libm-2.12.so
00e51000-00e52000 r-xp 00000000 00:00 0 [vdso]
00e90000-00e93000 r-xp 00000000 fd:00 1722961 /root/workspace/CODE_TEST/Cpp/stack_smash_test/libcaptureexception.so
00e93000-00e94000 rw-p 00002000 fd:00 1722961 /root/workspace/CODE_TEST/Cpp/stack_smash_test/libcaptureexception.so
08048000-08049000 r-xp 00000000 fd:00 1722964 /root/workspace/CODE_TEST/Cpp/stack_smash_test/stack_smash
08049000-0804a000 rw-p 00000000 fd:00 1722964 /root/workspace/CODE_TEST/Cpp/stack_smash_test/stack_smash
081cd000-081ee000 rw-p 00000000 00:00 0 [heap]
f76f4000-f76f7000 rw-p 00000000 00:00 0
f7709000-f770c000 rw-p 00000000 00:00 0
ffb4c000-ffb61000 rw-p 00000000 00:00 0 [stack]
./run.sh: line 2: 29719 已放弃 (core dumped) LD_LIBRARY_PATH=`pwd` ./stack_smash $*
[root@Betty stack_smash_test]#
[root@Betty stack_smash_test]# ll
总用量 228
-rw-r--r-- 1 root root 19348 5月 12 19:34 captureexception.cpp
-rw------- 1 root root 397312 5月 12 19:37 core.29719
-rwxr-xr-x 1 root root 13728 5月 12 19:36 libcaptureexception.so
-rwxr-xr-x 1 root root 262 5月 12 19:36 mk.sh
-rwxr-xr-x 1 root root 51 5月 12 19:36 run.sh
-rwxr-xr-x 1 root root 4993 5月 12 19:36 stack_smash
-rw-r--r-- 1 root root 388 5月 12 19:16 stack_smash.c
-rwxr-xr-x 1 root root 6450 5月 12 19:36 stack_smash_debug
[root@Betty stack_smash_test]#
通过 gdb 查看
[root@Betty stack_smash_test]# gdb stack_smash_debug core.29719
...
Core was generated by `./stack_smash'.
Program terminated with signal 6, Aborted.
#0 0x00e51430 in __kernel_vsyscall ()
Missing separate debuginfos, use: debuginfo-install glibc-2.12-1.166.el6_7.7.i686 libgcc-4.4.7-16.el6.i686 libstdc++-4.4.7-16.el6.i686
(gdb) bt
#0 0x00e51430 in __kernel_vsyscall ()
#1 0x00696871 in raise () from /lib/libc.so.6
#2 0x0069814a in abort () from /lib/libc.so.6
#3 0x006d6735 in __libc_message () from /lib/libc.so.6
#4 0x00768e1d in __fortify_fail () from /lib/libc.so.6
#5 0x00768dca in __stack_chk_fail () from /lib/libc.so.6
#6 0x08048511 in func () at stack_smash.c:14
#7 0x0804851e in main (argc=1, argv=0xffb5eb74) at stack_smash.c:18
(gdb) info registers
eax 0x0 0
ecx 0x7417 29719
edx 0x6 6
ebx 0x7417 29719
esp 0xffb5e304 0xffb5e304
ebp 0xffb5e31c 0xffb5e31c
esi 0x0 0
edi 0x7feff4 8384500
eip 0xe51430 0xe51430 <__kernel_vsyscall+16>
eflags 0x296 [ PF AF SF IF ]
cs 0x23 35
ss 0x2b 43
ds 0x2b 43
es 0x2b 43
fs 0x0 0
gs 0x63 99
(gdb) disassemble
Dump of assembler code for function __kernel_vsyscall:
0x00e51420 <+0>: push %ecx
0x00e51421 <+1>: push %edx
0x00e51422 <+2>: push %ebp
0x00e51423 <+3>: mov %esp,%ebp
0x00e51425 <+5>: sysenter
0x00e51427 <+7>: nop
0x00e51428 <+8>: nop
0x00e51429 <+9>: nop
0x00e5142a <+10>: nop
0x00e5142b <+11>: nop
0x00e5142c <+12>: nop
0x00e5142d <+13>: nop
0x00e5142e <+14>: jmp 0xe51423 <__kernel_vsyscall+3>
=> 0x00e51430 <+16>: pop %ebp
0x00e51431 <+17>: pop %edx
0x00e51432 <+18>: pop %ecx
0x00e51433 <+19>: ret
End of assembler dump.
(gdb) q
[root@Betty stack_smash_test]#
使用 -fno-stack-protector 选项的编译脚本
[root@Betty stack_smash_test]# cat mk.sh
#!/bin/bash
g++ -O2 -Wall -m32 -shared -Wl,-fpic captureexception.cpp -o libcaptureexception.so
gcc -g -fno-stack-protector -Wall -U_FORTIFY_SOURCE -m32 stack_smash.c -o stack_smash_debug -L. -lcaptureexception
strip --strip-debug stack_smash_debug -o stack_smash
[root@Betty stack_smash_test]#
编译
[root@Betty stack_smash_test]# ./mk.sh
captureexception.cpp: In function ‘void TsSigHandler(int, siginfo_t*, void*)’:
captureexception.cpp:565: 警告:‘sigaction::<anonymous union>’的初始值设定周围缺少花括号
captureexception.cpp: In function ‘s32 CaptureExceptionInit()’:
captureexception.cpp:628: 警告:‘sigaction::<anonymous union>’的初始值设定周围缺少花括号
stack_smash.c: 在函数‘main’中:
stack_smash.c:19: 警告:在有返回值的函数中,控制流程到达函数尾
/tmp/ccY1mRzr.o: In function `func':
/root/workspace/CODE_TEST/Cpp/stack_smash_test/stack_smash.c:13: warning: the `gets' function is dangerous and should not be used.
[root@Betty stack_smash_test]#
[root@Betty stack_smash_test]# ll
总用量 228
-rw-r--r-- 1 root root 19348 5月 12 19:34 captureexception.cpp
-rw------- 1 root root 397312 5月 12 19:37 core.29719
-rwxr-xr-x 1 root root 13728 5月 12 19:41 libcaptureexception.so
-rwxr-xr-x 1 root root 265 5月 12 19:40 mk.sh
-rwxr-xr-x 1 root root 51 5月 12 19:36 run.sh
-rwxr-xr-x 1 root root 4833 5月 12 19:41 stack_smash
-rw-r--r-- 1 root root 388 5月 12 19:16 stack_smash.c
-rwxr-xr-x 1 root root 6286 5月 12 19:41 stack_smash_debug
[root@Betty stack_smash_test]#
运行
[root@Betty stack_smash_test]# ./run.sh
dddddeeeeefff
[root@Betty stack_smash_test]# ll
总用量 228
-rw-r--r-- 1 root root 19348 5月 12 19:34 captureexception.cpp
-rw------- 1 root root 397312 5月 12 19:37 core.29719
-rwxr-xr-x 1 root root 13728 5月 12 19:41 libcaptureexception.so
-rwxr-xr-x 1 root root 265 5月 12 19:40 mk.sh
-rwxr-xr-x 1 root root 51 5月 12 19:36 run.sh
-rwxr-xr-x 1 root root 4833 5月 12 19:41 stack_smash
-rw-r--r-- 1 root root 388 5月 12 19:16 stack_smash.c
-rwxr-xr-x 1 root root 6286 5月 12 19:41 stack_smash_debug
[root@Betty stack_smash_test]#
未触发崩溃
使用 -fstack-protector 选项,同时移除异常捕获库的使用
[root@Betty stack_smash_test]#
[root@Betty stack_smash_test]# gcc -g -fstack-protector -m32 stack_smash.c -o stack_smash_debug
/tmp/ccvc4lqK.o: In function `func':
/root/workspace/CODE_TEST/Cpp/stack_smash_test/stack_smash.c:13: warning: the `gets' function is dangerous and should not be used.
[root@Betty stack_smash_test]# strip --strip-debug stack_smash_debug -o stack_smash
[root@Betty stack_smash_test]# ll
总用量 64
-rw-r--r-- 1 root root 19348 5月 12 19:34 captureexception.cpp
-rwxr-xr-x 1 root root 13728 5月 12 19:44 libcaptureexception.so
-rwxr-xr-x 1 root root 262 5月 12 19:43 mk.sh
-rwxr-xr-x 1 root root 51 5月 12 19:36 run.sh
-rwxr-xr-x 1 root root 4777 5月 12 19:46 stack_smash
-rw-r--r-- 1 root root 388 5月 12 19:16 stack_smash.c
-rwxr-xr-x 1 root root 6234 5月 12 19:45 stack_smash_debug
[root@Betty stack_smash_test]#
运行
[root@Betty stack_smash_test]#
[root@Betty stack_smash_test]# ./stack_smash
asdasdasdasdasdasd
*** stack smashing detected ***: ./stack_smash terminated
======= Backtrace: =========
/lib/libc.so.6(__fortify_fail+0x4d)[0x768e1d]
/lib/libc.so.6[0x768dca]
./stack_smash[0x8048441]
./stack_smash[0x804844e]
/lib/libc.so.6(__libc_start_main+0xe6)[0x682d36]
./stack_smash[0x8048381]
======= Memory map: ========
0064a000-00668000 r-xp 00000000 fd:00 1316933 /lib/ld-2.12.so
00668000-00669000 r--p 0001d000 fd:00 1316933 /lib/ld-2.12.so
00669000-0066a000 rw-p 0001e000 fd:00 1316933 /lib/ld-2.12.so
0066c000-007fc000 r-xp 00000000 fd:00 1315201 /lib/libc-2.12.so
007fc000-007fd000 ---p 00190000 fd:00 1315201 /lib/libc-2.12.so
007fd000-007ff000 r--p 00190000 fd:00 1315201 /lib/libc-2.12.so
007ff000-00800000 rw-p 00192000 fd:00 1315201 /lib/libc-2.12.so
00800000-00803000 rw-p 00000000 00:00 0
009e7000-00a04000 r-xp 00000000 fd:00 1323084 /lib/libgcc_s-4.4.7-20120601.so.1
00a04000-00a05000 rw-p 0001d000 fd:00 1323084 /lib/libgcc_s-4.4.7-20120601.so.1
00e1d000-00e1e000 r-xp 00000000 00:00 0 [vdso]
08048000-08049000 r-xp 00000000 fd:00 1722963 /root/workspace/CODE_TEST/Cpp/stack_smash_test/stack_smash
08049000-0804a000 rw-p 00000000 fd:00 1722963 /root/workspace/CODE_TEST/Cpp/stack_smash_test/stack_smash
0964b000-0966c000 rw-p 00000000 00:00 0 [heap]
f76fd000-f76fe000 rw-p 00000000 00:00 0
f7710000-f7713000 rw-p 00000000 00:00 0
ff8a7000-ff8bc000 rw-p 00000000 00:00 0 [stack]
已放弃 (core dumped)
[root@Betty stack_smash_test]#
[root@Betty stack_smash_test]# ll
总用量 160
-rw-r--r-- 1 root root 19348 5月 12 19:34 captureexception.cpp
-rw------- 1 root root 307200 5月 12 19:46 core.29827
-rwxr-xr-x 1 root root 13728 5月 12 19:44 libcaptureexception.so
-rwxr-xr-x 1 root root 262 5月 12 19:43 mk.sh
-rwxr-xr-x 1 root root 51 5月 12 19:36 run.sh
-rwxr-xr-x 1 root root 4777 5月 12 19:46 stack_smash
-rw-r--r-- 1 root root 388 5月 12 19:16 stack_smash.c
-rwxr-xr-x 1 root root 6234 5月 12 19:45 stack_smash_debug
[root@Betty stack_smash_test]#
通过 gdb 查看
[root@Betty stack_smash_test]# gdb stack_smash_debug core.29827
GNU gdb (GDB) Red Hat Enterprise Linux (7.2-60.el6)
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /root/workspace/CODE_TEST/Cpp/stack_smash_test/stack_smash_debug...done.
warning: core file may not match specified executable file.
[New Thread 29827]
Missing separate debuginfo for
Try: yum --disablerepo='*' --enablerepo='*-debug*' install /usr/lib/debug/.build-id/d1/3e9f00612bb0d54f7301a1555926b8d7348aee
Reading symbols from /lib/libc.so.6...(no debugging symbols found)...done.
Loaded symbols for /lib/libc.so.6
Reading symbols from /lib/ld-linux.so.2...(no debugging symbols found)...done.
Loaded symbols for /lib/ld-linux.so.2
Reading symbols from /lib/libgcc_s.so.1...(no debugging symbols found)...done.
Loaded symbols for /lib/libgcc_s.so.1
Core was generated by `./stack_smash'.
Program terminated with signal 6, Aborted.
#0 0x00e1d430 in __kernel_vsyscall ()
Missing separate debuginfos, use: debuginfo-install glibc-2.12-1.166.el6_7.7.i686 libgcc-4.4.7-16.el6.i686
(gdb) bt
#0 0x00e1d430 in __kernel_vsyscall ()
#1 0x00696871 in raise () from /lib/libc.so.6
#2 0x0069814a in abort () from /lib/libc.so.6
#3 0x006d6735 in __libc_message () from /lib/libc.so.6
#4 0x00768e1d in __fortify_fail () from /lib/libc.so.6
#5 0x00768dca in __stack_chk_fail () from /lib/libc.so.6
#6 0x08048441 in func () at stack_smash.c:14
#7 0x0804844e in main (argc=1, argv=0xff8bab84) at stack_smash.c:18
(gdb) info registers
eax 0x0 0
ecx 0x7483 29827
edx 0x6 6
ebx 0x7483 29827
esp 0xff8ba314 0xff8ba314
ebp 0xff8ba32c 0xff8ba32c
esi 0x0 0
edi 0x7feff4 8384500
eip 0xe1d430 0xe1d430 <__kernel_vsyscall+16>
eflags 0x296 [ PF AF SF IF ]
cs 0x23 35
ss 0x2b 43
ds 0x2b 43
es 0x2b 43
fs 0x0 0
gs 0x63 99
(gdb) disassemble
Dump of assembler code for function __kernel_vsyscall:
0x00e1d420 <+0>: push %ecx
0x00e1d421 <+1>: push %edx
0x00e1d422 <+2>: push %ebp
0x00e1d423 <+3>: mov %esp,%ebp
0x00e1d425 <+5>: sysenter
0x00e1d427 <+7>: nop
0x00e1d428 <+8>: nop
0x00e1d429 <+9>: nop
0x00e1d42a <+10>: nop
0x00e1d42b <+11>: nop
0x00e1d42c <+12>: nop
0x00e1d42d <+13>: nop
0x00e1d42e <+14>: jmp 0xe1d423 <__kernel_vsyscall+3>
=> 0x00e1d430 <+16>: pop %ebp
0x00e1d431 <+17>: pop %edx
0x00e1d432 <+18>: pop %ecx
0x00e1d433 <+19>: ret
End of assembler dump.
(gdb) q
[root@Betty stack_smash_test]#
小结:
- 使用 -fstack-protector 选项能够检测出 stack smashing 问题,并在测到问题时通过 abort 方式触发 core dump;
- 使用 -fno-stack-protector 选项(默认?)时,是否触发 core dump 视具体情况而定;
- 使用 -fstack-protector 能够触发 core dump 生成的另外一个条件是,SIGABRT 信号未被型号处理函数所忽略;
在 stackoverflow 上找到的一个相关问题。
Stack smashing detected
问题:
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?
回答:
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:
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.
关键点:
- gcc 启用了一种保护机制进行 buffer overflow 错误的探测;而 Stack Smashing 是在使用了该机制后才会被触发;
- gcc 会使用一个名为 canaries 的保护变量,并将其初始化为特定值;
- 一旦该保护变量的内容在 overflow 发生时被篡改,将会触发 SIGABRT 信号进而终止当前程序运行;
- 作为对比实验,可以通过 -fno-stack-protector 去使能该机制,此时编译得到的可执行程序在运行时可能会触发不同的错误,例如 SIGSEGV 等,也可能暂时不触发任何错误;
- 作为一种安全特性 -fstack-protector 应该在可执行程序的 release 版本中使用打开;
- Valgrind 针对 stack overflow 相关错误无法给出有效的检测结果(该结论可以在 Valgrind 的 FAQ 中看到)
转载于:https://my.oschina.net/moooofly/blog/675695