解读 Meltdown & Spectre CPU 漏洞

Intel (及其他厂商)的芯片最近被爆的漏洞 Meltdown 和 Spectre 最近已经甚嚣尘上, 也有多人邀请我回答知乎上的相关问题,今天终于静下心来把 Meltdown 和 Spectre 以及相关的几篇论文读了,在专栏总结一下,争取让没有体系结构知识的读者也能读懂。


计算机操作系统有一个最基本的安全目标:保证用户程序不能任意访问内核/其他用户程序的内存。一旦某个恶意应用可以任意访问其他应用程序/操作系统的内存,那么后果则不堪设想。


为了实现这个目标,操作系统和计算机硬件(CPU)采取了以下措施:

  • 操作系统:通过虚拟内存为每个应用程序和内核开辟独立的地址空间,规定相应的访问权限。
  • CPU:通过硬件实现支持虚拟内存(TLB)及其相应的访问权限。

举例来讲,如果有一个用户程序试图访问一个内核的内存地址,那么在CPU执行相应指令的过程中会探测到没有访问权限,进而触发中断/异常,导致程序终结。


所以一般情况下,除非恶意程序通过软件漏洞提权获得了内核权限,否则是无论如何也绕不过CPU 的权限检查从而能访问内核地址的。


具体来看,假设非法访问内存的指令为

mov rax  byte[x]  // 将内核地址x处的内容存到寄存器rax

操作系统会事先标注好内核的内存地址范围,如果 x 在内核的这个地址范围内,并且 CPU 不是以内核模式运行的话,那么该指令会被 CPU 标注为非法,引起异常,异常处理程序会将 rax 清空为0,并且终结此程序,这样后续指令再来读 rax 的时候就只能读到0了。


目前看来这一整套流程还是无懈可击的。


然而这里一个重要的前提假设是:CPU 在做权限检查并且将 rax 清零的过程中,不会泄露任何关于 [x] 的信息


然而 Meltdown 和 Spectre 这两个漏洞厉害的地方就在于,利用现代CPU speculative execution (预测执行)的漏洞,在 rax 被清零之前把信息传递了出去。


以 Meltdown 的攻击代码(简化版)为例:

mov rax byte[x]  // 非法操作
shl rax 0xC  // rax * 4096, page alignment
mov rbx qword [rbx + rax]  // [rbx] 为用户空间的一个array,合法操作

理论上讲,在执行第二条指令之前,rax应该已经被清零了。然而在实际的 CPU 运行中,为了达到更好的性能,第二条和第三条指令在异常处理生效之前都会被部分执行,直到异常处理时 rax 和 rbx 被清零。


目前看起来也没什么问题,因为rbx 也会被清零,关于 [x] 的任何信息都没有留下。


但问题的关键就在第三行指令:如果地址 rbx + rax 不在cache中的话,CPU 会自动将这一地址调入cache中,以便之后访问时获得更好的性能,然而异常处理并不会将这个cache flush掉。而这条 cache 的地址是和 rax 直接相关的,这样就相当于在 CPU 硬件中留下了和rax 相关的信息。


那么如何还原 rbx + rax 这个被cache的地址呢?这时候需要用到的原理就是利用cache的访问延时,即已经被cache的数据访问时间短,没有被cache的数据访问时间长。由于[rbx]这个array是在用户地址空间内的,可以自由操作,首先我们要确保整个 [rbx]这个array 都是没有被cache的,然后执行上述攻击代码,这时候 rbx + rax 这个地址就已经被cache了,接下来遍历整个[rbx] array,来测量访问时间,访问时间最短的那个 page 就可以确定为 rbx + rax。(如下图,图来自原论文meltdown)

rbx + 84 * page_size 处访问时间最短,因此确定原 rax 为84


至此,我们就取到了内核地址空间 x 处的一个 byte (84),如此循环,即可获得全部内核空间的数据,也就是说,整个电脑没有任何秘密可言,而且此漏洞完全不需要特殊权限,因此个人台式/云主机几乎都不可幸免(可怕!)。


至于 spectre,和 meltdown 的原理相似,利用分支预测错误的 speculative execution,访问到不该访问的信息,并且同样是通过 cache 这个side channel 传递出去。而且由于利用的分支预测原理普及率非常高,Spectre 的影响面更大一些。关于分支预测的原理,我之前还写过另外一个答案:CPU 的分支預測器是怎樣工作的? 可供参考。


为了阅读体验本文省略了很多细节(毕竟把几篇十几页的论文无损压缩到一篇专栏文章是不可能的),有耐心的读者可以去阅读原文:


[1] Meltdown: meltdownattack.com/melt

[2] Spectre: spectreattack.com/spect

[3] Flush-Reload Attack: FLUSH+RELOAD: A High Resolution, Low Noise, L3 Cache Side-Channel Attack

[4] KAISER: gruss.cc/files/kaiser.p

编辑于 2018-01-09

文章被以下专栏收录