【问题标题】:Spectre example幽灵示例
【发布时间】:2018-06-16 06:00:05
【问题描述】:

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

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

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

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

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

【问题讨论】:

  • 我认为您在该主题中的回答与我的问题没有直接关系。我想知道的是越界异常。假设一个数组有 10 个项目,所以范围是 0..9。现在,cpu 推测性地从索引 8 中获取一些项目。它们是 9、10、11、12。array1[10] 无效,它应该在发生附加之前抛出异常。不是吗?
  • 在下面给出了答案。 (Here 更能说明投机攻击)。推测执行的代码不会给出异常(否则,在 C 中,if (arr[x] != NULL) *arr[x] = 3; 之类的代码可以在 xNULL 时推测运行 *arr[x] = 3,这将触发用户不应该得到的异常,因为分支条件最终将评估为 false 并且推测运行代码不会退出。

标签: security spectre


【解决方案1】:

所以,array1[x] 实际上是无效的!那么攻击是什么?!没有获取到有效数据!

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

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

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

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

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

【讨论】:

  • 如果没有cflush命令,如何实现spectre?例如,是否可以使用 Evict+Reload?我似乎没有看到有人在 github 上成功地用 Evict+Reload 替换了 flush-reload?如果我使用Evict+Reload,是不是每次都要清空整个Cache中的所有Cachelines?
【解决方案2】:

Spectre(与 Metldown 不同)得益于 CPU 处理分支预测的方式。来自您参考的同一篇论文

[2.3] 推测执行要求处理器对分支指令的可能结果进行猜测。更好的预测通过增加可以成功提交的推测执行操作的数量来提高性能。
(...)
要预测是否采用条件分支, 处理器维护最近分支结果的记录。

然后

[4] 代码片段以对x 的边界检查开始,这对于安全性至关重要。特别是,此检查可防止处理器读取array1 之外的敏感内存。否则,越界输入x 可能会触发异常或可能导致处理器通过提供x = (address of a secret byte to read)−(base address of array1) 访问敏感内存。

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

不幸的是,在推测执行期间,边界检查的条件分支可能会遵循不正确的路径。例如,假设攻击者导致代码运行如下:

x 的值被恶意选择(并且越界),使得array1[x] 解析为受害者内存中某处的秘密字节k

array1 size 和 array2 不存在于处理器的缓存中,但 k 被缓存;和

• 先前的操作收到了有效的 x 值,导致分支预测器假设 if 很可能为真。

最后,在x 值被评估为过高之后,CPU 将有效地绕过if 主体,并且不会撤销检索到的y 值。但是缓存状态发生了变化,这就是攻击发生的地方:

处理器意识到其推测执行是错误的,并回退其寄存器状态。然而,在实际处理器上,来自array2 的推测性读取以特定于地址的方式影响缓存状态,其中地址取决于 k

array1[x] 的未授权访问是在推测代码执行期间进行的,因此不会引发异常,因为 CPU“知道”如果来自之前分支的条件,该推测执行的结果将不会退出碰巧是假的。

(与 Meltdown 不同,它会在执行的用户代码确实访问未经授权的区域时触发异常 - Meltdown 利用退出异常所需的时间与该访问之后预先执行的少数无序指令之间的竞争条件(并且不会被淘汰))。

【讨论】:

    【解决方案3】:

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

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

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

    1

    2

    3

    4

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

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

    然后 Attaker 可以用不同的方法撤销这 3 个(或在论文 k 中)。例如尝试一个数字并测量加载时间,然后从头开始重复所有操作

    (抱歉英语不好)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-05-11
      • 2011-07-09
      • 2014-07-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多