使用 eBPF检测 mmap泄露

编程入门 行业动态 更新时间:2024-10-25 00:25:46

使用 <a href=https://www.elefans.com/category/jswz/34/1725060.html style=eBPF检测 mmap泄露"/>

使用 eBPF检测 mmap泄露

目录

背景

官网

malloc泄露检测

mmap泄露检测

调用munmap释放内存

小结


背景

我们知道 mmap系统调用申请的内存空间,属于文件映射区域 和 匿名映射区域。这部分区域并不属于 heap,所以用一般的内存泄露检测工具是检测不出来的。例如:一般常用的内存泄露检测工具 vagrind、ASAN、malloc_debug等。关于ASAN的介绍,可以参考:ASAN入门参考-CSDN博客

官网

.py

可以看到,基于eBPF的BCC工具是支持以下内存申请接口,进行内存泄露检测的。

        attach_probes("malloc")attach_probes("calloc")attach_probes("realloc")attach_probes("mmap")attach_probes("posix_memalign")attach_probes("valloc", can_fail=True) # failed on Android, is deprecated in libc.so from bionic directoryattach_probes("memalign")attach_probes("pvalloc", can_fail=True) # failed on Android, is deprecated in libc.so from bionic directoryattach_probes("aligned_alloc", can_fail=True)  # added in C11

我们先来看看最常见的 malloc 的检测。

malloc泄露检测

test.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>void allocate_mmap_memory()
{int *p=mmap(NULL,//系统指定首地址getpagesize(),//一个页(基本单位)PROT_READ|PROT_WRITE,MAP_ANONYMOUS|MAP_SHARED,//匿名映射0,0);//可以在这一页里随便折腾printf("mmap address p : %p\n",p);*p=20;*(p+1)=30;*(p+2)=40;munmap(p,4096);//释放内存
}void a()
{int* p = malloc(5);printf("malloc address p : %p\n",p);//allocate_mmap_memory();//free(p);
}void b()
{a();
}void c()
{b();
}int main(int argc,char* argv[])
{while(1){sleep(15);c();}return 0;
}

编译运行:

wj@wj:~/linux$ gcc test.c -o test.out
wj@wj:~/linux$ ./test.out 
malloc address p : 0x561051d3a2a0
malloc address p : 0x561051d3a6d0
malloc address p : 0x561051d3a6f0
malloc address p : 0x561051d3a710
^C

wj@wj:~/linux$ ps -ef | grep test
kernoops    1078       1  0 19:33 ?        00:00:00 /usr/sbin/kerneloops --test
wj          4861    2537  0 21:52 pts/0    00:00:00 ./test.out
wj          4863    3794  0 21:52 pts/2    00:00:00 grep --color=auto test

sudo python3 memleak -a -p 4861
# -a 表示显示每个内存分配请求的大小以及地址
# -p 指定案例应用的 PID 号

wj@wj:/usr/share/bcc/tools$ sudo python3 memleak -a -p 4861
[sudo] wj 的密码: 
Attaching to pid 4861, Ctrl+C to quit.
[21:52:46] Top 10 stacks with outstanding allocations:
[21:52:51] Top 10 stacks with outstanding allocations:
[21:52:56] Top 10 stacks with outstanding allocations:addr = 561051d3a6f0 size = 55 bytes in 1 allocations from stack0x0000561051aec28e	a+0x16 [test.out]0x0000561051aec2c2	b+0x12 [test.out]0x0000561051aec2d7	c+0x12 [test.out]0x0000561051aec301	main+0x27 [test.out]0x00007fa2fc829d90	__libc_start_call_main+0x80 [libc.so.6]
[21:53:01] Top 10 stacks with outstanding allocations:addr = 561051d3a6f0 size = 55 bytes in 1 allocations from stack0x0000561051aec28e	a+0x16 [test.out]0x0000561051aec2c2	b+0x12 [test.out]0x0000561051aec2d7	c+0x12 [test.out]0x0000561051aec301	main+0x27 [test.out]0x00007fa2fc829d90	__libc_start_call_main+0x80 [libc.so.6]
[21:53:06] Top 10 stacks with outstanding allocations:addr = 561051d3a6f0 size = 55 bytes in 1 allocations from stack0x0000561051aec28e	a+0x16 [test.out]0x0000561051aec2c2	b+0x12 [test.out]0x0000561051aec2d7	c+0x12 [test.out]0x0000561051aec301	main+0x27 [test.out]0x00007fa2fc829d90	__libc_start_call_main+0x80 [libc.so.6]
[21:53:11] Top 10 stacks with outstanding allocations:addr = 561051d3a6f0 size = 5addr = 561051d3a710 size = 510 bytes in 2 allocations from stack0x0000561051aec28e	a+0x16 [test.out]0x0000561051aec2c2	b+0x12 [test.out]0x0000561051aec2d7	c+0x12 [test.out]0x0000561051aec301	main+0x27 [test.out]0x00007fa2fc829d90	__libc_start_call_main+0x80 [libc.so.6]
[21:53:16] Top 10 stacks with outstanding allocations:addr = 561051d3a6f0 size = 5addr = 561051d3a710 size = 510 bytes in 2 allocations from stack0x0000561051aec28e	a+0x16 [test.out]0x0000561051aec2c2	b+0x12 [test.out]0x0000561051aec2d7	c+0x12 [test.out]0x0000561051aec301	main+0x27 [test.out]0x00007fa2fc829d90	__libc_start_call_main+0x80 [libc.so.6]
[21:53:21] Top 10 stacks with outstanding allocations:addr = 561051d3a6f0 size = 5addr = 561051d3a710 size = 510 bytes in 2 allocations from stack0x0000561051aec28e	a+0x16 [test.out]0x0000561051aec2c2	b+0x12 [test.out]0x0000561051aec2d7	c+0x12 [test.out]0x0000561051aec301	main+0x27 [test.out]0x00007fa2fc829d90	__libc_start_call_main+0x80 [libc.so.6]

从 memleak 的输出可以看到,案例应用在不停地分配内存,并且这些分配的地址没有被回收。

test.c  加上释放函数。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>void allocate_mmap_memory()
{int *p=mmap(NULL,//系统指定首地址getpagesize(),//一个页(基本单位)PROT_READ|PROT_WRITE,MAP_ANONYMOUS|MAP_SHARED,//匿名映射0,0);//可以在这一页里随便折腾printf("mmap address p : %p\n",p);*p=20;*(p+1)=30;*(p+2)=40;munmap(p,4096);//释放内存
}void a()
{int* p = malloc(5);printf("malloc address p : %p\n",p);//allocate_mmap_memory();free(p);
}void b()
{a();
}void c()
{b();
}int main(int argc,char* argv[])
{while(1){sleep(15);c();}return 0;
}

再次检测。

wj@wj:~/linux$ gcc test.c -o test.out
wj@wj:~/linux$ ./test.out 
malloc address p : 0x558bfb5142a0
malloc address p : 0x558bfb5142a0
malloc address p : 0x558bfb5142a0
malloc address p : 0x558bfb5142a0
^C

wj@wj:~/linux$ ps -ef | grep test
kernoops    1078       1  0 19:33 ?        00:00:00 /usr/sbin/kerneloops --test
wj          5018    2537  0 22:07 pts/0    00:00:00 ./test.out
wj          5029    3794  0 22:08 pts/2    00:00:00 grep --color=auto test
wj@wj:~/linux$ 

wj@wj:/usr/share/bcc/tools$ sudo python3 memleak -a -p 5018
Attaching to pid 5018, Ctrl+C to quit.
[22:08:09] Top 10 stacks with outstanding allocations:
[22:08:14] Top 10 stacks with outstanding allocations:
[22:08:19] Top 10 stacks with outstanding allocations:
[22:08:24] Top 10 stacks with outstanding allocations:
[22:08:29] Top 10 stacks with outstanding allocations:
[22:08:34] Top 10 stacks with outstanding allocations:
[22:08:39] Top 10 stacks with outstanding allocations:
[22:08:44] Top 10 stacks with outstanding allocations:
^Cwj@wj:/usr/share/bcc/tools$ 

现在,我们看到,案例应用已经没有遗留内存,证明我们的修复工作成功完成。

mmap泄露检测

test.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>void allocate_mmap_memory()
{int *p=mmap(NULL,//系统指定首地址getpagesize(),//一个页(基本单位)PROT_READ|PROT_WRITE,MAP_ANONYMOUS|MAP_SHARED,//匿名映射0,0);//可以在这一页里随便折腾printf("mmap address p : %p\n",p);*p=20;*(p+1)=30;*(p+2)=40;munmap(p,4096);//释放内存
}void a()
{//int* p = malloc(5);//printf("malloc address p : %p\n",p);allocate_mmap_memory();//free(p);
}void b()
{a();
}void c()
{b();
}int main(int argc,char* argv[])
{while(1){sleep(15);c();}return 0;
}

编译运行:

wj@wj:~/linux$ gcc test.c -o test.out
wj@wj:~/linux$ ./test.out 
mmap address p : 0x7fd503547000
mmap address p : 0x7fd50350d000
^C
wj@wj:~/linux$ 

wj@wj:~/linux$ ps -ef | grep test
kernoops    1078       1  0 19:33 ?        00:00:00 /usr/sbin/kerneloops --test
wj          5100    2537  0 22:15 pts/0    00:00:00 ./test.out
wj          5105    3794  0 22:15 pts/2    00:00:00 grep --color=auto test
wj@wj:~/linux$ 

wj@wj:/usr/share/bcc/tools$ sudo python3 memleak -a -p 5100
Attaching to pid 5100, Ctrl+C to quit.
[22:15:52] Top 10 stacks with outstanding allocations:addr = 55fbc12f22a0 size = 1024addr = 7fd503547000 size = 40961024 bytes in 1 allocations from stack0x00007fd50327eba4	__GI__IO_file_doallocate+0x94 [libc.so.6]4096 bytes in 1 allocations from stack0x000055fbc0d581df	allocate_mmap_memory+0x36 [test.out]0x000055fbc0d58239	a+0x12 [test.out]0x000055fbc0d5824e	b+0x12 [test.out]0x000055fbc0d58263	c+0x12 [test.out]0x000055fbc0d5828d	main+0x27 [test.out]0x00007fd503229d90	__libc_start_call_main+0x80 [libc.so.6]
[22:15:57] Top 10 stacks with outstanding allocations:addr = 55fbc12f22a0 size = 1024addr = 7fd503547000 size = 40961024 bytes in 1 allocations from stack0x00007fd50327eba4	__GI__IO_file_doallocate+0x94 [libc.so.6]4096 bytes in 1 allocations from stack0x000055fbc0d581df	allocate_mmap_memory+0x36 [test.out]0x000055fbc0d58239	a+0x12 [test.out]0x000055fbc0d5824e	b+0x12 [test.out]0x000055fbc0d58263	c+0x12 [test.out]0x000055fbc0d5828d	main+0x27 [test.out]0x00007fd503229d90	__libc_start_call_main+0x80 [libc.so.6]
[22:16:02] Top 10 stacks with outstanding allocations:addr = 55fbc12f22a0 size = 1024addr = 7fd503547000 size = 40961024 bytes in 1 allocations from stack0x00007fd50327eba4	__GI__IO_file_doallocate+0x94 [libc.so.6]4096 bytes in 1 allocations from stack0x000055fbc0d581df	allocate_mmap_memory+0x36 [test.out]0x000055fbc0d58239	a+0x12 [test.out]0x000055fbc0d5824e	b+0x12 [test.out]0x000055fbc0d58263	c+0x12 [test.out]0x000055fbc0d5828d	main+0x27 [test.out]0x00007fd503229d90	__libc_start_call_main+0x80 [libc.so.6]
[22:16:07] Top 10 stacks with outstanding allocations:addr = 55fbc12f22a0 size = 1024addr = 7fd503547000 size = 4096addr = 7fd50350d000 size = 40961024 bytes in 1 allocations from stack0x00007fd50327eba4	__GI__IO_file_doallocate+0x94 [libc.so.6]8192 bytes in 2 allocations from stack0x000055fbc0d581df	allocate_mmap_memory+0x36 [test.out]0x000055fbc0d58239	a+0x12 [test.out]0x000055fbc0d5824e	b+0x12 [test.out]0x000055fbc0d58263	c+0x12 [test.out]0x000055fbc0d5828d	main+0x27 [test.out]0x00007fd503229d90	__libc_start_call_main+0x80 [libc.so.6]

从 memleak 的输出可以看到,案例应用在不停地分配内存,并且这些分配的地址没有被回收。

调用munmap释放内存

test.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>void allocate_mmap_memory()
{int *p=mmap(NULL,//系统指定首地址getpagesize(),//一个页(基本单位)PROT_READ|PROT_WRITE,MAP_ANONYMOUS|MAP_SHARED,//匿名映射0,0);//可以在这一页里随便折腾printf("mmap address p : %p\n",p);*p=20;*(p+1)=30;*(p+2)=40;munmap(p,4096);//释放内存
}void a()
{//int* p = malloc(5);//printf("malloc address p : %p\n",p);allocate_mmap_memory();//free(p);
}void b()
{a();
}void c()
{b();
}int main(int argc,char* argv[])
{while(1){sleep(15);c();}return 0;
}

编译运行:

wj@wj:~/linux$ gcc test.c -o test.out
wj@wj:~/linux$ ./test.out 
mmap address p : 0x7f4e82632000
mmap address p : 0x7f4e82632000
^C
wj@wj:~/linux$ 

wj@wj:~/linux$ ps -ef | grep test
kernoops    1078       1  0 19:33 ?        00:00:00 /usr/sbin/kerneloops --test
wj          5467    2537  0 22:24 pts/0    00:00:00 ./test.out
wj          5470    3794  0 22:24 pts/2    00:00:00 grep --color=auto test
wj@wj:~/linux$ 

wj@wj:/usr/share/bcc/tools$ sudo python3 memleak -a -p 5467
Attaching to pid 5467, Ctrl+C to quit.
[22:25:09] Top 10 stacks with outstanding allocations:
[22:25:14] Top 10 stacks with outstanding allocations:
[22:25:19] Top 10 stacks with outstanding allocations:
[22:25:24] Top 10 stacks with outstanding allocations:
[22:25:29] Top 10 stacks with outstanding allocations:

现在,我们看到,案例应用已经没有遗留内存,证明我们的修复工作成功完成。

小结

如果工作中遇到了mmap相关的泄露,考虑一下 eBPF或许是个不错的选择。

更多推荐

使用 eBPF检测 mmap泄露

本文发布于:2023-11-15 07:48:41,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1596191.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:eBPF   mmap

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!