0x00 基础知识们 之前写完操作系统,再来看ret2dir果然一片明朗,相比于之前对于映射机制方面的欠缺,这里明显更加得心应手 1.Linux内存管理 首先Linux的内存管理大致会分为Buddy System 和 Slub算法两种,这里由于我寻找的是一篇古早的分析,所以可能会有些许欠缺,但是目前学习该同样很早的漏洞利用手法已经足够,比较详细且时间较近的分析我推荐arttnba3师傅的个人博客
【OS.0x02】Linux 内核内存管理I - 页、区、节点 - arttnba3's blog
1.Buddy System(伙伴系统) 分配单元为页,且该系统的初衷就是为了缓解内存碎片化的问题,这里由于还没涉及到很多,所以仅仅知道他是分配页框的即可 2.Slub算法 上面我们知道Buddy System是以页面为单位来分配的,因此当我们程序需要分配几十字节大小该怎么办呢?总不能不管什么都分配几个页框吧,因此就有了该slub 算法的由来 这里介绍一下大致结构,首先就是一个统筹全局的数组kmalloc_caches[12] , 他是一个kmem_cache 元素类型的数组,里面包含了12个kmem_cache 类型,而这个kmem_cache 里面包含着的就是一些待分配的内存块信息,这里我们kmalloc_caches[12] 里面的不同的kmem_cahce 自身所担当的职能是不同的,例如该数组中的一个kmem_cache 类型只会包揽一种大小内存块的信息,因此我们的Slub算法总共是可以分配12种大小不同的内存块,分别是:
2^3, 2^4, 2^5, 2^6, ... , 2^11, 96, 192字节
然后每个kmem_cache 里面又保存着当前分配器的类型以及分配情况,其中比较重要的是node 和cpu_slab ,他俩的类型分别是kmem_cache_node 和kmem_cache_cpu ,这两个的作用也有所不同,首先我们了解一个知识点,那就是分配器会首先申请一整页的内存,然后该内存就是一个slab ,当分配器获取该slab 后再从中切割小块分给用户 然后剩下的信息我们到具体分配过程中了解
- 首先是最初创建slub的时候:
系统中不存在任何slab 供我们使用,所以此时我们会向buddy system 中申请一个页框来存放我们的初试slab ,然后我们根据需求的块大小找到kmalloc_cahces 中适配的分配器,将我们获取到的slab 提供给他,注意这里我们会将该slab 分配给kmem_cache_cpu 下,且该字段下也只会指向一个slab 这点得注意,下面就是过程图: 这里可以看到有一个页框是链接到kmem_cache_cpu 下的page 字段,该字段指向的就是分配slab 的页框地址,然后我们也会将第一个块标记为已分配并且返还回去,然后剩下的空间我们会将其分割成一个个空闲块组成的链表,该链表的地址也会分配给kmem_cache_cpu 下的free_list 字段,然后如果我们该页框上面有空闲块的话,那么我们每次就将其标记为已分配然后unlink空闲链表返还分配地址就可以了
- 然后如果我们的
kmem_cache_cpu 分配满了并且kmem_cache_node 中有包含空闲块的slab 的时候,就会将其替换,然后把塞满的块接入到kmem_cache_node 中的full 双链表下 然后再切换之后返还一个空白块就可以了
- 如果我们此时
kmem_cache_cpu 指向的页也满了,然后kmem_cache_node 也没有空闲的块,那么此时我们就会重新向buddy system 申请一个新的页加入kmem_cache_cpu 当中,然后将满的块移入kmem_cache_node ,如下: 然后就是重新获取
- 上面讲完了分配的过程,下面我们来讲述释放的过程,这里我们的操作就主要是在
kmem_cache_node 中了,第一种情况那就是我们要释放的块在kmem_cache_node 中的full 双链表下: 此时我们直接将该块标记为空闲,然后将其加入partial 双链表当中
- 而如果我们释放的块是在
kmem_cache_node 中的partial 双链表当中或者说是在kmem_cache_cpu 的page 当中,我们直接释放然后加入空闲队列就行了,这里我直接按照上图的结果来展示释放后的状态
- 最后一种情况就是我们所释放的该块是该
slab 中最后一个块,那么此时我们释放该块后然后再归还整个slab 给buddy system 即可,这里就不画图辣。
2.ret2dir原理 ret2dir的存在是为了解决SMAP/SMEP保护模式的一种手法,该保护模式是阻止了内核程序执行用户程序,第一次被提出是在14年的一篇论文,这里页给出链接 ret2dir原论文 首先我们得知道一下Linux内存中的基本布局,链接如下,有兴趣的同学可以自行观看 Linux 内存布局 我们可以看到有以下一个区域 复制代码 隐藏代码
========================================================================================================================
Start addr | Offset | End addr | Size | VM area description
========================================================================================================================
| | | |
0000000000000000 | 0 | 00007fffffffffff | 128 TB | user-space virtual memory, different per mm
__________________|____________|__________________|_________|___________________________________________________________
| | | |
0000800000000000 | +128 TB | ffff7fffffffffff | ~16M TB | ... huge, almost |