深入浅出解析Meltdown与Spectre漏洞(第一部分)

本文通过通俗易懂的方式解析Meltdown漏洞的工作原理,涉及处理器缓存机制、预测执行和分支预测等关键技术概念,帮助读者理解为何这些存在25年的设计缺陷会引发严重的安全问题。

Meltdown与Spectre可访问性概述(第一部分)

在过去几周,现代处理器中两个关键设计缺陷的细节终于向公众披露。虽然关于Meltdown和Spectre影响的讨论很多,但关于这些攻击究竟是什么以及如何运作的详细说明却很少。我们将尽力弥补这一空白。

本文旨在解释Meltdown和Spectre攻击的工作原理,但采用的方式即使没有计算机架构背景的人也能理解。部分技术细节会大幅简化或省略,但您将理解核心概念,以及为什么Spectre和Meltdown如此重要且技术上有趣。

为便于阅读,本文分为两部分。第一部分(即您现在阅读的内容)从计算机架构速成课程开始,提供一些背景知识并解释Meltdown的实际作用。第二部分解释Spectre的两种变体,并讨论为什么我们在这些漏洞存在25年后才进行修复。

背景

首先快速概述一些重要的计算机架构概念,以及关于硬件、软件及其如何协同工作的基本假设。这些对于理解漏洞及其工作原理是必要的。

软件是指令和数据

您使用的所有软件(例如Chrome、Photoshop、Notepad、Outlook等)都是由计算机处理器执行的一系列小型独立指令。这些指令对存储在内存(RAM)和称为寄存器的小型特殊存储位置表中的数据进行操作。几乎所有软件都假设程序的指令按顺序执行。这个假设既合理又实用——相当于假设时间旅行是不可能的——它使我们能够编写正常运行的软件。

Windows上notepad.exe中的这些Intel x86-64处理器指令展示了软件在指令级别的外观。箭头从分支指令流向其可能的目的地。

处理器设计为快速运行。非常非常快。现代Intel处理器每秒可执行约3000亿条指令。速度推动新处理器销售。消费者需求速度。计算机工程师找到了一些非常聪明的方法来使计算机快速运行。其中三种技术——缓存、预测执行和分支预测——是理解Meltdown和Spectre的关键。正如您可能猜到的,这些优化与计算机硬件执行指令的顺序假设相冲突。

缓存

处理器执行指令非常快(每条指令约2纳秒)。这些指令需要存储在某个地方,它们操作的数据也是如此。那个地方称为主内存(即RAM)。读取或写入RAM的速度比处理器执行指令的速度慢50-100倍(约100纳秒/操作)。

因为从内存读取和写入速度较慢(相对于指令执行速度),现代处理器的关键目标是避免这种缓慢。实现这一目标的一种方法是假设大多数程序的共同行为:它们反复访问相同的数据。现代处理器通过将频繁访问的内存位置内容副本存储在“缓存”中来加速对这些位置的读写。该缓存位于芯片上,靠近执行指令的处理器核心。这种接近性使得访问缓存内存位置比离芯片到RAM中的主存储要快得多。缓存访问时间因缓存类型及其位置而异,但大约在1纳秒到3纳秒之间,而访问RAM则需要约100纳秒。

Intel Nehalem处理器芯片的图像(第一代Core i7,取自本新闻稿)。有多个级别的缓存,按距离执行电路的远近编号。L1和L2缓存在核心本身(可能是核心图像的右下/左下)。L3缓存在芯片上但在多个核心之间共享。缓存占用大量昂贵的处理器空间,因为性能提升是值得的。

与主内存容量相比,缓存容量非常小。当缓存填满时,放入缓存中的任何新项目必须驱逐现有项目。由于内存和缓存访问时间存在显著差异,程序可以通过计时访问所需时间来告知其请求的内存位置是否被缓存。我们稍后将深入讨论这一点,但这种基于缓存的时间侧信道是Meltdown和Spectre用来观察内部处理器状态的方法。

预测执行

一次执行一条指令很慢。现代处理器不会等待。它们一次执行一束指令,然后重新排序结果以假装一切按顺序执行。这种技术称为乱序执行。从性能角度来看,这很有意义:一次执行4条指令需要8纳秒(4条指令 x 2纳秒/指令)。一次执行4条指令(在现代处理器上是现实的)只需2纳秒——速度提升75%!

虽然乱序执行和预测执行有不同的技术定义,但出于本博客文章的目的,我们将两者都称为预测执行。我们觉得这是合理的,因为乱序执行本质上是推测性的。一束中的某些指令可能不需要执行。例如,像除以零这样的无效操作可能会停止执行,从而迫使处理器回滚同一束中后续指令执行的操作。

通过预测执行指令获得的性能可视化。假设有4个执行单元且指令彼此不依赖,顺序执行需要8纳秒,而乱序执行需要2纳秒。请注意,此图是极大的简化,故意没有显示真实处理器中发生的许多重要事情(如流水线)。

有时,处理器对将执行哪些指令的猜测是错误的。在这些情况下,预测执行的指令必须“取消执行”。正如您可能猜到的,研究人员发现未执行指令的一些副作用仍然存在。

导致预测执行猜测错误的注意事项很多,但我们将重点关注与Meltdown和Spectre相关的两个:异常和分支指令。当处理器检测到规则被违反时会发生异常。例如,除法指令可以除以零,或者内存读取可以在没有权限的情况下访问内存。我们在关于Meltdown的部分进一步讨论这一点。第二个注意事项,分支指令,告诉处理器接下来执行什么。分支指令对于理解Spectre至关重要,并在下一节中进一步描述。

分支预测

分支指令控制执行流程;它们指定处理器应在何处获取下一条指令。对于本次讨论,我们只对两种分支感兴趣:条件分支和间接分支。条件分支就像道路上的岔路口,因为处理器必须根据条件值(例如A > B;C = 0;等)选择两个选项之一。间接分支更像一个门户,因为处理器可以去任何地方。在间接分支中,处理器读取一个值,该值告诉它在哪里获取下一条指令。

条件分支及其两个潜在目的地。如果cmp指令的两个操作数相等,则将采用此分支(即处理器将执行绿色箭头处的指令)。否则将不采用分支(即处理器将执行红色箭头处的指令)。代码取自notepad.exe。

间接分支。此分支将重定向执行到内存位置0x10000c5f0处的任何地址。在这种情况下,它将调用initterm函数。代码取自notepad.exe。

分支发生非常频繁,并且妨碍预测执行。毕竟,处理器直到分支条件计算完成后才知道要执行哪些代码。处理器解决这一困境的方法称为分支预测。处理器猜测分支目的地。当猜测错误时,已执行的操作将被取消执行,并从正确位置获取新指令。这不常见。现代分支预测器在正常工作量下轻松达到96%以上的准确率。

当分支预测器错误时,处理器会在错误的上下文中预测执行指令。一旦发现错误,这些幽灵指令将被取消执行。正如我们将解释的,Spectre漏洞表明可以控制分支预测器并确定那些未执行指令的某些影响。

Meltdown

现在让我们应用上述计算机架构知识来解释Meltdown。Meltdown漏洞是(几乎)每个自1995年以来发布的Intel处理器中的设计缺陷。Meltdown允许特制程序读取其不应有权访问的核心操作系统内存。

处理器通常有两种特权模式:用户和内核。用户部分用于您日常交互的正常程序。内核部分用于操作系统的核心。内核在您机器上的所有程序之间共享,确保它们可以协同工作并与计算机硬件配合,并包含您可能不想暴露给所有运行程序的敏感数据(击键、网络流量、加密密钥等)。因此,不允许用户程序读取内核内存。确定哪部分内存是用户、哪部分是内核的表也存储在内存中。

想象一种情况,某些内核内存内容在缓存中,但其权限不在。检查权限将比简单读取内容值慢得多(因为它需要内存读取)。在这些情况下,Intel处理器异步检查权限:它们启动权限检查,无论如何读取缓存值,并在权限被拒绝时中止执行。因为处理器比内存快得多,在权限结果到达之前,可能会有数十条指令被预测执行。通常,这不是问题。任何在权限检查失败后发生的指令都将被丢弃,就像它们从未执行过一样。

研究人员发现的是,可以预测执行一组指令,即使取消执行后也会留下可观察的迹象(通过缓存时间侧信道)。此外,根据内核内存的内容,可能会留下不同的迹象——这意味着用户应用程序可以间接观察内核内存内容,而无需有权读取该内存。

技术细节

使用以下步骤术语的Meltdown核心问题图形表示。可以在没有权限的情况下预测读取核心系统内存。这些临时预测读取的效果在指令中止和取消执行后应该是不可见的。事实证明,预测执行的缓存效果无法撤销,这创建了一个基于缓存的时间侧信道,可用于在没有权限的情况下读取核心系统内存。

在高层次上,攻击工作原理如下:

  1. 用户应用程序请求一个大内存块,我们称之为bigblock,并确保其中没有任何部分被缓存。该块在逻辑上分为256块(bigblock[0]、bigblock[1]、bigblock[2]、… bigblock[255])。
  2. 进行一些准备以确保内核地址的内存权限检查需要很长时间。
  3. 乐趣开始!程序将从内核内存地址读取一个字节——我们称此值为secret_kernel_byte。提醒一下,一个字节可以是0到255范围内的任何数字。此操作启动了权限检查和处理器之间的竞赛。
  4. 在权限检查完成之前,硬件继续其程序的预测执行,该程序使用secret_kernel_byte读取bigblock的一块(即x = bigblock[secret_kernel_byte])。即使指令后来被撤销,使用bigblock的一块也会缓存该块。
  5. 此时权限检查返回权限被拒绝。所有预测执行的指令都被取消执行,处理器假装它从未在bigblock[secret_kernel_byte]读取内存。只有一个问题:bigblock的一块现在在缓存中,而之前不在。
  6. 程序将计时读取bigblock每一块所需的时间。由于预测执行而缓存的块将比其余部分读取得快得多。
  7. bigblock中块的索引是secret_kernel_byte的值。例如,如果bigblock[42]读取得比任何其他条目快得多,则secret_kernel_byte的值必须为42。
  8. 程序现在通过缓存时间侧信道和预测读取了内核内存中的一个字节。
  9. 程序现在可以继续读取更多字节。Meltdown论文作者声称他们使用这种技术可以以503 Kb/s的速度读取内核内存。

影响是什么?

恶意软件可以使用Meltdown更轻松地在您的桌面上获得永久立足点,并监视您的密码和网络流量。这绝对很糟糕。您应该去应用修复程序。然而,恶意软件已经可以做到这些事情,尽管需要更多努力。

如果您是云提供商(如Amazon、Google或Microsoft)或拥有主要互联网基础设施的公司(如Facebook),那么这个漏洞绝对是一场灾难。很难强调这个漏洞有多糟糕。问题在于:云的工作原理是将大规模数据中心划分为许多可按分钟租用的虚拟机。一台物理机器可以有数百个不同的虚拟租户,每个都运行自己的自定义代码。Meltdown打破了租户之间的墙:每个租户都可能看到其他租户所做的一切,如他们的密码、加密密钥、源代码等。注意:物理硬件如何虚拟化很重要。Meltdown在某些情况下不适用。细节超出了本文的范围。

Meltdown的修复会带来性能损失。有些消息来源说是5-30%的性能损失,有些说是可忽略的,还有其他说是单位数到明显。我们确切知道的是,较旧的Intel处理器受影响比新处理器大得多。对于桌面机器,这稍微不方便。对于大型云提供商或互联网公司,整个基础设施5%的性能损失是一个巨大的代价。例如,Amazon估计有200万台服务器。5%到30%的减速可能意味着购买和安装10万台(5%)到60万台(30%)额外服务器以匹配先前能力。

我应该做什么?

请安装操作系统(即MacOS、Windows、Linux)的最新更新。所有主要软件供应商都发布了应由自动更新程序应用的修复程序。

所有主要云提供商已在内部部署修复程序,您作为客户无需担心。

待续…

我们希望您对计算机架构概念和Meltdown背后的技术细节有更好的理解。在本博客文章的后半部分,我们将解释Spectre V1和Spectre V2的技术细节,并讨论为什么这些漏洞在过去25年中一直隐藏。技术背景将变得更加复杂,但漏洞也更有趣。

最后,我们想提醒读者,本博客文章是为了让没有计算机架构背景的人也能理解而编写的,我们真诚希望我们成功解释了一些困难的概念。Meltdown和Spectre论文,以及Project Zero博客文章是更详细细节的更好来源。

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计