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

在这里插入图片描述
敬告:
《中华人民共和国刑法》第三百八十六条【破坏计算机系统罪;网络服务渎职罪】违反国家规定,对计算机信息系统功能进行删除、修改、增加、干扰,造成计算机系统不能正常运行,后果严重的,处五年以下有期徒刑或者拘役;后果特别严重的,处五年以上有期徒刑。
违反国家规定,对计算机系统中存储、处理或者传输的数据和应用程序进行删除、修改、增加的操作,后果严重的,依照前款规定处罚。
故意制作、传播计算机病毒等破坏性程序,影响计算机系统正常运行,后严重的,依照第一款规定处罚。
单位犯前三款罪的,对单位判处罚金,对其直接负责的主管人员和其他直接负责人员,依照第一款的规定处罚。

声明:本文仅供开发者与信息安全从业者学习参考,请遵守行业道德底线。

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

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

更新日期:
2022年1月29日
2022年1月26日


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 |             |                        | 
 | +-----------+             +------------------------+
 | |  CHUNK  2 |            
 | +-----------+         
 | |  CHUNK  3 |
 | +-----------+
 | |  CHUNK  4 | 
 | +-----------+
 | |  CHUNK  5 |
 | +-----------+
 | |  CHUNK  6 |
 | +-----------+
 | |    TOP    |
 | |           |
 V |           |
   +-----------+
--- WILDERNESS ---

我们释放CHUNK4,接着释放CHUNK2

+---HEAP GROWS UPWARDS
 |                            Bins
 | +-+-+-+-+-+-+             +------------------------+
 | |  CHUNK  1 |             | ADDRESS OF FREESPACE 4 | (1)free
 | +-----------+             +------------------------+
 | |FREESPACE 2 | (2)free     | ADDRESS OF FREESPACE 2 | (2)free
 | +-----------+             +------------------------+
 | |  CHUNK  3 |
 | +-----------+
 | |FREESPACE 4 | (1)free
 | +-----------+
 | |  CHUNK  5 |
 | +-----------+
 | |  CHUNK  6 |
 | +-----------+
 | |    TOP    |
 | |           |
 V |           |
   +-----------+
--- WILDERNESS ---

FREECHUNK4FREECHUNK2被合成FREECHUNK2

 +---HEAP GROWS UPWARDS
 |                            Bins
 | +-+-+-+-+-+-+             +------------------------+
 | |  CHUNK  1 |             | ADDRESS OF FREECHUNK 2 | 
 | +-----------+             +------------------------+
 | |FREECHUNK 2|
 | |           |  
 | |           |
 | |           |
 | |           | 
 | +-----------+
 | |  CHUNK  5 |
 | +-----------+
 | |  CHUNK  6 |
 | +-----------+
 | |    TOP    |
 | |           |
 V |           |
   +-----------+
--- WILDERNESS ---

当一个Chunk被释放后,in-use位被设置为0,程序会检查上一个或者下一个是否存在空闲空间,Bins会把空余空间合并。

Fastbins

Fastbins在源码中最大大小是这么定义的

#define MAX_FAST_SIZE (80 * SIZE_SZ / 4)

SIZE_SZ 在64位系统上是8bit,在32位系统上是4bit.MAX_FAST_SIZE在32位和64位系统上分别大小是160bytes80bytes
这就意味着小于MAX_FAST_SIZE的FREE CHUNK会被回收到Fastbins数组中
目前遇到一个棘手的问题,fastbin是一个释放小chunk的列表数组Fastbins] is an array of lists holding recently freed small chunks。单链接存储在“LIFO”中。

分割线:2022年1月29日,更新2022年1月26日,更新2022年2月6日

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

IT鹅

您的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值