【原创】实验验证 -fstack-protector 编译选项效果

发布时间 2023-04-20 16:46:35作者: DoubleLi

 

使用 -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]# 
 
 

测试程序

 
 
[root@Betty stack_smash_test]# cat stack_smash.c 
 
 
 
#include<stdio.h>
 
 
 
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:
 
 
 
 
#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.
 
 

关键点:

  • 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