1、攻击原理
多个进程在同一物理核心上执行时,它们共享一个BPU。BPU由两种结构组成:分支目标缓冲器(BTB)和方向预测器。
(1)BTB
①条件分支的目标仅在执行该分支时更新,可以利用这一点来检测是否采取了特定的受害者分支
②基于攻击者填充BTB,导致属于受害者的条目被驱逐
③观察未来访问的时间[3],攻击者可以推断出受害者执行的新分支
④创建BTB冲突,从而允许攻击者绕过地址空间布局随机化,发现特定受害者分支指令在地址空间中的位置
⑤利用BTB冲突来发现受害者的分支指令方向。他们展示了针对英特尔SGX飞地的内核空间攻击
(2)方向预测器
①BranchScope强制攻击者和选定的受害者分支之间发生冲突,并利用这些冲突来推断有关受害者分支的信息
1)前提
a.受害者减速
b.触发受害者代码执行
c.在同一物理核心上共同居住
d.攻击者必须能够在其分支和PHT中受害进程的分支之间造成冲突
e.攻击必须强制攻击代码和受害者代码使用1级预测器
a)确保最近没有遇到攻击使用的分支
b)使2级预测器不准确并延长其训练时间
i.分支的方向是随机选择的,没有分支间的依赖关系
ii.执行的分支不能包含任何可由2级预测器预测的规则模式
f.攻击应该在受害者分支之前启动PHT条目,并在分支之后探测它以推断分支方向
g.分支预测器在处理器上的行为与这个简单的教科书模型一致
h.确保在受害者执行攻击的第2阶段时,与目标分支对应的PHT条目处于攻击者所需的状态
2)提出的缓解措施
a.基于软件
a)通过算法消除分支结果对秘密数据的依赖性
i.然而,将这种保护应用于大型代码库是具有挑战性的,因此这种机制只能限于使用敏感数据运行的程序的关键部分。
b)从目标程序中消除条件分支
i.将此方法应用于依赖关系很少的简单分支很容易。然而,复杂控制流的转换(根据分支结果执行不同的代码)具有挑战性。目前还不知道是否有可能将真实世界的应用程序转换为无分支代码。此外,高度可预测的分支在转换时通常表现更差[10]。
b.基于硬件
a)PHT的随机化
i.BranchScope需要能够在PHT中创建可预测的冲突(例如,基于虚拟地址)。为了防止这种冲突,可以修改PHT索引功能以接收该软件实体特有的一些数据作为输入。
b)删除敏感分支的预测
i.由于并非所有分支指令都会泄露敏感信息,因此可以采取有利于这种观察的缓解方法。
c)划分BPU
i.以对BPU进行划分,使攻击者和受害者不共享相同的结构。例如,SGX码可以使用与正常码不同的分支预测器。或者,可以支持请求BPU的私有分区的机制[37]。通过分区,攻击者将失去与受害者创建冲突的能力。
d)其他
i.通过在性能计数器或定时测量中消除或添加噪声来消除攻击者准确测量分支结果的能力
ii.更改预测FSM,使其更加随机,从而干扰攻击者精确推断受害者分支方向的能力
iii.检测攻击足迹,并在检测到正在进行的攻击时调用缓解措施,如冻结或杀死攻击者进程。在攻击者破坏操作系统的SGX环境中,这可能很困难;或者,如果SGX代码检测到正在进行的攻击,则SGX代码可以决定重新映射自身或停止执行。
我们提出了BranchScope——一种新的侧通道攻击,攻击者通过操纵共享的方向分支预测器来推断受害者程序中任意条件分支指令的方向。
分支预测器的方向组件存储给定分支(取或未取)的预测,并且是以前工作攻击分支目标缓冲区(BTB)的不同组件。
BranchScope是第一个对定向分支预测器的细粒度攻击,扩展了我们对分支预测单元侧通道漏洞的理解。我们的攻击针对组织未知的复杂混合分支预测器。我们演示了攻击者如何迫使这些预测器切换到一个简单的1级模式,以简化方向恢复。我们在最近的几个 Intel CPU 上执行 BranchScope,并展示了对 SGX 飞地的攻击。
现代微处理器依靠分支预测单元(BPU)来维持跨条件分支向执行流水线的不间断指令传递。当多个进程在同一物理核心上执行时,它们共享一个BPU。尽管从利用率和复杂性方面考虑很有吸引力,但共享可能会为攻击者打开大门,使其能够操纵共享的BPU状态,创建侧通道,并获得受害者进程执行的分支指令的方向或目标。这种泄漏可能会危害敏感数据。例如,当分支指令以密钥的一位为条件时,密钥位会直接泄漏。这发生在现代密码方案的**幂运算算法[13,32]和其他关键数学运算[3]**的实现中。攻击者还可以改变预测器状态,从而改变其在受害者中的行为。
在现代微处理器上,BPU由两种结构组成:分支目标缓冲器(BTB)和方向预测器。先前的工作专门针对BTB创建侧信道[1,3,21,35]。在BTB中,条件分支的目标仅在执行该分支时更新;可以利用这一点来检测是否采取了特定的受害者分支。该领域的第一次攻击提出了几种基于BTB的攻击,这些攻击基于攻击者填充BTB,导致属于受害者的条目被驱逐。通过观察未来访问的时间[3],攻击者可以推断出受害者执行的新分支。我们在相关工作部分描述了这些攻击及其局限性。在其他工作[21]中,我们最近提出了一种对BTB的侧通道攻击,该攻击在受害者和攻击者进程之间创建BTB冲突,从而允许攻击者绕过地址空间布局随机化,发现特定受害者分支指令在地址空间中的位置。Lee等人[35]在这项工作的基础上,利用BTB冲突来发现受害者的分支指令方向。他们展示了针对英特尔SGX飞地的内核空间攻击。
在本文中,我们提出了一种新的微架构侧通道攻击,我们称之为BranchScope,它将定向预测器作为信息泄漏的来源。据我们所知,BranchScope是第一个利用定向预测器结构的攻击,表明即使BTB受到保护,BPU也可能很脆弱。BranchScope的工作原理是强制攻击者和选定的受害者分支之间发生冲突,并利用这些冲突来推断有关受害者分支的信息。
这种攻击具有BTB攻击中没有的新挑战。为了实现碰撞,我们必须克服现代CPU中使用的复杂混合预测机制的不可预测性。BranchScope通过生成分支模式来克服这一点,即使处理器中存在复杂的多级预测器,分支模式也会迫使分支预测器选择本地一级预测。其次,在可靠地创建冲突之后,攻击者可以通过执行具有预定义结果的一对分支,测量这些分支的预测精度,并将该信息与预测器状态相关,从而与受害者分支的方向相关,来稳健地公开受害者的分支方向。
我们在三个最新的英特尔x86_64处理器上演示了BranchScope——Sandy Bridge、Haswell和Skylake。要执行BranchScope,攻击者不需要对分支预测器操作的细节进行逆向工程,只需要从用户空间对预测状态机执行简单的操作。我们还演示了如何将BranchScope扩展到攻击SGX飞地,即使最近提出的保护措施得到了实施。我们展示了BranchScope可以在超线程核心之间执行,推进了先前演示的基于BTB的攻击,该攻击仅在调度在同一虚拟核心上的进程之间泄露信息[21]。此功能放宽了攻击者的进程调度约束,从而实现更灵活的攻击。最后,我们描述了在未来系统中防止BranchScope攻击的对策。
最近的Meltdown[36]和Spectre[34]攻击表明,推测执行容易受到侧通道攻击,直接影响当前系统的安全并导致数据泄露。分支预测器对这些攻击至关重要,因为攻击者必须误传,甚至直接污染(称为分支中毒攻击)分支预测器,以迫使预测器猜测受害者选择的易受攻击代码的地址。Spectre中提出的分支中毒攻击基于与BranchScope相同的基本原理——利用分支预测器数据结构中不同分支指令之间的冲突。在这种情况下,我们认为BranchScopecan为攻击者提供了额外的工具,让他们可以使用推测来执行更高级、更灵活的攻击。作为社区考虑防御这些攻击,BranchScope中列出的漏洞也必须得到解决。总之,本文的主要贡献和主要成果是:
我们提出了BranchScope——第一种明确针对通过定向分支预测器提取敏感信息的侧信道攻击(与针对分支目标缓冲区的现有工作相反)。BranchScope不受基于BTB的攻击防御的影响。
我们证明,在存在系统噪声的情况下,BranchScope在三代英特尔处理器的用户空间中可靠高效地工作,错误率低于1%。
我们证明了BranchScope可以自然地扩展到攻击SGX飞地,其错误率甚至比传统系统更低。
我们描述了减轻BranchScope的硬件和软件对策,提供了对侧信道攻击安全的分支预测单元。
现代分支预测器[15,31,41,43,50]通常由程序计数器直接索引的简单一级双峰预测器(我们称之为一级预测器[49])和gshare风格的二级预测器[57]组成。类似gshare的预测器利用了分支结果取决于最近分支的结果的观察结果,而不仅仅取决于分支的地址。由分支地址索引的选择器表基于预测器的先前行为来识别哪个预测器可能对特定分支执行得更好。这种设计结合了两个分支预测器的最佳特性。
图1说明了这种混合预测器的一种可能的设计。1级预测器将其历史以2位饱和计数器的形式存储在模式历史表(PHT)中。gshare预测器有一个更复杂的索引方案,它将程序计数器与全局历史寄存器(GHR)相结合。GHR记录程序执行的最后几个分支的结果。分支历史信息也使用2位饱和计数器存储在PHT中;这两个预测器之间的唯一区别是PHT如何被索引。
如果预测要采用分支,则从称为分支目标缓冲区(BTB)的结构中获得分支的目标地址,BTB是一个简单的地址直接映射缓存,存储映射到每个BTB条目的分支的最后目标地址。已公布的对BPU的侧信道攻击(如第11节所述)均以BTB为目标。相反,BranchScope以BPU的方向预测单元为目标。
我们的攻击假设存在一个受害者和一个间谍程序。受害者程序包含间谍程序试图推断的秘密信息,而无权直接访问这些信息。威胁模型有三个主要假设:
在同一物理核心上共同居住:我们假设受害者和间谍程序在同一个物理核心上运行,因为BPU是在虚拟核心级别共享的。先前的工作[21]已经显示了强制这种共同居住的可能技术。
受害者减速:要执行高分辨率BranchScope攻击,我们能够检测分支的单个执行行为,受害者进程需要减速。这种减速是高分辨率侧通道攻击的常见要求[26,33]。减缓受害者的速度是一个正交问题,可以通过多种方式来实现,例如,通过利用Gullasch等人[26]提出的Linux调度器或执行微体系结构性能降级攻击[4]。重要的是,在恶意操作系统攻击SGX隔间的威胁模型中,操作系统可以精细地控制调度,以减缓受害者的速度。
触发受害者代码执行:我们假设攻击者可以启动受害者进程的代码执行,从而迫使受害者随时执行目标易受攻击的操作。这一假设适用于许多由外部输入触发的应用程序。例如,考虑一个发送加密数据的服务器;攻击者可以通过向该服务器发送请求来触发该服务器的响应。我们不认为攻击者可以观察受害者的响应内容。
我们认为,这三个假设适用于大量现实的攻击场景,使BranchScope与其他侧通道攻击一样,对现代系统构成严重威胁。在本文的后面,我们通过在一个真正的基于SGX的平台上演示BranchScope来支持这一说法。
在本节中,我们将介绍BranchScope的概述。我们从攻击的背景信息和高级概述开始,然后转到细节。
一般来说,攻击过程如下:
阶段1:对PHT条目进行预处理。在此阶段,攻击者进程将目标PHT条目初始化为指定状态。这种启动是通过执行精心选择的随机分支指令块来完成的。此块是由攻击者一次性、先验地生成的。
阶段2:处决受害者。接下来,攻击者启动它打算在受害者进程中监视的分支的执行,并等待,直到受害者的活动更改PHT状态。
阶段3:探测PHT条目。最后,攻击者针对与受害者相同的PHT条目执行更多分支指令,同时对它们进行计时以观察其预测结果。攻击者将预测结果与PHT的状态相关联,以识别受害者分支的方向。
攻击者必须能够在其分支和PHT中受害进程的分支之间造成冲突。在已知预测器操作的情况下,这些碰撞使攻击者能够发现受害者分支的方向。具体地,通过观察该分支(在上面的阶段2中执行)对在阶段3中执行的攻击者探测分支的预测精度的影响。如果PHT索引严格由指令地址确定(如在1级预测器中),则在两个进程的分支之间的PHT中创建冲突是直接的,因为受害者代码的虚拟地址通常不是秘密。如果使用地址空间布局随机化(ASLR)来随机化代码位置,则攻击者可以使用数据公开[48]或对ASLR的侧信道攻击[21,24,28,30,54]来解随机化。
BranchScope需要以下两种能力:
建立冲突。攻击依赖于在预测器内生成冲突。如果使用的预测器是简单索引的1级预测器,而不是更复杂的类似gshare的预测器,那么创建冲突将大大简化。攻击必须强制攻击代码和受害者代码使用1级预测器。
Prime Probe策略。在攻击者强行在PHT中发生碰撞后,她仍然需要能够解释PHT的状态,以确定受害者分支的方向。因此,我们需要了解如何在阶段1中使特定PHT进入所需的启动状态。这种启动状态必须使我们能够将阶段3中攻击者的探测操作的一些可观察行为与受害者分支的方向关联起来。
在接下来的两节中,我们将解释攻击者是如何实现这两个目标的。
BranchScope建立冲突的策略是强制间谍代码和受害者代码都使用1级预测器,这使得使用的PHT条目成为分支地址的一个简单函数。我们从一个实验开始,该实验演示了选择逻辑是如何工作的,然后使用这些观察结果来强制对我们的目标分支使用1级预测器。我们在三款最新的英特尔处理器上进行了这些实验:基于Skylake微架构的i5-6200U、基于Haswell微架构的i7-4800MQ和基于Sandy Bridge微架构的iq-2600。
硬件内的选择逻辑尝试选择更准确的预测器。为了深入了解这种选择是如何在2级预测器学习分支执行模式时进行的,我们进行了以下实验。来自同一分支指令的不规则但重复的分支结果序列不能由简单的1级预测器准确预测,因为分支结果不是前两个分支的函数。然而,一旦历史被初始化,这样的序列就可以由2级预测器预测。为了了解学习过程的进展速度以及在1级预测器上选择类似gshare的预测器的速度,我们在两款最新的英特尔处理器上进行了以下实验:基于Skylake微架构的i5-6200U和基于Haswell微体系结构的i7-2600。
我们将10位的数组初始化为随机选择的状态。这个位模式用于控制在我们的实验中是否采用分支。
我们以数组位为条件执行单个分支指令,每个位执行一次。我们连续重复该系列分支20次,并记录每次迭代中该分支序列中错误预测的总数。我们使用硬件性能计数器来跟踪预测,从而能够以单个分支预测失误的分辨率进行准确的测量。
一个1级预测器平均不能预测超过50%,但一个gshare风格的预测器最终应该学会这种模式。
该实验的预测精度(多次运行的平均值)如图2所示。从图中可以看出,在执行第一次迭代时,预测失误率约为50%(十分之五的分支预测失误)。该结果是预期的,因为在该阶段,2级预测器不具有任何先前状态,而1级预测器原则上不能预测这种模式。作为分支模式重复执行,分支预测失误率降低,因为2级预测器结构积累了更多的历史。当分支模式重复约5-7次时,预测精度接近100%并保持在该值。两个CPU都表现出了类似的行为,Skylake处理器学习模式的速度稍快。
这些结果表明,最终(在5-7次迭代或50-70次执行分支之后)对于该模式,仅使用2级预测器。然而,当第一次遇到分支时,使用了1级或2级预测器,但没有有效地进行预测。
接下来,我们关注预测器的初始行为(图2中的早期迭代)。我们推测,对于信息没有存储在预测器历史中的新分支,使用1级预测器。这一假设直观上是有道理的,因为与简单的1级预测器相比,2级预测器需要更长的时间来学习分支模式。例如,如果执行循环末尾的“几乎总是执行”分支,则1级预测器将在2-3次执行后收敛到“强执行”状态。另一方面,2级预测器将对分支的每个实例使用不同的历史寄存器值,从而使用不同的PHT条目,使其收敛速度明显较慢。我们进行了实验来验证1级预测器在没有历史记录的分支中的使用,并发现它适用于所有三个英特尔平台。当可以简单地基于分支地址建立冲突时,我们可以检测1级预测器的使用。
我们现在将讨论如何使用从之前的实验中收集的知识,以迫使硬件为攻击者和受害者代码选择1级预测器。
攻击者代码。我们观察到,新分支直接在攻击者代码中使用1级预测器来强制使用1级预测器:我们在分支预测器中与受害分支冲突的地址处循环放置多个分支(如果也使用1级预接器),这样在任何时候,BPU中都不存在正在使用的攻击分支,迫使单元使用1级预测器。
受害者代码。更困难的任务是强制受害者代码使用1级预测器;受害者代码不在攻击者的控制之下。为了迫使BPU对目标受害者分支使用1级预测器,攻击者需要实现两个目标之一:1)确保最近没有遇到攻击使用的分支,从而从1级模式开始对这些分支进行预测;2) 使2级预测器不准确并延长其训练时间,迫使选择器至少对几个分支选择1级模式。因此,攻击者必须确保这两个属性中至少有一个(如果不是同时存在的话)成立,才能强制受害者代码使用1级预测器。
我们通过开发一系列分支密集型代码来实现这一目标,攻击者执行这些代码来将BPU驱动到降低2级预测精度并可能替换受害分支的状态。执行该序列的结果是,受害者代码在执行其分支时将使用1级预测器,从而使我们能够实现冲突。该代码具有另一个关键功能:它强制PHT条目进入所需状态,使我们能够根据预测FSM的操作可靠地检测分支结果(在下一节中进行反向工程)。为了最大限度地提高其效率,随机化代码必须具有两个属性。
首先,执行的分支不能包含任何可由2级预测器预测的规则模式。为此,代码中分支的方向是随机选择的,没有分支间的依赖关系。其次,代码必须影响PHT中的大量条目。这是通过执行大量的分支指令并通过在它们之间放置或不放置NOP指令来随机化这些指令的存储位置来实现的。结果模式只随机化一次(当生成块时),并且在执行期间不会重新随机化。必须在受害者执行目标分支之前(在攻击的第1阶段期间)使用分支预测器执行这些操作。
需要以这种方式执行的分支指令的总数取决于特定CPU上BPU内部数据结构的大小。我们通过实验发现,执行100000条分支指令足以随机化大多数PHT条目的状态,并有效地禁用2级预测器。清单1中给出了这样一个代码的示例。减少此代码的大小是未来研究的主题;例如,如果我们只关注驱逐一个特定的分支,我们可能能够找到映射到同一PHT的较短的分支序列,并替换该条目。
在开发了一种可靠的方法来建立攻击者和受害者之间的冲突后,下一个任务是了解预测逻辑的操作,以开发一种使我们能够推断受害者分支方向的主探测策略。攻击应该在受害者分支之前启动PHT条目,并在分支之后探测它以推断分支方向。预测器结构的核心是一组产生预测决策的有限状态机(FSM)。通常,为PHT表中的每个条目维护这些FSM中的一个。组合预测器结构中的1级和2级预测器都使用相同的FSM逻辑,甚至可能使用仅在对PHT的索引函数上不同的相同PHT。
我们从一个假设开始,即每个PHT条目都由一个教科书式的两位饱和计数器FSM组成,该FSM具有四种状态:强取(ST)、弱取(WT)、弱不取(WN)和强不取(SN)。我们生成了几个针对同一PHT的分支指令,并观察结果预测(图3)。我们注意到,状态机在这些处理器上的实际实现是未知的,并且可能更复杂。例如,该实现可以包括附加的状态转移,并且可以依赖于来自其他CPU数据结构的输入。然而,我们发现分支预测器在处理器上的行为与这个简单的教科书模型一致。
考虑以下三个步骤,其中在一个进程中执行一个以前没有历史记录的测试分支。这基本上模仿了我们的三个攻击阶段,但在同一过程中。首先,我们执行前面提到的分支指令三次,通过将相应的PHT条目置于强状态之一(ST或SN)来初始化它。其次,我们再次执行同一分支,同时获得和未获得结果(在两个单独的试验中)。这被称为目标阶段,类似于攻击的第二阶段。最后,我们再执行两次相同的分支来检测预测失误(我们称之为探测阶段,类似于攻击的第3阶段)。在这个阶段,我们还记录了两个探测分支中每一个的预测精度。
表1描述了我们对所有可能情况的观察结果。例如,考虑有问题的分支被执行了三次而没有得到结果的情况(主要阶段)。期望此活动将FSM转换为SN状态。当在目标阶段执行一次带有结果的分支时,FSM切换到WN状态。最后,在探测阶段,分支被执行两次,但没有得到结果。在这种情况下,在探测阶段执行的第一分支将被错误预测,而第二分支将被正确预测。相反,如果不采取目标阶段中的分支,FSM将保持在SN状态。在这种情况下,探测阶段的两个分支都会被预测错误。因此,通过在探测阶段观察两个分支的预测结果的差异,攻击者可以确定受害者分支在目标阶段的方向。这是BranchScope利用的关键观察结果。
根据表1,可以通过用相同的分支指令执行两个单独的探测来确定PHT状态,结果为已执行和未执行。例如,假设当用两个已取分支(TT)进行探测时,观察到的两个探测分支的预测模式是两次命中(HH),而当用两条未取分支(NN)进行探测则是两次预测失误(MM)。在这种情况下,我们可以得出结论,有问题的PHT条目位于强取(ST)状态(表1中的第1行和第2行)。请注意,我们在Skylake处理器中发现的一个特性使强取(ST)和弱取(WT)状态在该处理器上无法区分。然而,这一限制并不妨碍承认其他状态。它也不能阻止BranchScope对Skylake的攻击,因为攻击者总是可以选择一个PHT随机化代码,将目标PHT条目置于没有这种模糊性的状态。
执行随机分支指令块(清单1)允许攻击者强制受害者代码使用1级预测器,正如我们在上一节中所讨论的那样。然而,精心选择的随机化代码也可以使目标PHT条目进入攻击者所需的状态。
为了更好地理解PHT随机化的性质和系统噪声的影响,并为我们的攻击选择适当的随机化代码,以可靠地将PHT条目置于攻击者指定的状态,我们进行了一个由10000次迭代组成的实验。在每次迭代中,我们生成一个新的随机化代码块,然后执行以下活动1000次:a)执行生成的分支块,b)对固定地址执行PHT探测操作。对于探测操作,我们考虑了两种情况:1)两个已采取的分支,以及2)两个未采取的分支。对于每次迭代,我们为每个探测模式收集了1000个测量值,并确定了PHT状态的统计分布。
为了收集统计概况,我们只考虑了产生稳定PHT状态的迭代。我们假设,如果探测代码的两种变体中最频繁的预测模式发生在85%以上的时间(在1000次执行中),则结果是稳定的。同样,由于各种系统影响,在执行相同的随机化代码之后,PHT条目的状态并不总是相同的。结果表明,大多数随机生成的分支代码块都会产生稳定的PHT状态,探测代码的两种变体的模式分布(以及截止点)如图4a所示。图上的每个点表示每个PHT随机化代码块(实验的每次迭代)的探测代码的最频繁预测模式的百分比。每个迭代由图上的一个点来描述,其中x轴表示TT探测代码的最频繁预测模式的百分比,而y轴表示NN探测代码的最高频率预测模式。从图中可以看出,83%的所有随机化代码块导致两个探测代码序列的稳定的显性预测模式。可以使用表1将稳定模式转换为探测分支地址所针对的PHT条目的FSM状态之一。然而,当预测模式不稳定(对于任何一种探测组合,最频繁的模式出现的次数都不到85%)。我们假设,由于预测器上的各种系统级影响,例如2级预测器的调用,或者由于一些间歇性处理,随机化代码继承的不同PHT状态,实验的这种特定迭代过于嘈杂。在这种情况下,我们认为测量结果不可靠且噪声过大,并从我们收集的统计数据中删除此特定迭代。在下面的花图中,我们将这些情况分类为未知情况。
图4b描述了探测分支所针对的PHT条目的解码PHT状态的分布。除了具有不同模式的四种标准稳定状态外,我们还观察到另一种具有稳定行为的模式。该附加模式由探测代码中的两个正确预测(HH)组成,而与探测类型无关。这样的模式指示PHT随机化码对目标分支没有影响,并且BPU总是能够产生正确的预测。这可能表示该分支使用了2级预测器。我们称这种情况为肮脏。
要实现BranchScope,攻击者需要确保在受害者执行攻击的第2阶段时,与目标分支对应的PHT条目处于攻击者所需的状态。攻击者不能简单地随意设置此状态,因为她需要在第1阶段结束时执行PHT随机化代码,从而重置整个PHT。然而,攻击者可以使用上述分析随机生成随机化PHT的代码块,直到找到使目标PHT条目处于所需状态的代码块。找到合适的随机化代码是攻击者一次性完成的工作,可以在攻击前阶段执行。这是BranchScope的一个关键元素。
我们现在可以在预测器行为和目标阶段中分支的方向之间创建映射。主要结论是,一个过程可能仅通过检查两个探测分支是否被正确预测来确定目标分支的方向。
知道与不同内存地址相关联的PHT条目的状态可能会使攻击者在单个执行事件中监视受害者进程中的多个分支指令。为了进行这种侵略性攻击,对手需要了解PHT组织的一些细节。为此,我们进行了以下实验。
首先,我们执行随机化代码来设置PHT的初始状态。接下来,对于给定范围的虚拟地址,我们在每个地址放置一条分支指令并执行这些分支。最后,我们评估与每个已放置分支指令。PHT状态是以与我们之前的实验类似的方式确定的,使用将探测代码的预测结果翻译为PHT状态的字典。这个实验使我们能够探测整个PHT。图5a展示了将分支指令放置在从0x300000到0x30010f的虚拟地址范围内时的结果。从图中可以看出,两个相邻的地址可以处于不同的状态。实验表明,PHT索引函数的粒度是单个字节。
PHT探测数据可以用于发现PHT的大小。假设PHT指数是用简单的模运算计算的,那么对PHT大小进行逆向工程的任务是微不足道的。观察到的模式在每个N个地址之后重复,其中N是PHT的大小。我们利用这一见解在我们的实验机器上发现了PHT的大小。所有测量的状态都表示为状态向量:
向量V可以划分为大小为w的等长子向量。我们将w称为窗口大小。那么,Sw是包含大小为w的所有子向量的集合:
函数H(w)表示在Sw:
其中D(x)是两个向量之间的汉明距离。基于此,PHT的大小可以定义如下:
如果得到的函数具有几个局部极小值,则选择w值最低的值。为了找到PHT的大小,我们从 2 16 2^{16} 216个连续地址中获得了测量值。然后,我们测试了从2到 2 16 2^{16} 216的所有可能的窗口大小,并计算了比率H(w)/w。为了加快进程,并不是在尝试所有可能的排列之后,我们为每个窗口大小计算了100个随机排列的汉明距离。显示比值最小值的结果如图5b所示。对于窗口大小214,获得了最小值。因此,我们得出结论,PHT的大小为16384个条目。图5c展示了以对齐形式收集的数据,使得每行中的项目映射到相同的PHT条目。可以清楚地观察到重复的模式。
基于上述步骤,在本节中,我们构建并评估实际攻击。BranchScope由一个间谍进程组成,该进程执行prime(阶段1)并触发被攻击的受害者进程执行(阶段2)。然后间谍执行探测(第3阶段)以完成攻击。我们假设间谍可以减慢受害者进程的速度,以便在上下文切换期间执行单个分支指令。在这种调度场景中,间谍可以启动,然后允许受害者执行单个分支,然后进行探测。在标准情况下,可以使用[26]满足这一要求。在SGX飞地和许多其他隔离执行解决方案[12,16,17,53]的情况下,由于SGX威胁模型假设攻击控制操作系统,因此很难满足这一要求。
为了证明这种攻击,我们首先进行了一个秘密通道实验。首先,我们生成一个大的随机位数组。此数组加载到受害者进程的地址空间(间谍无权访问此数组)。受害者重复执行分支指令,其结果取决于存储在数组中的值(如清单2所示)。清单2(B)显示了被分解的受害者代码的相关部分。当if条件的值为零时,将执行分支。spy的伪代码如清单3所示。间谍的任务是确定秘密数组的内容。spy程序的核心是spy_function(),它执行单个分支指令(在if语句中),并记录与该分支相关的预测数据以供将来分析。为了在PHT结构中实现间谍分支与受害者分支的冲突,我们在两个进程中将两个分支指令放置在相同的虚拟地址。这确保了当BPU使用1级预测器时,两个分支将被映射到同一PHT条目。为了获得受害者分支的更多方向,从执行随机化将PHT条目置于所需初始状态并关闭2级预测机制的代码块。
攻击者进程依赖硬件性能计数器[51]来精确检测正确和不正确的预测事件。如果无法访问性能计数器,也可以使用时间戳计数器进行计时测量,我们将在下一节中对此进行讨论。间谍提取一系列分支预测失误值,并对该序列进行解码,以确定受害者的分支方向。例如,如果攻击者观察到一个由两个预测错误的分支组成的序列,或者一个预测正确,一个预测错误,则受害者分支被检测为已执行,否则不执行。图6给出了隐蔽通道中数据泄漏的示例。该图还显示了错误接收的比特。请注意,我们在本实验中使用的模式词典扩展了很少观察到的预测错误模式,以便包括所有四种可能的组合。
为了测量隐蔽信道上的这种错误率,我们使用它来传输100万个比特,一次所有比特都设置为0,另一次全部设置为1,第三次随机选择比特值。对于每个位,我们执行取决于位值的分支条件,无论是已取还是未取。攻击者被安排在与受害者进程相同的核心上。将攻击者收集的比特与原始比特进行比较,并计算错误率。我们在两种设置下,在英特尔最新的三个x86_64处理器上进行了这个实验——Skylake、Haswell和SandyBridge。在第一个设置中,基准测试被安排在一个独立的物理核心上,没有其他用户进程运行。在第二种情况下,没有设置任何限制。由于我们实验机器上的每个物理内核都有两个硬件线程上下文,因此在这种嘈杂的环境中,其他正常的系统活动也同时在内核上执行。
我们进行了10次上述实验,并计算了平均速率。结果如表2所示。BranchScope在两个处理器上都具有出色的精度,在Skylake和Haswell上的结果略好。即使存在外部噪声,Skylake和Haswell处理器也显示出非常低的错误率。这可以通过与旧的Sandy Bridge处理器相比,改进的分支预测器设计[46]中的预测器表的大小更大来解释。
BranchScope攻击所需的一个关键功能是检测分支预测器事件的能力。在第7节中,我们使用硬件性能计数器来检测遗漏的分支。这种方法依赖于硬件明确地提供分支预测结果。然而,为了利用这一点,攻击者需要至少部分提升权限。
另一种方法是通过观察分支对CPU性能的影响来检测与分支相关的事件。错误预测的分支会导致获取错误的路径指令,并导致重新启动管道的重要周期丢失。因此,攻击者可以跟踪循环数,以确定是否正确预测了分支。这种计时可以通过英特尔处理器上的rdtsc或rdtscp指令来实现。这些指令为用户进程提供了对计时硬件的直接访问,绕过了系统软件层。
BranchScope攻击要求攻击者检测分支执行的单个实例的预测是正确的还是不正确的,而不是依赖于聚合BPU性能。为了评估rdtscp指令作为我们攻击目的的可靠测量机制的适用性,我们进行了一系列实验。首先,我们收集了两种情况下正确和错误预测的单个分支指令的时间测量值:执行分支和未执行分支。每宗个案均收集了10万份样本。结果数据以及计算的平均值如图7所示。未取得实际分支结果的情况如图7a所示,而取得结果的情况则如图7b所示。从图中可以看出,分支预测失误会对性能产生显著影响,而且无论分支的实际方向如何,这种影响都会存在。放缓在各个数据点以及平均值中都很明显。为了消除缓存对这些测量的影响,我们对每个分支实例执行了两次,但只记录了指令放入缓存后第二次执行期间的延迟。
具体来说,当BP正确预测结果(预测命中)时,我们记录了连续执行两次的单个分支指令的延迟。我们将这种测量称为H1和H2。然后,我们对方向预测错误的情况进行了相同的测量。我们将这些测量称为M1和M2。由于预测错误的分支的延迟必须高于正确预测的延迟,因此我们可以将分支事件检测错误率计算为H1>M1或H2>M2时的情况百分比。我们分别为首先进行第二次测量。此外,为了摊销噪声,我们收集了多个测量值并计算了平均值,而不是依赖于单个时间测量值。结果如图8所示。正如预期的那样,第一次测量的错误率更高(由于缓存效应),在20-30%的范围内。当使用单个测量时,第二测量具有约10%的低错误率,并且随着测量次数接近10,第二次测量进一步减少到几乎为0。
这些结果证明了使用rdtscp指令作为分支事件检测机制进行时间测量的可行性。尽管在分支的第一次执行中正确检测事件很有挑战性,但这并不影响BranchScope攻击,因为攻击者可以仅根据对第二次分支执行的观察,将PHT条目置于显示受害者分支结果的状态。为了说明这一点,请考虑与受害分支相关联的PHT条目的状态为强获取(ST)并且攻击者使用未获取分支进行探测的情况。如果采用了受害者分支的结果,那么攻击者将观察到MM模式。当受害者的分支结果没有被采纳时,间谍会观察到MH模式。因此,为了揭示受害者分支的方向,只有第二分支执行的观察结果才是相关的。
图9展示了PHT进入的不同状态如何影响探测分支的时间。该图以所有四种状态和两种探测类型的测量为特征,还描绘了每个结果的标准偏差。从图中很容易看出,使用时间测量可以可靠地区分PHT状态。
BranchScope可以直接用于针对支持隔离执行的系统,如Intel的SGX[42],也可以在传统环境中用作一般的侧通道攻击。在本节中,我们首先概述英特尔SGX和在这种环境中的攻击注意事项,然后描述即使受害者在SGX飞地内运行,也可以对其进行一系列特定攻击。
英特尔的软件保护扩展(SGX)是一种基于硬件的独立执行系统,旨在保护应用程序机密,使其免受操作系统内核和管理程序等系统软件的破坏。x86-64 ISA的SGX扩展为应用程序提供了一组指令,这些指令可用于启动嵌入应用程序地址空间内的安全飞地。对包围区内存的访问由SGX硬件控制,以防止来自包围区外部的访问。因此,如果应用程序将敏感代码和数据存储在飞地内,那么即使是系统软件也无法访问这些机密。
除了为飞地内存页提供运行时访问控制外,SGX还支持内存加密和完整性检查机制,以提供针对内存物理攻击的保护。SGX是业界为安全和可信计算,并且目前是大量研究的主题。
诸如SGX之类的孤立执行环境可能容易受到侧通道攻击。虽然内存受到保护,但许多CPU硬件资源仍然在飞地代码和非飞地代码之间共享。由于两个原因,孤立执行环境中的侧通道威胁可能更加严重。首先,用户倾向于更加信任声称具有高级安全功能的系统[5]。其次,威胁模型假设攻击者完全控制系统软件。这意味着攻击者可以完全控制飞地的调度,能够控制来自预取器、缓存以及其他工作负载的噪声。OS还可以控制其他参数,例如CPU核心频率、页面转换、低级别性能计数器和许多其他会增加噪声的功能。最近的几部作品详细研究了这个问题。例如,Moghimi等人[44]研究了SGX如何“放大”已知的缓存攻击,使孤立的实体极易受到此类攻击。Schwarz等人[47]演示了SGX如何用于隐藏缓存攻击,使反恶意软件,即使是在内核级别运行的软件,也无法检测缓存侧通道攻击。最后,SGX飞地被证明容易受到传统缓存侧信道攻击[22]以及SGX特有的一些新攻击,特别是页表侧信道攻击[54]。
在SGX环境中,对操作系统的控制使攻击者能够在低噪声环境中执行BranchScope攻击。攻击的成功很大程度上取决于以精确的时间执行分支操作的能力。攻击者控制的操作系统可以很容易地操纵受害者的执行时间。例如,攻击者可以配置高级可编程中断控制器(APIC),使飞地代码在执行多条指令后中断[35]。或者,当飞地执行某些代码时,攻击者可以取消映射某些内存页以强制中断[54]。
对SGX的隐蔽通道攻击:为了说明在SGX环境中的BranchScope,我们重复我们的隐蔽通道基准测试,其中发送方在SGX包围区内运行,使用BranchScope与SGX外部的接收方通信。表3说明了BranchScope的隐蔽信道质量:即使在存在噪声的情况下,错误率也是可接受的;然而,当OS控制噪声(通过防止其他进程运行)时,信道的质量得到改善。
接下来,我们将概述使用BranchScope可以攻击的应用程序的其他示例。无论这些应用程序是照常运行还是在SGX飞地内运行,攻击都会起作用。
蒙哥马利梯形图:蒙哥马利梯形图是一种常用的模幂运算[32]和标量乘法[45]算法。这两种数学运算构成了传统RSA的关键组件,也构成了公钥密码的椭圆曲线(ECC)实现。Montgomery梯形图基于不管密钥k中的比特值ki如何都执行操作。该实现通过均衡执行路径来减轻定时和功率侧信道。然而,它需要一个直接依赖于ki值的分支。Yarom等人[55]演示了使用FLUSH+RELOAD缓存侧通道攻击的ECDSA密码的OpenSSL实现的漏洞。在这次攻击中,CPU缓存被用来监视目标分支的方向。BranchScope可以直接恢复该分支的方向。尽管最新版本的密码库不包含结果直接取决于密钥位的分支,但通常仍然可以恢复一些有限的信息[6,8],并且许多过时的库仍在使用中。
libjpeg:我们的攻击如何泄露敏感信息的另一个例子是对流行的JPEG编码/解码库libjpeg的攻击。由于在解压缩期间执行的反余弦变换(IDCT)操作,所以攻击是可能的。在该优化中,将系数矩阵的行和列中的元素与0进行比较以避免昂贵的计算。每个这样的比较被实现为单独的分支指令。通过监视这些分支,BranchScope能够恢复有关解码像素块的相对复杂度的信息。之前,通过计算可以应用优化的次数,使用页面故障侧通道[27,54]演示了对libjpeg的攻击,从而恢复原始图像。BranchScope攻击是有利的,因为它不仅可以区分所有行/列元素都为零的情况,还可以指示哪个元素不等于零。
ASLR值恢复:BranchScope还可以用于推断受害者包围区内的控制代码。攻击者不仅可以了解某个分支是否被占用,还可以通过观察分支冲突来检测受害者虚拟内存中分支指令的位置。这使攻击者能够绕过地址空间布局随机化(ASLR)保护。以前,使用BTB也证明了类似的攻击[21,35]。Gruss[23]指出,基于BTB的攻击在最近的英特尔处理器上不起作用。这使得方向预测器成为这类攻击的唯一候选者。
基于分支的攻击的根本原因是执行以机密数据状态为条件的分支指令。我们在本文中的目标是强调分支预测器单元中的这种新的泄漏源是漏洞的来源。在本节中,我们概述了针对BranchScope的几种可能的软件和硬件防御措施。探索这些防御是未来研究的一个有趣方向。
仅限软件的解决方案可能对分支预测器单元的底层组织高度敏感。除了侧通道威胁之外,恶意实体还可以使用BranchScope绕过现有限制在彼此之间进行通信。例如,密封的SGX包围区可能会将敏感信息传输到违反SGX系统安全属性的常规进程。软件缓解技术无法提供对秘密通道的保护,因为它们不能消除硬件中的泄漏源,使攻击者可以自由使用它进行秘密通信。
一种可能的缓解技术是通过算法消除分支结果对秘密数据的依赖性[3]。然而,将这种保护应用于大型代码库是具有挑战性的,因此这种机制只能限于使用敏感数据运行的程序的关键部分。
另一种适用性更广的可能方法是从目标程序中消除条件分支。这种被称为if转换[10]的技术是一种编译器优化,它使用条件指令(如cmov)将条件分支转换为顺序代码,有效地将控制依赖关系转换为数据依赖关系。如果转换删除了条件分支指令,则可以减轻BranchScope攻击。一些研究[9,11]使用if转换作为定时侧信道攻击的缓解措施。将此方法应用于依赖关系很少的简单分支很容易。然而,复杂控制流的转换(根据分支结果执行不同的代码)具有挑战性。目前还不知道是否有可能将真实世界的应用程序转换为无分支代码。此外,高度可预测的分支在转换时通常表现更差[10]。
分支预测器机制的设计可以重新安排,以减轻通过定向分支的泄漏预测器单元。在本节中,我们概述了几种可能的此类缓解措施。探索有效的缓解措施是未来研究的一个有趣方向。
PHT的随机化:BranchScope需要能够在PHT中创建可预测的冲突(例如,基于虚拟地址)。为了防止这种冲突,可以修改PHT索引功能以接收该软件实体特有的一些数据作为输入。例如,这可以是SGX硬件状态的一部分,也可以只是进程生成的一些随机数。一次性随机化可能容易受到探测攻击,该攻击逐个检查PHT条目,直到发现冲突为止;可以使用周期性随机化(牺牲一些性能)。该解决方案类似于随机化缓存映射,以防止侧信道攻击[52]。
删除敏感分支的预测:由于并非所有分支指令都会泄露敏感信息,因此可以采取有利于这种观察的缓解方法。软件开发人员可以指示能够泄露秘密信息的分支,并请求对其进行保护。然后CPU必须避免预测这些分支,始终依赖于静态预测,并避免在执行这些分支之后更新任何BPU结构。尽管这种缓解技术有负面的性能开销,但它为大多数安全敏感分支提供了完美的安全性。与软件技术一样,这种方法不能再次保护ts的隐蔽通道攻击。
划分BPU:可以对BPU进行划分,使攻击者和受害者不共享相同的结构。例如,SGX码可以使用与正常码不同的分支预测器。或者,可以支持请求BPU的私有分区的机制[37]。通过分区,攻击者将失去与受害者创建冲突的能力。
其他解决方案。其他解决方案也是可能的。例如,我们可以通过在性能计数器或定时测量中消除或添加噪声来消除攻击者准确测量分支结果的能力[39]。另一种解决方案可能会更改预测FSM,使其更加随机,从而干扰攻击者精确推断受害者分支方向的能力。最后,一类解决方案可能侧重于检测攻击足迹,并在检测到正在进行的攻击时调用缓解措施,如冻结或杀死攻击者进程。在攻击者破坏操作系统的SGX环境中,这可能很困难;或者,如果SGX代码检测到正在进行的攻击,则SGX代码可以决定重新映射自身或停止执行。
Acicmez等人进行了第一项研究,研究了基于分支预测器的侧信道。[1-3]:他们提出了四种不同的攻击,证明了它们可以对抗RSA加密标准的实现。第一种攻击通过模拟取幂步骤和测量取决于预测器先前状态的时间差来利用分支预测器的确定性行为。第二次攻击假设间谍过程与受害者一起在一个平行的虚拟核心上运行。间谍不断从BTB中删除受害者的条目,以迫使分支预测器将所有分支预测为未执行(假设BTB未命中导致未执行预测)。第三次攻击也是基于间谍用自己的数据填充BTB。这里的主要区别在于,这种攻击是同步的,这意味着攻击者可以在执行目标分支之前执行BTB填充。最后,在上一次攻击中,间谍也并行执行并填充BTB,但这一次,间谍不是测量加密算法的总执行时间,而是在受害者进程执行所采取的分支时检测其BTB条目的驱逐。后来,他们通过仔细调整BTB填充的强度,显著提高了最后一次进攻的准确性。这种攻击是最有趣的,因为它以高精度展示了实际结果。
上面描述的所有攻击都与BranchScope有很大不同。除第一次攻击(定时分析攻击)外,所有攻击都依赖于填充BTB(类似缓存的结构),因此类似于缓存侧通道攻击[38,56]。这使得应用现有的缓存保护技术[14,52]来保护BTB成为可能。相比之下,BranchScope利用了现代分支预测器的混合特性,并直接在方向预测器中操纵数据,从而打开了以前未探索的侧通道。分支预测器已在[19,20,29]中用于构建隐蔽信道。然而,这些工作依赖于没有研究细粒度分支方向恢复的可能性。Bhattacharya等人[7]考虑了对RSA的故障攻击,并结合对分支预测失误数量的分析。
最近的工作利用微结构特征来构建隐蔽通道[18,40]。这些通道允许攻击者绕过系统隔离,包括Intel SGX[25]。正如我们所展示的,BranchScope可以以类似的方式用于跨隔离边界传输信息。
在本文中,我们提出了BranchScope——一种新的微体系结构侧通道攻击,它利用定向分支预测器来泄露机密数据。我们演示了对最近英特尔处理器的攻击。我们的结果显示攻击者可以在不知道内部预测器组织的情况下以非常低的错误率恢复秘密比特。因此,研究人员和系统开发人员在设计未来系统时,必须将BranchScope视为一种新的安全威胁。我们提出了一些对策来保护未来的系统不受BranchScope的影响。