跨线程返回地址预测

某些 AMD 和海光处理器存在跨线程返回地址预测漏洞。在 SMT 模式下运行时,当一个同级线程从 C0 状态转换出去时,另一个同级线程可能会使用从 C0 状态转换出去的同级线程的返回目标预测。

Spectre v2 缓解措施保护 Linux 内核,因为它在上下文切换到空闲线程时,会用安全的目标填充返回地址预测条目。然而,KVM 允许 VMM 在从 C0 状态转换出去时阻止退出客户机模式。这可能导致由客户机控制的返回目标被同级线程使用。

受影响的处理器

以下 CPU 存在漏洞

  • AMD Family 17h 处理器

  • 海光 Family 18h 处理器

问题

当 SMT 启用时,受影响的支持 SMT 的处理器支持 1T 和 2T 执行模式。在 2T 模式下,核心中的两个线程都在执行代码。要使处理器核心进入 1T 模式,需要其中一个线程请求从 C0 状态转换出去。这可以通过 HLT 指令或请求非 C0 的 MWAIT 指令来传达。当线程重新进入 C0 状态时,处理器会转换回 2T 模式,前提是另一个线程也仍在 C0 状态下。

在受影响的处理器中,返回地址预测器 (RAP) 根据 SMT 模式进行分区。例如,在 2T 模式下,每个线程使用一个私有的 16 条目 RAP,但在 1T 模式下,活动线程使用一个 32 条目 RAP。在 1T/2T 模式之间转换时,RAP 内容不会被修改,但 RAP 指针(控制用于预测的下一个返回目标)可能会改变。这种行为可能导致在 1T/2T 切换后,一个 SMT 线程的返回目标被同级线程的 RET 预测使用。特别是,在转换为 1T 后立即执行的 RET 指令可能使用刚进入空闲状态的线程的返回目标。理论上,如果使用的返回目标不是来自可信代码,这可能导致信息泄露。

攻击场景

可以通过在受影响的处理器上执行一系列具有目标返回位置的 CALL 指令,然后转换出 C0 状态来发起攻击。

缓解机制

在进入空闲状态之前,内核会将上下文切换到空闲线程。上下文切换通过执行一系列 CALL 指令,用安全的目标填充 RAP 条目(在 Linux 中称为 RSB)。

通过拦截 HLT 和 MWAIT 指令,阻止客户机虚拟机直接使处理器进入空闲状态。

完全解决此问题需要以上两种缓解措施。

内核命令行上的缓解控制

使用现有的 Spectre v2 缓解措施,这些措施将在上下文切换时填充 RSB。

KVM 缓解控制 - 模块参数

默认情况下,KVM 虚拟机监控程序通过拦截客户机尝试从 C0 转换出去来缓解此问题。VMM 可以使用 KVM_CAP_X86_DISABLE_EXITS 功能来覆盖这些拦截,但由于这不常见,因此覆盖此路径的缓解措施默认未启用。

KVM_CAP_X86_DISABLE_EXITS 功能的缓解措施可以通过布尔模块参数 mitigate_smt_rsb 启用,例如 kvm.mitigate_smt_rsb=1