【技术文章】Understanding Spectre & Meltdown Vulnerability 3

这篇文章中,我们将要讨论spectre以及它对当前系统的影响。正如之前文章介绍的,处理器使用推测执行以及分支预测来更好的利用CPU的周期。

Spectre 攻击会推测执行一些永远不会被执行的指令。这些推测执行的指令会改变微架构状态(比如CPU cache),从而引起side channel attacks。这些side channel attacks包括Flush-Reload Attack(相同的攻击也在Meltdown中使用)。

Understanding Spectre

Spectre和Meltdown的区别在于,我们会trick进程让其暴露自身的数据和秘钥,但是meltdown我们trick内核来暴露内核memory的数据。

想象一下,如果你运行浏览器的程序。在那个浏览器上,你运行了多个app,并且那些app在共享通用地址空间。那么底层的虚拟机如果确保这些app不能访问保存在通用地址空间的秘密数据和密码呢?这是通过访问memory之前进行相关的检查做到的。
比如我在浏览器上有一个app A,会在javascript中创造并使用一些数组(这段javascript代码会运行在浏览器上)。

var fruits = ["Banana", "Orange", "Apple", "Mango"];
var fLen = fruits.length;
var text = "<ul>";
for (i = 0; i < fLen; i++) {
    text += "<li>" + fruits[i] + "</li>";
}

问题:是什么阻止代码访问fruits[1000]?
答:如果这段代码尝试访问任何超出了array 长度边界的地址,那么虚拟机VM会返回undefined,因为内部的VM会确保每个array访问操作都在边界之内。因此内部的array访问会按照下面的执行:

var value = if ( x < fruits.size()) {
 fruits[x];
}

因此,底层的VM阻止了在单一VM上运行的多个app访问共享地址空间的其他app的秘密数据和密码。

然而Spectre攻击提供了另外一种途径来破坏虚拟机提供的隔离。使用这种攻击,如果我们知道之前秘密数据和密码存储在哪里,那么我们可以获得在common memory范围内的任何secret data和密码。

深入Spectre Attack

Spectre attacks是第一个训练分支预测来在特定代码段进入特定分支的技术。这是通过使用足够的数据训练target code,使其在特定的分支被taken。在训练好了分支预测器之后,处理器开始推测执行预测分支上的指令。此时,攻击者向目标代码传送一个恶意值。处理器仍然会尝试使用该恶意值来推测执行指令。

一旦处理器意识到它进入了错误的分支,它会迅速的放弃推测执行指令的状态。但是在推测执行窗口期间,一些微架构状态的改变已经发生了,并且隐藏在memory中。

让我们理解下面的代码:

if ( x < array1.size()) {
  int value = array2[array1[x] * 4096] // branch 1
}

注意:在这个例子中,我们会简单地将检查是否X在数组的范围内。如果在,那么我们会使用x*4096来访问array2。同样,array2是一个非常大的数组。

开始,攻击者执行这段代码,X在array的范围内,在此期间,处理器会凭借分支预测器的帮助,推测执行分支1, array2[array1[x] * 4096]。在这个阶段,在处理器推测执行分支1时,攻击者进行如下操作:

  1. 攻击者传输给X一个值超过array边界,即X>array1.size();
  2. 在开始Spectre攻击之前,攻击者确保CPU cache已经flush掉。这可以确保array1.size()对应的值被memory空间读取到cache之前,cpu处于idle状态。因此处理器会推测执行branch1的指令。
  3. 在这个推测执行的窗口,处理器会读取(array1+x)地址的值。因为这个X已经超过了array的大小,因此(array1+x)可能会包含一些隐藏的秘钥。
  4. 现在这个memory 地址的数据已经被存入寄存器,并且该分支下面的指令已经开始执行array2 [ Secret * 4096 ]。在执行完毕之后, array2 [ Secret * 4096 ] 的数据肯定已经在CPU cache中。
  5. 剩下的操作就是和meltdown类似,我们遍历secret的所有可能的值,检查需要花多将该值从memory中加载进来。

通过这种方式,我们逐字节的访问地址空间的信息,获得访问秘钥信息的权限。

注意,在javascript中,我们没有CLFFLUSH指令来保证CPU cache已经被flush掉,但是这个可以间接的通过使用Evict+Reload技术来保证。

在Evict+Reload中,eviction通过强制cache set存储数据。比如访问其他memory位置的数据,将会被保存到cache中,并且由于cache大小,导致处理器放弃被probe的数据。

如何解决Spectre

没有直接的方法来避免这个问题。其中的一个方法是我们可以放弃在关键代码段使用推测执行。这些关键代码段可以被VM判断,基于代码段是否进行下面的两个判断:

  1. 这些代码是否可能是用来推测的执行指令,并且是否可能获得进程地址中保护空间的数据?
  2. 如果我们关闭这些代码段的推测执行,程序性能会降低多少

另外,像LFENCE这样的指令可以确保我们阻塞所有的后面的指令,直到之前的指令已经执行完毕。

欢迎关注我的公众号《处理器与AI芯片》

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值