通过检查每个页面错误中的错误地址来缓解 Meltdown?

信息安全 linux 硬件 检测 核心 崩溃
2021-08-30 23:31:13

简短的问题

在缺少 Intel TSX(因此无法抑制异常)的系统上,检查每个页面错误指向内核内存的错误地址是否可靠地检测到尝试的 Meltdown 漏洞利用?Linux内核do_page_fault()函数在每个页面错误时被调用,并且错误内存访问的地址在该函数中可用,因此应该可以检查该地址是否指向特定于内核的内存范围。对于不能选择 KPTI 并且可以接受以可用性(非特权 DoS)换取机密性的威胁模型,这个想法是否正确?


长问题

最近披露的 Intel 处理器中的 Meltdown 漏洞利用所有现代处理器的无序执行特性来读取任意物理内存。这依赖于能够反复尝试访问内核内存,尽管访问尝试会失败。这些失败的访问尝试触发一个#PF或页面错误,导致发送用户空间进程SIGSEGV由于它试图访问内核内存。Meltdown 攻击利用了这样一个事实,即尽管访问被拒绝,缓存仍然填充有特权内存。攻击的下一阶段是使用定时攻击来检索缓存内容。然而,如果没有 TSX 支持,似乎不可能(据我所知)抑制这些页面错误。在这样的系统上,Meltdown 必然会触发大量由尝试访问内核内存引起的页面错误。这可以被内核检测到。

论文中,描述了执行攻击的三个步骤:

Meltdown 结合了讨论的两个构建块
在第 4 节中。首先,攻击者使 CPU 执行
一个瞬态指令序列,它使用了一个 inacces-
存储在物理内存某处的唯一秘密值
(参见第 4.1 节)。瞬态指令序列作用
作为隐蔽信道的发射器(参见第 4.2 节),
最终将秘密值泄露给攻击者。

  熔断包括 3 个步骤:

步骤 1  攻击者选择的内存位置的内容
  攻击者无法访问的信息被加载
  入一个寄存器。

步骤 2  临时指令访问高速缓存行
  基于寄存器的秘密内容。

Step 3  攻击者使用 Flush+Reload 确定
  访问缓存行,因此秘密存储在
  选择的内存位置。

通过对不同的内存位置重复这些步骤,
攻击者可以转储内核内存,包括
整个物理内存。

在阅读了关于使用内核跟踪子系统假设缓解措施之后,检测由于访问内核内存而导致的异常大量页面错误将能够可靠地检测到 Meltdown 是有道理的。我的想法正确吗?这种缓解措施将简单地检查每个页面错误CR2(保存错误地址的寄存器)是否大于0xffff000000000000,这将表明尝试访​​问内核内存。然后系统可能会引发内核恐慌,从而阻止攻击继续进行。

内核源代码中do_page_fault()函数定义为:

dotraplinkage void notrace
do_page_fault(struct pt_regs *regs, unsigned long error_code)
{
    unsigned long address = read_cr2(); /* Get the faulting address */
    enum ctx_state prev_state;

    prev_state = exception_enter();
    if (trace_pagefault_enabled())
        trace_page_fault_entries(address, regs, error_code);

    __do_page_fault(regs, error_code, address);
    exception_exit(prev_state);
}
NOKPROBE_SYMBOL(do_page_fault);

每次出现页面错误时都会调用此函数,并将错误地址保存到address. 如果没有 TSX 支持,据我所知,攻击无法避免进入此功能。在我看来,添加一个简单的检查来查看地址是否在危险范围内,因此BUG_ON(address > 0xffff000000000000)在这些限制下,类似的东西可以可靠地检测到 100% 的 Meltdown 攻击。address通过仅在发生足够数量的违规时触发恐慌并在小于时忽略违规(这意味着良性 NULL 指针取消引用),这可以变得更加可靠(不太可能触发误报mmap_min_addr),但这只会如果给定的工作负载触发误报,则有必要。

如果以下任何一项为真,则此缓解措施将不起作用:

  • Spectre 不会导致页面错误,可以在不滥用 eBPF 的情况下执行 Meltdown。
  • 在没有 TSX 的系统上,还有另一种方法可以在不触发页面错误的情况下使用 Meltdown。
  • do_page_fault()发生缺页时可以避免该功能。

重新阅读该论文时,它提到了使用 TSX 以外的其他方法抑制异常,但我并不完全清楚。听起来好像可以像这样避免页面错误:

if (condition_mispredicted_as_false)
    access_kernel_memory();

如果这是真的,那么这种检测机制(以及 Capsule8 的检测机制)将不起作用。

假设自然误报不是问题并忽略它会打开非特权 DoS 错误的事实,这种缓解措施是否适用于没有 TSX 的系统?

1个回答

这将阻止运行 Meltdown 攻击的三种方式中的两种。对你来说不幸的是,它对第三个没有任何作用。

进行 Meltdown 攻击的最简单方法是执行具有足够长的流水线延迟的非法读取,以使 CPU 在触发页面错误之前推测性地对读取进行操作,然后捕获错误。您的提议将在攻击者执行多次读取之前发现并阻止它。

更快的方法是使用 TSX 来抑制故障,但您已指定 TSX 在系统上不存在。

第三种方法是将 Meltdown 与 Spectre 的分支错误预测相结合:训练分支预测器以采用无害地址的“读取内存”分支,然后在指定受保护地址的同时以另一种方式分支。这比读取受保护内存的其他任何一种方式都慢得多,但是由于在发现分支错误预测时会丢弃非法读取,因此不会引发页面错误。因此,您提出的代码完全看不到这些读取。