我不认为来自 RS 的负载回放与 RIDL 攻击有关。因此,我将根据我对 RIDL 论文中提供的信息的理解、英特尔对这些漏洞的分析以及相关专利。
行填充缓冲区是 L1D 缓存中的硬件结构,用于保存缓存中未命中的内存请求和 I/O 请求,直到它们得到服务。当所需的高速缓存行填充到 L1D 数据阵列中时,会为可高速缓存的请求提供服务。当驱逐写组合缓冲区的任何条件发生时(如手册中所述),将提供写组合写服务。UC 或 I/O 请求在被发送到 L2 缓存时得到服务(这会尽快发生)。
请参阅 RIDL论文的图 4 。用于产生这些结果的实验工作如下:
- 受害线程将已知值写入单个内存位置。内存位置的内存类型为WB、WT、WC或UC。
- 受害线程在循环中读取相同的内存位置。每个加载操作后面
MFENCE
都有一个可选的CLFLUSH
. 从论文中我不清楚CLFLUSH
其他两个指令的顺序,但这可能无关紧要。MFENCE
序列化缓存行刷新操作以查看缓存中每次加载未命中时会发生什么。此外,MFENCE
减少了 L1D 端口上两个逻辑核之间的争用,从而提高了攻击者的吞吐量。
- 在同级逻辑核心上运行的攻击者线程循环执行清单 1 中所示的代码。第 6 行使用的地址可以是任何东西。唯一重要的是第 6 行的加载要么出错,要么导致需要微码辅助(设置页表条目中的访问位)的页面遍历。页面遍历也需要使用 LFB,并且大多数 LFB 在逻辑内核之间共享。
我不清楚图 4 中的 Y 轴代表什么。我的理解是,它表示每秒从隐蔽通道获取到缓存层次结构(第 10 行)的行数,其中数组中行的索引等于受害者写入的值。
如果内存位置是 WB 类型,当受害线程将已知值写入内存位置时,该行将被填充到 L1D 缓存中。如果内存位置是 WT 类型,当受害线程将已知值写入内存位置时,该行将不会被填充到 L1D 缓存中。但是,在第一次读取该行时,它将被填充。因此,在这两种情况下CLFLUSH
,来自受害线程的大多数负载都会在缓存中命中。
当加载请求的缓存行到达 L1D 缓存时,它首先被写入为请求分配的 LFB。缓存行的请求部分可以直接从 LFB 提供给加载缓冲区,而无需等待行被填充到缓存中。根据 MFBDS 漏洞的描述,在某些情况下,可能会将来自先前请求的陈旧数据转发到加载缓冲区以满足加载 uop。在 WB 和 WT 情况下(没有刷新),受害者的数据最多被写入 2 个不同的 LFB。来自攻击者线程的页面遍历可以轻松覆盖 LFB 中受害者的数据,之后攻击者线程将永远无法在其中找到数据。所有在 L1D 缓存中命中的加载请求都不会通过 LFB;他们有一条单独的道路,它与来自 LFB 的路径复用。尽管如此,在某些情况下,来自 LFB 的陈旧数据(噪声)被推测性地转发到攻击者的逻辑核心,这可能来自页面遍历(也可能来自中断处理程序和硬件预取器)。
有趣的是,在 WB 和 WT 情况下,陈旧数据转发的频率远低于所有其他情况。这可以通过以下事实来解释:在这些情况下,受害者的吞吐量要高得多,并且实验可能会提前终止。
在所有其他情况下(WC、UC 和所有带刷新的类型),缓存中的每个加载都未命中,并且必须通过 LFB 从主内存将数据提取到加载缓冲区。发生以下事件序列:
- 来自受害者的访问在 TLB 中命中,因为它们访问的是相同的有效虚拟页面。物理地址从 TLB 获得并提供给 L1D,L1D 为请求分配一个 LFB(由于未命中),并将物理地址与描述加载请求的其他信息一起写入 LFB。此时,来自受害者的请求在 LFB 中等待处理。由于受害者
MFENCE
在每次加载后都会执行一次,因此在任何给定周期内,LFB 中最多有一个未完成的加载来自受害者。
- 攻击者在兄弟逻辑核心上运行,向 L1D 和 TLB 发出加载请求。每次加载都是到一个未映射的用户页面,因此会导致错误。当它在 TLB 中未命中时,MMU 告诉加载缓冲区应该阻止加载,直到地址转换完成。根据专利和其他英特尔专利的第 26 段,这就是 TLB 未命中的处理方式。地址转换仍在进行中,加载被阻塞。
- 来自受害者的加载请求接收它的缓存线,该缓存线被写入 LFB 中,并为加载而涂上所有涂层。负载请求的部分行被转发到 MOB,同时,该行被写入 L1D 缓存。之后,可以解除 LFB 的涂层,但不会清除任何字段(除了指示其空闲的字段)。特别是,数据仍在LFB中。受害者然后发送另一个加载请求,该请求在缓存中也未命中,要么是因为它不可缓存,要么是因为缓存行已被刷新。
- 攻击者加载的地址转换过程完成。MMU 确定需要引发故障,因为物理页面不存在。但是,直到负载即将退休(当它到达 ROB 的顶部时)才会引发故障。无效的翻译不会缓存在 Intel 处理器的 MMU 中。MMU 仍然必须告诉 MOB 翻译已经完成,并且在这种情况下,在 ROB 的相应条目中设置错误代码。似乎当 ROB 看到其中一个微指令具有有效的故障/辅助代码时,它会禁用与该微指令的大小和地址相关的所有检查(可能还有 ROB 中的所有后续微指令)。这些检查不再重要。据推测,禁用这些检查可以节省动态能源消耗。退休逻辑知道当负载即将退休时,无论如何都会提出错误。同时,当 MOB 被告知翻译完成时,它像往常一样重放攻击者的负载。然而,这一次,一些无效的物理地址被提供给 L1D 缓存。通常,物理地址需要与来自同一逻辑核心的 LFB 中的所有未决请求进行比较,以确保逻辑核心看到最新的值。这是在查找 L1D 缓存之前或同时完成的。物理地址并不重要,因为比较逻辑被禁用。但是,所有比较的结果都表现得好像结果表明成功一样。如果至少有一个已分配的 LFB,则物理地址将匹配某个已分配的 LFB。由于受害者有一个未完成的请求,并且由于受害者' s secret 可能已经从先前的请求中写入到同一个 LFB 中,缓存行的同一部分,在技术上包含陈旧数据,在这种情况下(陈旧数据是机密),将被转发给攻击者。请注意,攻击者可以控制缓存行内的偏移量和要获取的字节数,但无法控制哪个 LFB。高速缓存行的大小为 64 字节,因此只有攻击者加载的虚拟地址的 6 个最低有效位以及加载的大小很重要。然后,攻击者使用数据索引到其数组中,以使用缓存侧通道攻击来揭示秘密。这种行为也可以解释 MSBDS,显然数据大小和 STD uop 检查被禁用(即,检查很容易通过)。缓存行的同一部分,在技术上包含陈旧数据,在这种情况下(陈旧数据是秘密),将被转发给攻击者。请注意,攻击者可以控制缓存行内的偏移量和要获取的字节数,但无法控制哪个 LFB。高速缓存行的大小为 64 字节,因此只有攻击者加载的虚拟地址的 6 个最低有效位以及加载的大小很重要。然后,攻击者使用数据索引到其数组中,以使用缓存侧通道攻击来揭示秘密。这种行为也可以解释 MSBDS,显然数据大小和 STD uop 检查被禁用(即,检查很容易通过)。缓存行的同一部分,在技术上包含陈旧数据,在这种情况下(陈旧数据是秘密),将被转发给攻击者。请注意,攻击者可以控制缓存行内的偏移量和要获取的字节数,但无法控制哪个 LFB。高速缓存行的大小为 64 字节,因此只有攻击者加载的虚拟地址的 6 个最低有效位以及加载的大小很重要。然后,攻击者使用数据索引到其数组中,以使用缓存侧通道攻击来揭示秘密。这种行为也可以解释 MSBDS,显然数据大小和 STD uop 检查被禁用(即,检查很容易通过)。请注意,攻击者可以控制缓存行内的偏移量和要获取的字节数,但无法控制哪个 LFB。高速缓存行的大小为 64 字节,因此只有攻击者加载的虚拟地址的 6 个最低有效位以及加载的大小很重要。然后,攻击者使用数据索引到其数组中,以使用缓存侧通道攻击来揭示秘密。这种行为也可以解释 MSBDS,显然数据大小和 STD uop 检查被禁用(即,检查很容易通过)。请注意,攻击者可以控制缓存行内的偏移量和要获取的字节数,但无法控制哪个 LFB。高速缓存行的大小为 64 字节,因此只有攻击者加载的虚拟地址的 6 个最低有效位以及加载的大小很重要。然后,攻击者使用数据索引到其数组中,以使用缓存侧通道攻击来揭示秘密。这种行为也可以解释 MSBDS,显然数据大小和 STD uop 检查被禁用(即,检查很容易通过)。然后,攻击者使用数据索引到其数组中,以使用缓存侧通道攻击来揭示秘密。这种行为也可以解释 MSBDS,显然数据大小和 STD uop 检查被禁用(即,检查很容易通过)。然后,攻击者使用数据索引到其数组中,以使用缓存侧通道攻击来揭示秘密。这种行为也可以解释 MSBDS,显然数据大小和 STD uop 检查被禁用(即,检查很容易通过)。
- 随后,故障/辅助负载到达 ROB 的顶部。负载没有退出,管道被刷新。如果负载发生故障,则会引发故障。在辅助加载的情况下,从相同的加载指令重新开始执行,但辅助在分页结构中设置所需的标志。
- 重复这些步骤。但是攻击者可能并不总是能够从受害者那里泄露秘密。如您所见,来自攻击者的加载请求必须命中包含机密的已分配 LFB 条目。为页面遍历和硬件预取器分配的 LFB 可能会使成功执行攻击变得更加困难。
如果攻击者的负载没有故障/协助,LFB 将从 MMU 接收到有效的物理地址,并执行正确性所需的所有检查。这就是负载必须故障/协助的原因。
论文中的以下引用讨论了如何在同一线程中执行 RIDL 攻击:
我们通过在我们自己的线程中写入值并观察我们从同一个线程泄漏的值来执行没有 SMT 的 RIDL 攻击。图 3 显示,如果我们不写入值(“没有受害者”),我们只会泄漏零,但是当受害者和攻击者运行在同一个硬件线程中(例如,在沙箱中)时,我们几乎在所有情况下都会泄漏秘密值.
我认为这个实验中没有特权级别的变化。受害者和攻击者在同一硬件线程上的同一操作系统线程中运行。当从受害者返回给攻击者时,LFB 中可能仍有一些未完成的请求来自(尤其是来自商店)。请注意,在 RIDL 论文中,在所有实验中都启用了 KPTI(与 Fallout 论文相比)。
除了从 LFB 泄漏数据外,MLPDS 还显示数据也可能从加载端口缓冲区泄漏。这些包括线分割缓冲区和用于大小大于 8 字节的加载的缓冲区(我认为当加载 uop 的大小大于加载端口的大小时需要它,例如 SnB/IvB 上的 AVX 256b占用端口 2 个周期)。
图 5 中的 WB 情况(无冲洗)也很有趣。在这个实验中,受害线程将 4 个不同的值写入 4 个不同的缓存行,而不是从同一个缓存行读取。该图显示,在 WB 情况下,只有写入最后一个缓存行的数据会泄露给攻击者。解释可能取决于循环的不同迭代中缓存行是否不同,遗憾的是在论文中并不清楚。论文说:
对于没有刷新的WB,只有最后一个缓存行有一个信号,这表明CPU在将数据存储到缓存之前在LFB的单个条目中执行写组合。
在将数据存储到缓存中之前,如何在同一个 LFB 中组合对不同缓存行的写入?那是零意义。LFB 可以保存单个高速缓存行和单个物理地址。像这样组合写入是不可能的。可能发生的情况是 WB 写入正在写入为其 RFO 请求分配的 LFB。当无效的物理地址被传输到 LFB 进行比较时,数据可能总是从最后分配的 LFB 中提供。这可以解释为什么只有第四个存储写入的值被泄露。
有关 MDS 缓解措施的信息,请参阅:什么是新的 MDS 攻击,如何缓解它们?. 我在那里的回答只讨论了基于英特尔微码更新的缓解措施(不是非常有趣的“软件序列”)。
下图显示了使用数据推测的易受攻击的结构。