Home user space slab memory allocator - libumem
Post
Cancel

user space slab memory allocator - libumem

对应github: https://github.com/luochenglcs/libumem

1
2
3
4
reference:
https://arrowpig1979.wordpress.com/2008/08/16/%e4%bd%bf%e7%94%a8libumem%e5%ae%9a%e4%bd%8dmemory-leak%e5%92%8cmemory-corruption%ef%bc%884%ef%bc%89/

https://www.codenong.com/8287649/

一、libumem介绍

libumem是一个运行在用户模式的内存分配程序库,包含在Solaris 9及以后的版本中。libumem不仅能够优化程序的内存分配,而且还提供了内存分配调试和记录的功能,配合mdb工具,可以轻松观察程序内存的分配情况和定位内存泄漏的问题。

libumem使用Slab概念。Slab是Slab Allocator中一个基本内存单元,代表一个或者多个虚拟内存中的页(Page),通常会被分割成为多个大小等同的Chunks,即Buffer。Buffer含有用户所使用的数据,以及一些额外的信息(取决于环境变量的设置)。这些额外的信息对我们调试,检测内存泄漏非常有用。下面就是 Buffer 的一个基本结构:

image-20201110171811756

1
2
3
4
Metadata Section,提供内存分配的长度信息,在32位程序应用中为8个字节。
User Data Section,用户使用的内存区域,存储用户数据。
Redzone Section8个字节,隔离User DataDebug Meta Data
Debug Metadata8个字节。前面四个字节为指针,指向一个umem_bufctl_audit结构,记录内存分配时候的堆栈。此结构的定义可以在/usr/include/umem_impl.h找到。后面的四个字节为校验位,与前面字节一起来判断这个buffer是否被破坏。

https://hosam.wordpress.com/opensolaris-open-source-from-sun-microsystems-inc/

二、libumem的维测特性

1 linux目前的内存调测手段

1
2
3
4
5
6
7
8
1.glibc内存检测
2.valgrind内存检查机制
3、gperftools内存检查机制
4、ASan内存检查机制
5、Memwatch内存检查机制
6、Dr.Memory内存检查机制
9、Electric Fence内存检查机制
8、Dmalloc内存检查机制

2 libumem的内存调测

需要和mdb工具配合,

我们先看下面的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>

void test_leak_malloc(void)
{
        char *p = malloc(50);
        p = malloc(100);
        free(p);
}

void test_UAF(void)
{
        char *p = malloc(50);
        free(p);
        *p = 1;
}

void main(void)
{
        char *p = malloc(50);
        test_leak_malloc();
        test_UAF();
        pause();
        return;
}
gcc -g test.c -o test
UMEM_DEBUG=default, UMEM_LOGGING=transaction LD_PRELOAD=/usr/local/lib/libumem.so.0 ./test&
//使用 man umem_debug查看UMEM_DEBUG、UMEM_LOGGING的含义。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
[root@localhost ~]# mdb -p `pidof test` //使用mdb attach到test进程
loading modules: [ libgcc_s-8-20191121.so.1 libdl-2.28.so libpthread-2.28.so libc-2.28.so libumem.so.0.0.0 ld-2.28.so ]
::findleaks -d
BYTES             LEAKED         VMEM_SEG CALLER
16384                  6     7f3daf3af000 MMAP
4096                   1     7f3db1c40000 MMAP
8192                   1     7f3db1c3c000 MMAP
8192                   1     7f3db1c28000 MMAP
33595392               1     7f3dafa0c000 MMAP
16384                  1     7f3daf771000 MMAP
------------------------------------------------------------------------
           Total       6 oversized leaks, 33648640 bytes

CACHE             LEAKED           BUFCTL CALLER
00007f3db1bba048       1 00007f3db1b3e7e0 main+0x12  //内存泄漏1
00007f3db1bba048       1 00007f3db1b3e8c0 test_leak_malloc+0x12  //内存泄漏2
------------------------------------------------------------------------
           Total       2 buffers, 160 bytes

mmap(2) leak: [7f3daf3af000, 7f3daf3b3000), 16384 bytes
mmap(2) leak: [7f3db1c40000, 7f3db1c41000), 4096 bytes
mmap(2) leak: [7f3db1c3c000, 7f3db1c3e000), 8192 bytes
mmap(2) leak: [7f3db1c28000, 7f3db1c2a000), 8192 bytes
mmap(2) leak: [7f3dafa0c000, 7f3db1a16000), 33595392 bytes
mmap(2) leak: [7f3daf771000, 7f3daf775000), 16384 bytes
umem_alloc_80 leak: 1 buffer, 80 bytes
            ADDR          BUFADDR        TIMESTAMP           THREAD
                            CACHE          LASTLOG         CONTENTS
    7f3db1b3e7e0     7f3db1b6bf60 60116209000b4637      -1312650368
                     7f3db1bba048     7f3db1bf8300                0
                 libumem.so.0.0.0`umem_alloc+0x98
                 libumem.so.0.0.0`malloc+0x39 //泄漏内存的申请流程
                 main+0x12
                 libc-2.28.so`__libc_start_main+0xf3
                 _start+0x2e

umem_alloc_80 leak: 1 buffer, 80 bytes
            ADDR          BUFADDR        TIMESTAMP           THREAD
                            CACHE          LASTLOG         CONTENTS
    7f3db1b3e8c0     7f3db1b6bef0 60116209000b463c      -1312650368
                     7f3db1bba048     7f3db1bf83c0                0
                 libumem.so.0.0.0`umem_alloc+0x98
                 libumem.so.0.0.0`malloc+0x39
                 test_leak_malloc+0x12 //泄漏内存的申请流程
                 main+0x1b
                 libc-2.28.so`__libc_start_main+0xf3
                 _start+0x2e

通过findleaks -d可以查看到内存泄漏的调用栈和信息;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
T-0.000000000  addr=7f3db1b6be80  umem_alloc_80 //test_UAF free addr=7f3db1b6be80
         test_UAF+0x22
         main+0x20
         libc-2.28.so`__libc_start_main+0xf3
         _start+0x2e

T-0.000000005  addr=7f3db1b6be80  umem_alloc_80 //test_UAF malloc(50) addr=7f3db1b6be80 
         libumem.so.0.0.0`umem_alloc+0x98
         libumem.so.0.0.0`malloc+0x39
         test_UAF+0x12
         main+0x20
         libc-2.28.so`__libc_start_main+0xf3
         _start+0x2e

T-0.000000060  addr=7f3db1b6af40  umem_alloc_128 //test_leak_malloc free addr=7f3db1b6af40
         test_leak_malloc+0x30
         main+0x1b
         libc-2.28.so`__libc_start_main+0xf3
         _start+0x2e

T-0.000000067  addr=7f3db1b6af40  umem_alloc_128 //test_leak_malloc malloc(100) addr=7f3db1b6af40
         libumem.so.0.0.0`umem_alloc+0x98
         libumem.so.0.0.0`malloc+0x39
         test_leak_malloc+0x20
         main+0x1b
         libc-2.28.so`__libc_start_main+0xf3
         _start+0x2e
             
T-0.000000182  addr=7f3db1b6bef0  umem_alloc_80 //test_leak_malloc malloc(50) addr=7f3db1b6bef0
         libumem.so.0.0.0`umem_alloc+0x98
         libumem.so.0.0.0`malloc+0x39 
         test_leak_malloc+0x12        
         main+0x1b                    
         libc-2.28.so`__libc_start_main+0xf3
         _start+0x2e                  
                                      
T-0.000000187  addr=7f3db1b6bf60  umem_alloc_80 //main malloc(50) addr=7f3db1b6bf60
         libumem.so.0.0.0`umem_alloc+0x98
         libumem.so.0.0.0`malloc+0x39 
         main+0x12                    
         libc-2.28.so`__libc_start_main+0xf3
         _start+0x2e                  

通过umalog命令可以看到具体分配的细节;

从上面也可以看到有两处申请未释放。

memory corruption的处理;通过memory corruption的有user after free, double free, array bound write…

1
2
3
4
5
6
::umem_verify
Cache Name                      Addr             Cache Integrity     
...
umem_alloc_80                       7f3db1bba048 1 corrupt buffer
umem_alloc_96                       7f3db1bb9048 clean
...
7f3db1bba048::umem_verify
Summary for cache 'umem_alloc_80'
  buffer 7f3db1b6be80 (free) seems corrupted, at 7f3db1b6be90 //这里已经free的7f3db1b6be80地址出现corrupted

通过上面umalog命令可以查看到申请的调用栈:

1
2
3
4
5
6
7
T-0.000000005  addr=7f3db1b6be80  umem_alloc_80 //test_UAF malloc(50) addr=7f3db1b6be80 
         libumem.so.0.0.0`umem_alloc+0x98
         libumem.so.0.0.0`malloc+0x39
         test_UAF+0x12
         main+0x20
         libc-2.28.so`__libc_start_main+0xf3
         _start+0x2e

综合信息可以知道test_UAF中出现use after free的情况;

ps:目前libumem支持调用栈的getstack的代码还没有合入; 后面需要合入

社区代码还有很多待完善的地方。

This post is licensed under CC BY 4.0 by the author.