GCC ASAN内存检测工具 笔记

GCC DEBUG 相关参数 官方手册

https://gcc.gnu.org/onlinedocs/gcc/Debugging-Options.html

我的环境

时间:

1
2
3
chunli@blog:~/source$ date
Wed 30 Nov 2022 06:38:20 PM CST
chunli@blog:~/source$

软件

1
2
3
4
5
6
chunli@blog:~/source$ gcc --version
gcc (Debian 10.2.1-6) 10.2.1 20210110
Copyright (C) 2020 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
chunli@blog:~/source$

程序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
chunli@blog:~/source$ cat gcc_asan_test.c
#include <stdio.h>
#include <string.h>

int fun1(char *dst, const char *str)
{
dst[10] = str[10];
return 0;
}

int main()
{
char buff[10];
const char *str = "HelloWorld HelloWorld HelloWorld";
fun1(buff, str);

return 0;
}
chunli@blog:~/source$

直接运行

运行即崩溃

1
2
3
chunli@blog:~/source$ gcc -g -O1 gcc_asan_test.c && ./a.out
Segmentation fault
chunli@blog:~/source$

asan 运行

加上 fsanitize 再运行, 可以直接看到报错了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
chunli@blog:~/source$ gcc -g -O1 -fsanitize=address gcc_asan_test.c && ./a.out

错误的说明很有用, 指出了 gcc_asan_test.c:7 存在 stack-buffer-overflow
=================================================================
==420560==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffe05f9017a at pc 0x7f37b961c8a1 bp 0x7ffe05f90100 sp 0x7ffe05f8f8b0
WRITE of size 32 at 0x7ffe05f9017a thread T0
#0 0x7f37b961c8a0 in __interceptor_memcpy ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:806
#1 0x5589aebaa1cc in fun1 /home/chunli/source/gcc_asan_test.c:7
#2 0x5589aebaa263 in main /home/chunli/source/gcc_asan_test.c:15
#3 0x7f37b9431d09 in __libc_start_main ../csu/libc-start.c:308
#4 0x5589aebaa0d9 in _start (/home/chunli/source/a.out+0x10d9)

Address 0x7ffe05f9017a is located in stack of thread T0 at offset 42 in frame
#0 0x5589aebaa1e3 in main /home/chunli/source/gcc_asan_test.c:12

ASAN 断点

这样课可以看到错误原因,但是看不到触发条件
GDB ASAN 断点

  1. b __asan::ReportGenericError 发现了错误,断点位于汇报信息之前
  2. b __sanitizer::Die 发现了错误,断点位于汇报信息之后

如果这个程序, 发到项目现场, 会发现依赖了一个 libasan.so.6

1
2
3
4
5
6
7
8
9
10
11
chunli@blog:~/source$ gcc -g -O1 -fsanitize=address gcc_asan_test.c
chunli@blog:~/source$ ldd ./a.out
linux-vdso.so.1 (0x00007ffd1a9f8000)
libasan.so.6 => /lib/x86_64-linux-gnu/libasan.so.6 (0x00007f5c3f175000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f5c3efa0000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f5c3ef9a000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f5c3ef78000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f5c3ee34000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f5c3ee1a000)
/lib64/ld-linux-x86-64.so.2 (0x00007f5c3fb4b000)
chunli@blog:~/source$

为了便于发布到现场, libasan需要静态编译

1
2
3
4
5
6
7
8
9
10
chunli@blog:~/source$ gcc -g -O1 -fsanitize=address -static-libasan gcc_asan_test.c
chunli@blog:~/source$ ldd a.out
linux-vdso.so.1 (0x00007fff8a6ff000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007fd23efd2000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fd23efb0000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fd23ee6c000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fd23ee52000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fd23ec7d000)
/lib64/ld-linux-x86-64.so.2 (0x00007fd23f98c000)
chunli@blog:~/source$

运行效果

1
2
3
4
5
6
7
8
9
10
11
12
chunli@blog:~/source$ ./a.out
=================================================================
==420593==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7fff926b734a at pc 0x56083c88c121 bp 0x7fff926b72d0 sp 0x7fff926b6a80
WRITE of size 32 at 0x7fff926b734a thread T0
#0 0x56083c88c120 in __interceptor_memcpy (/home/chunli/source/a.out+0x1e120)
#1 0x56083c93b74c in fun1 /home/chunli/source/gcc_asan_test.c:7
#2 0x56083c93b7e3 in main /home/chunli/source/gcc_asan_test.c:15
#3 0x7f91d1223d09 in __libc_start_main ../csu/libc-start.c:308
#4 0x56083c876419 in _start (/home/chunli/source/a.out+0x8419)

Address 0x7fff926b734a is located in stack of thread T0 at offset 42 in frame
#0 0x56083c93b763 in main /home/chunli/source/gcc_asan_test.c:12

ASAN 实现原理

GCC 添加编译选项 -fsanitize=address

程序运行中 会时刻检测 读取/写入 的合法性.
一旦发现 影子内存 的标记 不一致, 马上 调用 report