利用C或C++编写系统时,容易出现内存方面的问题,当代码量过大时,我们需要用工具检查代码。其中ascan工具在开销小,本章对此工具的使用作一个简单介绍。
1.栈溢出
cpp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int func0(void)
{
char str[4] = {0};
strcpy(str,"1234");
return 0;
}
int main(int argc,char *argv[])
{
func0();
return 0;
}
编译
bash
$ g++ -g 1.cpp -o 1 -fsanitize=leak -fsanitize=address -fno-omit-frame-pointer
运行
bash
$ ./1
=================================================================
==21786==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffc1f3df6e4 at pc 0x7faf3475077a bp 0x7ffc1f3df6b0 sp 0x7ffc1f3dee58
WRITE of size 5 at 0x7ffc1f3df6e4 thread T0
#0 0x7faf34750779 (/usr/lib/x86_64-linux-gnu/libasan.so.4+0x79779)
#1 0x5643f7fedb48 in func0() /home/zg/zg_code/zg_test/test/ascan_demo/1.cpp:8
#2 0x5643f7fedbac in main /home/zg/zg_code/zg_test/test/ascan_demo/1.cpp:13
#3 0x7faf34307c86 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21c86)
#4 0x5643f7fed999 in _start (/home/zg/zg_code/zg_test/test/ascan_demo/1+0x999)
定位出第8行有栈溢出
2 堆溢出
cpp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void func1(void)
{
char * p = (char*) malloc(sizeof(char)*4);
char chs[] ={"12345"};
memset(p,0x0,4);
if (p != NULL) {
memcpy(p,chs,5);
}
}
int main(int argc,char *argv[])
{
func1();
return 0;
}
编译
bash
$ g++ -g 2.cpp -o 2 -fsanitize=leak -fsanitize=address -fno-omit-frame-pointer
运行
bash
$ ./2
=================================================================
==21804==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x602000000014 at pc 0x7fa9abe2477a bp 0x7ffefe188770 sp 0x7ffefe187f18
WRITE of size 5 at 0x602000000014 thread T0
#0 0x7fa9abe24779 (/usr/lib/x86_64-linux-gnu/libasan.so.4+0x79779)
#1 0x558db4c94b3e in func1() /home/zg/zg_code/zg_test/test/ascan_demo/2.cpp:11
#2 0x558db4c94ba0 in main /home/zg/zg_code/zg_test/test/ascan_demo/2.cpp:17
#3 0x7fa9ab9dbc86 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21c86)
#4 0x558db4c94919 in _start (/home/zg/zg_code/zg_test/test/ascan_demo/2+0x919)
0x602000000014 is located 0 bytes to the right of 4-byte region [0x602000000010,0x602000000014)
allocated by thread T0 here:
#0 0x7fa9abe89b40 in __interceptor_malloc (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xdeb40)
#1 0x558db4c94a86 in func1() /home/zg/zg_code/zg_test/test/ascan_demo/2.cpp:7
#2 0x558db4c94ba0 in main /home/zg/zg_code/zg_test/test/ascan_demo/2.cpp:17
#3 0x7fa9ab9dbc86 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21c86)
SUMMARY: AddressSanitizer: heap-buffer-overflow (/usr/lib/x86_64-linux-gnu/libasan.so.4+0x79779)
Shadow bytes around the buggy address:
0x0c047fff7fb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c047fff7fc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c047fff7fd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c047fff7fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c047fff7ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0c047fff8000: fa fa[04]fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff8010: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff8020: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff8030: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff8040: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff8050: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
==21804==ABORTING
检测出第11行有堆溢出
3 释放后使用
就是申请了一块内存区域,释放后没有设置为NULL,后续继续使用了。
cpp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void func2(void)
{
int * a = (int*)malloc(sizeof(int)*1);
if ( a != NULL ) {
*a = 1;
printf("a is:%d.",*a);
free(a);
*a = 2;
printf("error a is:%d.",*a);
}
}
int main(int argc,char *argv[])
{
func2();
return 0;
}
bash
g++ -g 3.cpp -o 3 -fsanitize=leak -fsanitize=address -fno-omit-frame-pointer
bash
$ ./3
=================================================================
==21822==ERROR: AddressSanitizer: heap-use-after-free on address 0x602000000010 at pc 0x561a596b4ae8 bp 0x7ffed1292570 sp 0x7ffed1292560
WRITE of size 4 at 0x602000000010 thread T0
#0 0x561a596b4ae7 in func2() /home/zg/zg_code/zg_test/test/ascan_demo/3.cpp:12
#1 0x561a596b4b21 in main /home/zg/zg_code/zg_test/test/ascan_demo/3.cpp:19
#2 0x7f6527861c86 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21c86)
#3 0x561a596b4949 in _start (/home/zg/zg_code/zg_test/test/ascan_demo/3+0x949)
0x602000000010 is located 0 bytes inside of 4-byte region [0x602000000010,0x602000000014)
freed by thread T0 here:
#0 0x7f6527d0f7a8 in __interceptor_free (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xde7a8)
#1 0x561a596b4ab0 in func2() /home/zg/zg_code/zg_test/test/ascan_demo/3.cpp:11
#2 0x561a596b4b21 in main /home/zg/zg_code/zg_test/test/ascan_demo/3.cpp:19
#3 0x7f6527861c86 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21c86)
previously allocated by thread T0 here:
#0 0x7f6527d0fb40 in __interceptor_malloc (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xdeb40)
#1 0x561a596b4a3b in func2() /home/zg/zg_code/zg_test/test/ascan_demo/3.cpp:7
#2 0x561a596b4b21 in main /home/zg/zg_code/zg_test/test/ascan_demo/3.cpp:19
#3 0x7f6527861c86 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21c86)
SUMMARY: AddressSanitizer: heap-use-after-free /home/zg/zg_code/zg_test/test/ascan_demo/3.cpp:12 in func2()
Shadow bytes around the buggy address:
检测出第12行,内存使用有问题
4 全局缓存溢出
cpp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int g_abc[11];
int func3(void)
{
int i = 0;
for (i = 0; i <= 100; i++) {
printf("value:%d\t",g_abc[i]);
if (i%10 == 0 && i != 0) {
printf("\n");
}
}
return g_abc[12];
}
int main(int argc,char *argv[])
{
func3();
return 0;
}
bash
g++ -fsanitize=address -fno-omit-frame-pointer -fsanitize=leak -use-after-free -g 4.cpp -o 4
bash
$ ./4
value:0 value:0 value:0 value:0 value:0 value:0 value:0 value:0 value:0 value:0value:0
=================================================================
==21989==ERROR: AddressSanitizer: global-buffer-overflow on address 0x55e55885b10c at pc 0x55e558659a94 bp 0x7fff8b9bbc00 sp 0x7fff8b9bbbf0
READ of size 4 at 0x55e55885b10c thread T0
#0 0x55e558659a93 in func3() /home/zg/zg_code/zg_test/test/ascan_demo/4.cpp:11
#1 0x55e558659b4b in main /home/zg/zg_code/zg_test/test/ascan_demo/4.cpp:21
#2 0x7f24d7366c86 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21c86)
#3 0x55e558659949 in _start (/home/zg/zg_code/zg_test/test/ascan_demo/4+0x949)
0x55e55885b10c is located 0 bytes to the right of global variable 'g_abc' defined in '4.cpp:5:5' (0x55e55885b0e0) of size 44
SUMMARY: AddressSanitizer: global-buffer-overflow /home/zg/zg_code/zg_test/test/ascan_demo/4.cpp:11 in func3()
Shadow bytes around the buggy address:
检测出第11行有全局缓存溢出
5 内存泄漏
cpp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int func4(void)
{
char * p = (char*) malloc(5);
memset(p,0x0,5);
memcpy(p,"1234",4),
printf("%s\n",p);
}
int main(int argc,char *argv[])
{
func4();
return 0;
}
bash
$ g++ -fsanitize=address -fno-omit-frame-pointer -fsanitize=leak -use-after-free -g 5.cpp -o 5
cpp
$ ./5
1234
=================================================================
==22003==ERROR: LeakSanitizer: detected memory leaks
Direct leak of 5 byte(s) in 1 object(s) allocated from:
#0 0x7f6d980d6b40 in __interceptor_malloc (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xdeb40)
#1 0x55d89de199eb in func4() /home/zg/zg_code/zg_test/test/ascan_demo/5.cpp:7
#2 0x55d89de19a40 in main /home/zg/zg_code/zg_test/test/ascan_demo/5.cpp:15
#3 0x7f6d97c28c86 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21c86)
SUMMARY: AddressSanitizer: 5 byte(s) leaked in 1 allocation(s).
第7行所申请的内存没释放