二进制安全:ptmalloc内存管理机制与堆块chunk源码分析

Posted 鸿渐之翼

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了二进制安全:ptmalloc内存管理机制与堆块chunk源码分析相关的知识,希望对你有一定的参考价值。

声明:本文仅供开发者与信息安全从业者学习参考,请遵守行业道德底线。
底层安全垃圾小废物请指教,嘤嘤嘤。


作者:深圳市狩猎者网络安全技术有限公司-知柯信息安全团队-hongsofwing
本文参考:glibc内存管理ptmalloc源代码分析 华庭(庄明强)2011/4/17
本文源代码使用glibc-2.15 source code 下载地址直达glibc-2.15
参考阅读:Heap overflow堆溢出(一)

这是一篇结合了malloc.c源代码分析的文章,也许部分读者朋友会认为这篇文章在炒冷饭,我不是炒冷饭!本文是我学习heap的笔记,本文包括了堆溢出的基本概念。

Ptmalloc内存管理概述:

简介:

ptmalloc 实现了 malloc(),free()以及一组其它的函数. 以提供动态内存管理的支持。分配器处在用户程序和内核之间,它响应用户的分配请求,向操作系统申请内存,然后将其返回给用户程序,为了保持高效的分配,分配器一般都会预先分配一块大于用户请求的内存, 并通过某种算法管理这块内存。

堆是一个结构,可以对不同的内存进行管理,下面是Linux系统中的堆,堆的增长是从小到大。

+--- Heap grows to bigger positions
 |
 | +-+-+-+-+-+-+ 0x00000000
 V |   CODE    |
   +-----------+
   |   HEAP    |
   |           |
   +-----------+
   |           | A
   |           | |
   +-----------+ +---- Stack grows to lower positions
   |   STACK   |
   +-----------+ 0xFFFFFFFF

Malloc Chunk 堆块分析

想必我们都看过这张图片:malloc chunk

/malloc/malloc.c中1072行代码注释有上图的源码
malloc.c关于chunk声明的C源码

struct malloc_chunk 

  INTERNAL_SIZE_T      mchunk_prev_size;  /* Size of previous chunk (if free).  */
  INTERNAL_SIZE_T      mchunk_size;       /* Size in bytes, including overhead. */

  struct malloc_chunk* fd;         /* double links -- used only if free. */
  struct malloc_chunk* bk;

  /* Only used for large blocks: pointer to next larger size.  */
  struct malloc_chunk* fd_nextsize; /* double links -- used only if free. */
  struct malloc_chunk* bk_nextsize;
;

以上程序中在定义了mchunk_prev_size域,mchunk_size域,fd,bk
fd_nextsize,bk_nextsize

各个域的作用
指针FD与BK只有当CHUNK块空闲时存在,如下图所示,FD指针指向下一个CHUNK头部Prev_size,BK指向上一个CHUNK的Prev_size

FreeChunk过程

实现FreeChunk是通过双链表完成的如下图所示

CHUNK在FREE之前的结构

    chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
	    |             Size of previous chunk, if unallocated (P clear)  |
	    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
	    |             Size of chunk, in bytes                     |A|M|P|
      mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
	    |             User data starts here...                          .
	    .                                                               .
	    .             (malloc_usable_size() bytes)                      .
	    .                                                               |
nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
	    |             (size of chunk, but used for application data)    |
	    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
	    |             Size of next chunk, in bytes                |A|0|1|
	    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

CHUNK在FREE之后的结构:

chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
	    |             Size of previous chunk, if unallocated (P clear)  |
	    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    `head:' |             Size of chunk, in bytes                     |A|0|P|
      mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
	    |             Forward pointer to next chunk in list             |
	    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
	    |             Back pointer to previous chunk in list            |
	    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
	    |             Unused space (may be 0 bytes long)                .
	    .                                                               .
	    .                                                               |
nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    `foot:' |             Size of chunk, in bytes                           |
	    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
	    |             Size of next chunk, in bytes                |A|0|0|
	    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

关于Arena

ptmalloc2 的实现中,Arena 是程序存储每线程堆 per-thread heaps的地方。 理想情况下,人们会认为每个线程都应该有自己的 Arena,每一个Arena需要几个堆,例如具有大量多线程的 Apache Web Server就无法使用它。

static struct malloc_par mp_ =

  .top_pad = DEFAULT_TOP_PAD,
  .n_mmaps_max = DEFAULT_MMAP_MAX,
  .mmap_threshold = DEFAULT_MMAP_THRESHOLD,
  .trim_threshold = DEFAULT_TRIM_THRESHOLD,
#define NARENAS_FROM_NCORES(n) ((n) * (sizeof (long) == 4 ? 2 : 8))
  .arena_test = NARENAS_FROM_NCORES (1)
;

malloc/malloc.c:1750

#define NARENAS_FROM_NCORES(n) ((n) * (sizeof (long) == 4 ? 2 : 8))

malloc/arena.c:906

int n = __get_nprocs ();

 if (n >= 1)
 narenas_limit = NARENAS_FROM_NCORES (n);
 else
 /* We have no information about the system. Assume two
 cores. */
 narenas_limit = NARENAS_FROM_NCORES (2);

关于Top:

在malloc
当我们在分配Heap的时候,TOP始终位于顶部。TOP的大小取决于Arena的空间大小。当我们首次调用Heap的时候,TOP为0。TOP会存在Heap的分配内存中,如下是它的分配结构代码:

+---HEAP GROWS UPWARDS
 |
 | +-+-+-+-+-+-+
 | |  MALLOC 1 |
 | +-----------+
 | |  MALLOC 2 |
 | +-----------+
 | |  MALLOC 3 |
 | +-----------+
 | |    TOP    |
 | |           |
 V |           |
   +-----------+
--- WILDERNESS ---

关于Bins:

Bins结构:

 +---HEAP GROWS UPWARDS
 |                            Bins
 | +-+-+-+-+-+-+             +------------------------+
 | |  CHUNK  1 |             |                        | 
 | +-----------+             +------------------------+
 | |  CHUNK  2 |            
 | +-----------+         
 | |  CHUNK  3 |
 | +-----------+
 | |  CHUNK  4 | 
 | +-----------+
 | |  CHUNK  5 |
 | +-----------+
 | |  CHUNK  6 |
 | +-----------+
 | |    TOP    |
 | |           |
 V |           |
   +-----------+
--- WILDERNESS ---

Bins是内存中的双链表结构,bins用于跟踪被FREE的CHUNK。当一个CHUNK被释放后,它会被放入Bins数组中。
这里有128个Bins,一个unsorted chunks bin与剩下的127个Bins。
这127个Bins由21个small chunk和96个Bins组成

1(Unsorted) + 96(Small chunks) + 31(Large chunks) = 128(Bins).

Small Chunk与Chunk的区别

这里我们又会有疑问smallchunk和 普通chunk的区别是什么?
在这里把Chunk分为Small ChunkLarge Chunk
它们最大的不同在于当chunk被释放(free)时bins回收大小不一样。
Small Chunk会把相同大小的Free chunk储存在bins中。
在以下案例中,我们分配6个相同大小的CHUNK

+---HEAP GROWS UPWARDS
 |                            Bins
 | +-+-+-+-+-+-+             +------------------------+
 | |  CHUNK  1 |             |                        | 
 | +以上是关于二进制安全:ptmalloc内存管理机制与堆块chunk源码分析的主要内容,如果未能解决你的问题,请参考以下文章

ptmalloc机制

Linux 内核内存布局与堆管理

百度工程师带你探秘C++内存管理(ptmalloc篇)

百度工程师带你探秘C++内存管理(ptmalloc篇)

Linux glibc内存管理:用户态内存分配器——ptmalloc实现原理

Linux 内核 内存管理内存管理架构 ② ( 用户空间内存管理 | malloc | ptmalloc | 内核空间内存管理 | sys_brk | sys_mmap | sys_munmap)