对漏洞CVE-2018-18281的理解
对漏洞CVE-2018-18281的理解
一种分离原子操作导致的漏洞,理解一个应该就会能理解这一类的漏洞了
#程序局部性原理:
程序在执行时呈现出局部性规律,即在一段时间内,整个程序的执行仅限于程序中的某一部分。相应地,执行所访问的存储空间也局限于某个内存区域。
有了这个原理,就有了多级页表机制:
通过地址映射,将连续的数据映射到离散的页上。
多级页表让所有程序只将当时需要的程序和数据等存放在内存,这样不必将全部的程序和数据放入内存,减少了不必要的内存开销。
#TLB:
TLB是作为加速多级页表查询的存在,因为多级页表在内存中存储,多次映射会增加时间开销,而TLB表是寄存器存储,比访问内存速度更快,可以将访问更加频繁的页表存入TLB,在以后访问中会先访问TLB,或者同时访问TLB和页表。
以上内容是产生漏洞的基础知识,然后介绍一下漏洞。
两个系统调用,
- mremap 系统调用用来改变虚拟内存的映射区域
- ftruncate 系统调用用来改变文件的大小到指定大小
简单来说这两个函数都可以修改页表并释放相应内存,并在修改完成后释放相应的TLB表。而存在的问题是在修改页表释放内存后,其他程序可以抢占cpu,将延迟TLB表的释放,导致内存的复用。
mremap 底层实现主要是 move_ptes 函数
可以看到函数将pmd中的每一项pte复制到了新的pmd中,而没有将对应的页删除,而old_pmd对应的TLB表的释放是在这个函数完成之后,所以如果一直不执行后续的TLB表的释放,就可以一直拥有这块内存的读写权限。
ftruncate 函数将文件大小变为指定的大小, 如果新的值比旧的值小, 则需要将文件在内存的虚存空间变小, 这需要调用到 zap_pte_range 函数
将上述两个函数的流程放到一起分析, 假设下面这种情况:
1.文件A映射到内存中
2.调用mremap ,更换pmd地址
3.在清空TLB前,调用ftruncate ,将文件 A 的文件大小改为 0(即将全部内存释放)
4.此时内存已经全部释放,但mremap 还没将之前的TLB清空,如果一直不让这一步程序执行,那么TLB将一直指向之前A所映射的内存地址,并拥有读写权限。
5.如果此时加载有高级权限的系统函数库到被映射的内存地址,然后通过TLB表改写内存,然后调用系统函数,就可以完成攻击。
漏洞的复现还没有完成。(不会Android)
参考:
http://jiayy.me/2019/02/15/CVE-2018-18281/
https://bugs.chromium.org/p/project-zero/issues/detail?id=1695