首页 > 解决方案 > 分支预测和推测性提取缓解

问题描述

为什么虚拟地址 (VA) 分离不足以缓解各种幽灵和崩溃缺陷?我的意思是通用的,不包括攻击intel p-cache == v-cache hack的那个;这显然是个坏主意,我找不到任何同情。

作为基线:

  1. 我的内核地址空间 (AS) 只与用户 AS 共享一个文本和数据页。这些页面包含足够的代码和数据来保存和存储寄存器;加载一个新的内存上下文,然后跳转到合适的地方。因此,这里没有有趣的地址可以发现。

  2. 来自 exec 的进程 AS 没有任何共同的 VA。也就是说,每个 VA 分配都是从一个公共池中获取的,因此即使是像 libc 这样的共享对象在每个进程中都位于不同的地址。大多数 unix 派生的人会觉得这很奇怪,但这当然是可行的;我错误地做了一次^H*10/为了测试。

  3. Fork() 处理的图像如果位于不同的访问控制域中,则会被沙箱化,以防止交叉泄漏。沙盒可以涉及上下文切换缓存驱逐、排除超线程的 cpuset,一直到非干扰内核。

我了解 [1] 是解决熔毁相关问题的基本方法;[2] 是 [1] 的扩展,因此适用于幽灵。[3] 会导致性能问题,但同样仅限于这些情况。

标签: x86armx86-64cpu-architecturebranch-prediction

解决方案


崩溃攻击依赖于(推测性地)直接(从攻击过程中)访问目标虚拟地址1

但幽灵不是。 您启动分支预测器,以便受到攻击的代码推测性地访问它自己的虚拟地址空间,这是它有权这样做的。 分支预测器别名意味着您通常/有时可以在您无法/没有映射的虚拟地址处启动分支的预测。(例如在内核中。)

通常的侧通道,缓存读取攻击,是基于在您自己的地址空间中逐出数组的缓存。但是其他侧通道可以将 Spectre 数据从目标返回给攻击者,例如启动缓存,然后查找哪个条目被冲突未命中驱逐,该地址在受攻击的进程中对某些内存进行别名。(更难,因为现代 x86 CPU 中的 L3 缓存使用复杂的索引功能,这与使用简单位范围作为索引的更简单缓存不同。但可能您可以使用 L2 或 L1d 未命中。L2 未命中/L3 命中仍应明显长于L2命中。)

或者使用 SMT(例如超线程),一种 ALU 计时攻击,其中 Spectre 小工具会创建与数据相关的 ALU 端口压力。在这种情况下,唯一相关的内存访问是受到攻击的数据(硬件允许,只有错误推测分支会导致回滚,而不是加载错误)。


当攻击内核时,它会将攻击进程的物理内存页映射到某个地方。(大多数内核将所有物理内存映射到一个连续的虚拟地址范围,从而可以轻松访问任何物理地址。) 缓存基于物理地址,而不是虚拟地址。

通过同一页面的不同映射使缓存行变热的 Spectre 小工具仍然有效。

在系统调用的上下文中,内核通常将用户空间内存映射到它在进程内部使用的相同虚拟地址,因此系统调用喜欢read并且write可以在用户空间和页面缓存之间进行复制。许多系统调用将用户空间指针传递给文件名。因此,在攻击内核时,Spectre gadget 可以在攻击过程中直接使用用户空间地址。

Spectre gadget 本身甚至可能位于用户空间内存中,尽管使用单独的页表来解决 Meltdown,您可以通过将内核页表设置为在没有 exec 权限的情况下映射用户空间 VA 来缓解这种情况。


脚注 1:Meltdown 是对页表中 U/S 位的绕过,允许用户空间潜在地读取内核留下映射的任何内存。是的,[1] 是一个足够的解决方法。请参阅http://blog.stuffedcow.net/2018/05/meltdown-microarchitecture/


推荐阅读