精读《glibc内存管理ptmalloc源代码分析》

前言:最近在学unlink和各种堆相关的攻击技巧
但是因为对堆的分配啥的不怎么熟悉,导致很头疼
这次来好好学习下,而且这也是Atum大佬的推荐阅读。

32位内存布局

1
可以看到总共4G内存,最上面1个G是内核空间的。
从上往下就是1G内核,栈,mmap映射,堆区,bss段,data段和text段。
堆和mmap映射区域相对增长,还有就是栈有个最大限制。

64位内存布局

2
因为在64位下有足够的内存空间。mmap和栈就相对增长了。
堆区因为空间足够,不太可能会往上覆盖到mmap映射区,至于其他,和32位差不多。

Chunk

3
用户所请求的空间在ptmalloc都会用一个Chunk表示。
可以看到上图是一个没有被free的Chunk
第一个是前一个(空闲)Chunk的大小
第二个是当前Chunk的大小,第三位代表了不同的意思
这边主要看P位,P位表示前一个chunk是否在使用
如果是1则在,那么第一个表示前一个chunk大小的四字节就无效。
如果为0,则表示前一个chunk空闲,这时表示的size就有效了。
第一个分配的chunk的p位总是为1.
4
上图是一个被free后的chunk
可以看到M位不存在。
还有就是多了4个指针(看情况)
一个是fd,指向后一个空闲的chunk
还有就是bd,指向前一个空闲的chunk
下面还有俩个分别代表大小
但是这只有large bin才会有。
一般都是2个指针。
还可以看到,下一个chunk的previous size没了
其实这是因为它正在使用中,那四个字节本来就没有用,就可以直接给上一个chunk申请的空间了。
这便是chunk的空间复用。

chunk空间复用

可以看到当chunk空闲时,至少需要16个字节空间来放那四个指针。
在使用时呢,首先有俩个指针8字节,再加上自己申请的,再减去4字节,为什么要减去4字节,其实是因为占用了下一个chunk的previous size的那四个字节。
所以此时chunk空间大小为
in_use_size = (用户请求大小+ 8 - 4 ) align to 8B
综上可以看出,chunk的大小为max(in_use_size, 16)。
这就是用户请求分配时,ptmalloc实际分配的大小。

bins

5
ptmalloc会统一管理被用户free掉的chunk,如上图所示。
一共维护了128个bin,并用数组来存储。
bin中的chunk被双向链表链接。
可以看到第一个为unsorted bin
然后就是small bins
small bins每个之间相差8字节。
里面的chunk被双向链表链接,其中用户申请时,small bins都是从尾补开始的,
而用户释放的都被连到了链表头部。
还有一个就是large bins,没什么好说的。
当空闲的chunk被链接到bin中的时候,都会把这chunk下一个的P位置为0,以表示前一个空闲。
他还会检查次chunk前一个chunk是否空闲,如果是则会合并俩个chunk,并把它放到unsorted bin中。
当然不是所有都会放到unsorted bin中,还会根据大小选择是否放入fast bins

fast bins

当大小小于64字节的chunk被释放后首先会放入fast bins中,在此时其下一个P位不会被置0.
以便快速分配。当需要给用户分配的大小小于64字节时,ptmalloc会先在fast bins中寻找,
如果没有则将相邻的chunk合并后放入unsorted bin,再在unsorted bin中寻找。

unsorted bin

当用户释放的chunk大于64字节或者fast bins中的chunk合并后,都会放进unsorted bin中。当fast bins中找不到用户所需求的chunk时,
ptmalloc则会寻找unsorted bin,如果没有,再将unsorted bin中的chunk放进bins中,再在bins中寻找。

说到底,fast bins 和 unsorted bin其实就是为了提高分配速度而存在的。

//todo

文章目录
  1. 1. 32位内存布局
  2. 2. 64位内存布局
  3. 3. Chunk
  4. 4. chunk空间复用
  5. 5. bins
    1. 5.1. fast bins
    2. 5.2. unsorted bin
|