幽灵示例

Spectre example

在幽灵 paper 中,有一个利用越界数组访问的示例(第 1.2 节)。密码是

if (x < array1_size)
  y = array2[ array1[x] * 256 ];

这个过程是用一些有效的 x 值来训练正确的路径。然后给出无效值 x 并同时假设 arra1_size 未缓存。由于分支预测器认为条件为真,它会推测性地获取 array2 的偏移量。

现在,问题来了。在推测执行中,它必须获取 array1[x] ,其中 x 是恶意的并且超出了范围。所以,array1[x]实际上是无效的!那什么是攻击?!未获取有效数据!

谁能帮我解释一下?这里有什么误解?

我的理解(简化)(可能有误):

当 x 高于边界时,处理器将加载标准数据 别的地方。 (有点像缓冲区溢出)

例如当数据是这样保存的时候:

1 <- 起始数组

2

3 <- 开始秘密数据

4

x 大于它可以读取的边界,例如 3(在论文中,这可以是所有内容及其命名的 k)。然后 3 被缓存

3用于加载第二个数组中的数据。处理器意识到错误并将其从缓存中删除(3/ k)。

然后攻击者可以用不同的方法撤销这个3(或纸上的k)。例如尝试一个数字并测量加载时间然后从头开始重复所有内容

(抱歉英语不好)

Spectre(与 Metlddown 不同)的工作归功于 CPU 处理分支预测的方式。来自您参考的同一篇论文

[2.3] Speculative execution requires that the processor make guesses as to the likely outcome of branch instructions. Better predictions improve performance by increasing the number of speculatively executed operations that can be successfully committed.
(...)
To predict whether a conditional branch is taken or not, the processor maintains a record of recent branches outcomes.

然后

[4] The code fragment begins with a bounds check on x which is essential for security. In particular, this check prevents the processor from reading sensitive memory outside of array1. Otherwise, an out-of-bounds input x could trigger an exception or could cause the processor to access sensitive memory by supplying x = (address of a secret byte to read)−(base address of array1).

但是这篇论文继续解释了为什么这可能仍然有效,不会触发异常:

Unfortunately, during speculative execution, the conditional branch for the bounds check can follow the incorrect path. For example, suppose an adversary causes the code to run such that:

• the value of x is maliciously chosen (and out-ofbounds) such that array1[x] resolves to a secret byte k somewhere in the victim’s memory;

array1 size and array2 are not present in the processor’s cache, but k is cached; and

• previous operations received values of x that were valid, leading the branch predictor to assume the if will likely be true.

最后CPU,在x值被评估过高后,将有效绕过if体,不会退回检索到的y值.然而缓存状态已经改变,这就是攻击发生的地方:

The processor realizes that its speculative execution was erroneous, and rewinds its register state. However, on actual processors, the speculative read from array2 affects the cache state in an address-specific manner, where the address depends on k

array1[x] 的未授权访问是在推测代码执行期间进行的,因此不会引发异常,因为 CPU“知道”该推测执行的结果不会被撤销如果前面分支的条件恰好为假。

(与 Meltdown 不同,Meltdown 在执行的用户代码确实访问未授权区域时触发异常 - Meltdown 利用退出异常所花费的时间与该访问之后的一些乱序指令之间的竞争条件,这些指令是预-执行(并且不会被淘汰))。

So, array1[x] is actually invalid! Then what is the attack?! no valid data is fetched!

这就是攻击的重点。索引(即 x)可能很大,所以我们能够访问我们不应该访问的数据。

例如,如果我们的代码在 Java 脚本沙箱或 Java 虚拟机中,我们将能够访问 sandbox/virtual 机器之外的数据。

更重要的是,推测执行可能会访问内核页面,即我们无权访问的页面。那就是崩溃。

这是我的基于 Spectre 的 Meltdown 概念证明,只有 99 行,您可能会觉得更容易理解:

https://github.com/berestovskyy/spectre-meltdown