Fallout: Leaking Data on Meltdown-resistant CPUs 论文笔记

基础知识

缓存

​ 为了提高从内存里读取数据的速度,我们设立了多级缓存。缓存速度比内存要快很多,可以用来存储一些经常用到的数据,这样可以调高数据的利用效率。

​ CPU会认为当前访问的某个地址的数据时,它周围的数据随后也会大概率被访问到,所以周围数据会一并放到缓存中,以便于取用。

乱序执行

​ 某些指令的准备工作,和一些不依赖前面指令运行结果的指令,都可以提前运行,然后把结果放入缓存。如果轮到该指令运行,就直接将缓存内数据写入内存。

分支预测

​ 遇到分支跳转时,按照之前的经验,如果某个分支经常被执行,那后续再去这个分支的概率一定很大,那这样咱们预测后面会去到这个分支,就提前把这个分支后面指令能做的工作先做了。

幽灵与熔断

​ 如果分支预测被恶意利用,收到恶意程序欺骗,那么就会在关键时候预测失败,从而执行一些本不该执行的指令。虽然只将数据存储在缓存中,但通过访问内存时间的不同(放入缓存的数据访问时间会明显较短),就可以知道哪一块地址被缓存了。

1
2
3
4
if (x < array1_size)
{
temp &= array2[array1[x] * 512];
}

​ 一开始的x都小于array1_size,欺骗CPU不断提前进行分支预测(投机执行)。但当真正的恶意x(某个地址单元)(大于array1_size)到来时,CPU还是把if里面的执行结果放入了缓存。只是在指令真正开始执行时,虽然缓存不被输出,但访问的时间会明显较短,数一下缓存的内存到数组开头的偏移距离,可以推出这个地址单元的值。

缓解机制

​ Meltdown攻击最有效的方式就是KAISER/KPTI。KAISER/KPTI方案中要求操作系统维护两个页表,一个页表给用户程序使用,一个给kernel自己使用。并且确保程序所使用的页表不会映射高优先级的页面,即不会映射kernel的页面。

​ 两个页表的切换,会导致CR3(控制寄存器:用于控制和确定处理器的操作模式以及当前执行任务的特性)的重新加载,从而引起TLB刷新,进而降低内存的访问速度。如果某些应用场景需要大量的内核和用户空间切换(两个页表之间的切换),会造成较高的性能开销。

最新的漏洞

​ 硬件修复后,上述缓解机制被禁用,该文章说明了最新的抗熔断处理器仍是具有数据泄漏的潜在风险,仍易受到熔断攻击。

  1. 一个写瞬态转发(WTF)的漏洞,它允许我们读取最近写入的数据
  2. 展示WTF的安全影响:
    1. 恢复系统内核写入的值
    2. 恢复TSX事务(粗粒度的锁,防止数据冲突)写入的数据
    3. 泄漏密钥
  3. 定义了一个新的TLB侧信道(store-to-leak):Inter的存储转发单元在一个不可访问的虚拟地址映射到一个相应的物理存储地址的过程中,可以利用一个丢失的权限检查,得到一个新的侧信道。
  4. 文章演示如何利用Store-to-Leak破解KASLR(上述的一种缓解机制)和ASLR(地址随机化),以及将这些攻击方式写成了一个小工具
  5. 定义了一个新的瞬态执行原因:它是当处理器遇到特定的边缘情况时执行的微型代码例程。(命名为assists)
  6. 实现了一次熔断攻击,利用由Supervisor Mode Access
    Prevention (SMAP)导致的页异常.

Write Transient Forwarding(WTF)漏洞

​ 文章发现WTF会错误地将值从写入的内存传递到随后的错误加载指令中。

​ 当程序试图从一个地址读取数据时,CPU必须首先检查存储缓冲区是否写入了相同的地址,如果地址匹配,则执行store-to-load forwarding。但是如果地址匹配但地址无效,则会产生WTF漏洞。

​ Inter的专利中表明,上述操作确实会发生错误。

“if there is a hit at operation 302 [lower address match]and the physical address of the load or store operations is not valid, the physical address check at operation 310 [full physical address match] may be considered as a hit and the method 300 [store-to-load forwarding] may continue at operation 308 [block load/forward data from store].”

​ 如果一个无效的地址,通过了低地址匹配302,但无法通过全地址匹配310,就会引发错误。该错误会导致300操作,使得store-to-load forwarding。

简单的例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
1char* victim_page = mmap(...,PAGE_SIZE,PROT_READ|PROT_WRITE,MAP_POPULATE, ...);
2char* attacker_address = 0x9876543214321000ull;//unsigned long long
3
4int offset = 7;
5victim_page[offset] = 42;
6if(tsx_begin() == 0) {
7memory_access(lut + 4096 * attacker_address[offset]);
8tsx_end();
9}
10
11for(i = 0; i < 256; i++) {
12 if(flush_reload(lut + i * 4096)) {
13 report(i);
14 }
15}

​ 上述的victim_page是一个普通的页面,用户可以在其中读写数据。attacker_address是构造的一个非规范的地址,其中的47到63位既不全是’ 0 ‘也不全是’ 1 ‘来导致错误。(行1-2)

​ 然后在用户空间 victim_page的指定偏移量7中存储机密值42。(行4-5)

​ 注意到,上述代码并没有直接访问victim_page来读取数据。相反,攻击者通过解引用毫无关联的attacker_address来读取存储缓冲区条目。而且上述代码还利用TSX事务来抑制该操作造成的其他异常。(行6-9)

​ 但由于WTF漏洞,CPU会以前一个存储的值作为页面偏移量来加载一个值。而前一个值就是我们存储的秘密值42。然后我们加载该页面的所有值,计算加载时间。会得到一个加载时间远小于其他值的内存地址,算一算偏移地址,就可以算出秘密值。

​ 这样的一个漏洞给可以让我们随意阅读上下文存储的数据。

数据弹出( Data Bounce)

我们想尝试,一个非法的数据写入是否能作为地址偏移量,去加载一个内存地址。如果可以,那么我们可以将需要获取的某一个秘密值作为输入,构造成地址,去访问内存。通过查看内存的访问速度,来判断哪一个内存访问速度明显较快,然后计算偏移量来恢复那个秘密值。

1
2
3
4
5
6
7
8
mov (0) -> $dummy
#生成一个异常并捕获他来启动瞬态执行
mov $x -> $(p)
#存储一个秘密值x在地址p上
mov (p) —> $value
#我们读取存储在地址p上的值
mov ($mem + $value * 4096) -> $dummy
#通过WTF,恢复存储的值

这里有两种情况:

  1. 如果从p读取的值是x,mem的第x页被缓存了,即Store-to-Load Forwarding的情况.
  2. No Store-to-Load Forwarding的情况出现,那么该数据弹出就失败了。这种失败可能是暂时的也可能是永久的。如果一个物理地址页面不支持虚拟地址,那么永远也不可能成功。如果来自硬件的错误(如中断),那么可能该错误是暂时的。

Fetch+Bounce

使用数据反弹很容易区分有效地址和无效地址。然而,它的成功率(即数据反弹需要重复的频率)直接取决于在TLB中存储了哪些地址。

通过分析数据反弹的成功率,我们进一步利用了与TLB相关的侧通道信息。

1
2
3
4
5
for retry = 0...2
mov $x→ (p)
mov (p)→ $value
mov ($mem + $value * 4096)→ $dummy
if flush_reload($mem + $x * 4096) then break

如果上述代码第一次就能命中,说明该地址本身就在TLB中。如果第二次可以命中,说明该地址不在TLB中,但是该地址是有效的。

可以看到页面0-7是无效的,页面17是在TLB中,其他地址有效但不在TLB中。

Speculative(投机的) Fetch+Bounce

如图:

攻击者需要控制数组索引就可以从内核中泄漏任意内存内容。根据要泄漏的字节值,我们将访问256个页面中的一个。然后,Fetch +Bounce用于检测哪些页面在TLB中缓存了有效的地址。缓存的TLB条目直接显示了泄漏的字节。

打破内核隔离

我们需要人为设置两个模块:

  • 内核模块

    • 我们设置的内核设置了一系列写入操作,每个操作都指向不同内核页面的不同页面偏移量。这些内核页面用户是无法直接访问的。
  • 攻击程序

    • 攻击者应用程序调用内核模块来执行内核写操作,然后尝试恢复内核写的值。

    攻击结果:

可以看到,内核存储数据数量越多,读取成功率越高。

在易受熔断的机器上,禁用KAISER补丁会使机器暴露在熔断攻击下。这意味着,与旧CPU相比,英特尔新一代CPU更容易受到攻击出现内核消息泄漏。

  • Copyright: Copyright is owned by the author. For commercial reprints, please contact the author for authorization. For non-commercial reprints, please indicate the source.

扫一扫,分享到微信

微信分享二维码
  • Copyrights © 2020-2023 YYz
  • Visitors: | Views:

请我喝杯咖啡吧~

支付宝
微信