diff options
author | Iru Cai <mytbk920423@gmail.com> | 2019-04-24 13:51:32 +0800 |
---|---|---|
committer | Iru Cai <mytbk920423@gmail.com> | 2019-05-20 09:32:55 +0800 |
commit | adde669d4a9338ea4ecabbd7c0e1adb89a19c8fd (patch) | |
tree | fdd4883c6d7fe0409dc0db702de58c89b7c0d015 /chap | |
parent | 69d5aab97e3097947a31bf7772a4fa3bc54272db (diff) | |
download | dissertation-rev1.tar.xz |
thesis revision 1rev1
Diffstat (limited to 'chap')
-rw-r--r-- | chap/abs.tex | 64 | ||||
-rw-r--r-- | chap/ack.tex | 21 | ||||
-rw-r--r-- | chap/chap1.tex | 148 | ||||
-rw-r--r-- | chap/chap2.tex | 846 | ||||
-rw-r--r-- | chap/chap3.tex | 817 | ||||
-rw-r--r-- | chap/chap4.tex | 405 | ||||
-rw-r--r-- | chap/chap5.tex | 257 | ||||
-rw-r--r-- | chap/chap6.tex | 40 | ||||
-rw-r--r-- | chap/encl1.tex | 64 | ||||
-rw-r--r-- | chap/origin.tex | 2 |
10 files changed, 2635 insertions, 29 deletions
diff --git a/chap/abs.tex b/chap/abs.tex index 8dc8efc..81b1b10 100644 --- a/chap/abs.tex +++ b/chap/abs.tex @@ -2,11 +2,71 @@ % Public domain. \begin{cabstract} - %\pkuthssffaq % 中文测试文字。 + 现代微处理器设计主要需要考虑性能和功耗。但随着软硬件系统越来越复杂, + 安全性在处理器设计中越来越重要。熔断(Meltdown)和幽灵(Spectre)攻 + 击的发现,表明处理器微体系结构的优化,虽然不影响程序的正确运行,但是 + 可能带来安全性的问题。其中 Spectre 攻击利用处理器的推测式执行,通过 + 暂态指令的执行构造隐蔽信道,将程序中的秘密信息泄露给攻击者,破坏了程 + 序的安全保证和系统的隔离性。由于推测式执行是微处理器设计中提升性能的 + 重要手段,在防御 Spectre攻击的同时,减少防御手段带来的性能下降,是一 + 个重要的问题。 + + 本文基于模拟平台,针对推测式执行侧信道攻击设计实现了一种防御结构。主 + 要工作内容如下: + \begin{enumerate} + \item 调研 Meltdown 和 Spectre 攻击,分析其技术原理。 + \item 调研现有的 Meltdown 和 Spectre 防御方案,分析这些方案的设计思 + 想、实现方法、安全性和性能开销。 + \item 设计一种针对 Spectre 攻击的防御结构,并在模拟平台中实现。该结 + 构动态追踪信息流,检测推测式执行的指令与推测的内存读取之间的依赖关 + 系,标记存在数据泄露风险的指令。进一步地,针对有风险的内存读取指令, + 采用安全的数据装载方案,避免在高速缓存状态中留下暂态执行的痕迹。 + \item 基于模拟平台对该防御结构进行评估。利用构造的攻击程序进行测试, + 表明该防御结构可以防御测试中的攻击,满足安全性要求。利用 SPEC + CPU2006 进行性能评测,平均性能开销为 8.5\%,需要安全执行的推测式数 + 据读取显著减少,降低了防御的性能开销。 + \end{enumerate} \end{cabstract} \begin{eabstract} - %Test of the English abstract. + Performance and power consumption are the main factors of modern + processor design. As software and hardware systems become more and + more complex, security is becoming important in microprocessor + design. The disclosure of Meltdown and Spectre shows that + microarchitecture optimizations can bring security issues, although + the programs still run correctly. Spectre exploits speculative + execution, constructing covert channel with transient instructions, + and leak secret information to the attacker, breaking the security + guarentee of the program and system isolation. Since speculative + execution is an important method to optimize the performance in + microprocessor design, it's important to defend against Spectre + attack, while minimize the performance loss of the defense. + + This thesis designs a microarchitecture to defend against + speculation side channels based on the a simulation platform. The + contribution of this thesis is as follows: + \begin{enumerate} + \item Investigate on Meltdown and Spectre attacks, and analyze how + these attacks work. + \item Investigate on current defenses of Meltdown and Spectre + attacks, analyze their idea, implementation, security and + performance overhead. + \item Design a microarchitecture to defend against spectre attack + and implement it on a simulation platform. This microarchitecture + tracks the information flow, detecting the dependency of a + speculated instruction and a speculated data load from memory, and + tags the instruction which may leak data. For memory reads which + is likely unsafe, a safe loading mechanism is used, avoiding + leaving transient execution side effects in the cache. + \item Evaluate the microarchitecture on the simulation + platform. Tested with a constructed proof of concept code, this + microarchitecture design can defend the tested attacks, meeting + the security requirement. Evaluated with SPEC CPU2006, this + microarchitecture has an average performance overhead of 8.5\%, + and the number of speculated loads that need to be safely executed + is significantly decreased, thus the performance overhead of the + defence is smaller. + \end{enumerate} \end{eabstract} % vim:ts=4:sw=4 diff --git a/chap/ack.tex b/chap/ack.tex index 5e36e98..0287890 100644 --- a/chap/ack.tex +++ b/chap/ack.tex @@ -1,6 +1,19 @@ -% Copyright (c) 2014,2016 Casper Ti. Vector -% Public domain. - \chapter{致谢} -% vim:ts=4:sw=4 +三年的研究生学习生活就要结束了。在这三年中,我学到了不少知识,体验了研究生的工作和生活方式。在大家的帮助下,我完成了研究生的学习和毕业论文的写作,我想对各位帮助我的人表示感谢。 + +首先感谢我的导师,北京大学微处理器研究开发中心的主任,程旭老师。程老师在工作中充满热情,对专业领域的知识有深刻的见解。他教导我们如何做人、做事,我会牢记老师的教导,在以后的事业中继续努力。 + +感谢我的论文指导老师杨春老师。在这半年的时间里,在我论文的每个阶段,杨老师都给了我不少的指导和鼓励,让我一步一步写出一篇论文。 + +感谢我的班主任刘锋老师。在这三年的研究生生活中,他主持了我们年级的各种工作。在我遇到困惑的时候,他还给我提出不少有用的建议。 + +感谢易江芳老师和佟冬老师。我在这几年的学习过程中,参与过两位老师研究小组的工作,在其中学习到了很多知识,了解到最新的研究进展。 + +感谢刘先华老师、管雪涛老师、陆俊林老师,我在本科期间学过他们的课程,使我了解到了计算机系统结构这个领域,来到这个实验室学习和工作。 + +感谢陈东维师兄、胡永泉师兄、张衡师兄,还有高铮、李岗嶷、陶淼等同学。这几年他们在我的学习和生活中提供过不少帮助,他们认真工作的态度值得我学习。 + +感谢我的室友班义琨、庄月清、朱瑞同学,这几年我们在一起生活,互相帮助。我不会忘记这几年一起生活的时光。 + +感谢我的家人和朋友,他们一直支持着我。我会珍惜这种来之不易的缘分,对人生充满希望。 diff --git a/chap/chap1.tex b/chap/chap1.tex index 61fc289..bee1ea1 100644 --- a/chap/chap1.tex +++ b/chap/chap1.tex @@ -1,12 +1,158 @@ % Copyright (c) 2014,2016,2018 Casper Ti. Vector % Public domain. -\chapter{绪论} +\chapter{绪论}\label{sec:intro} + +本章首先介绍论文的选题背景,然后介绍论文的研究平台和环境,最后介绍论文的组织结构。 \section{选题背景与研究意义} +现代微处理器使用了超标量流水线、乱序执行等设计,通过利用程序内的指令级 +并行性,掩盖指令的延迟的方法,提高处理器的指令执行效率。 + +乱序执行是处理器对指令进行动态调度的技术,它允许一条指令在满足数据依赖 +后即可进入执行单元执行,而无需等待程序序列之前的指令。在乱序执行处理器 +中,处理器存在多个不同的执行单元,用于同时处理多个指令。处理器使用 +Tomasulo 算法\supercite{tomasulo},可以识别指令之间的依赖关系,允许无 +依赖关系的指令并行执行。 + +在乱序执行中,指令可以不按程序序列改变体系结构状态,在指令执行发生异常 +时,发生异常之后的指令可能已经执行,使得处理器无法在处理异常后,恢复异 +常发生时的体系结构状态。为了解决这个问题,处理器需要支持精确中断。现代 +处理器通常使用重排序缓冲区(ROB)\supercite{preciseint}实现精确中断, +它使得指令按序提交至体系结构状态中,如果异常发生,则丢弃未提交的指令的 +结果。 + +超标量处理器设计允许处理器平均没周期执行多于一条指令,它可以在一周期内 +同时分发多个指令至不同的执行单元,进一步开发了程序的指令级并行性。 + +程序中除了数据相关之外,还存在控制相关。程序中存在大量的分支指令,等待 +分支指令执行,则后续指令在分支指令执行期间均无法执行,降低了执行单元的 +利用率,导致总体性能下降。因此现代微处理器使用了推测式执行技术,在分支 +指令执行结束前,根据分支预测的结果,执行预测将要执行的指令。分支预测需 +要预测分支的方向和目标地址。处理器使用分支目标缓冲器(BTB)预测分支指令 +的方向和目标地址\supercite{btb}。为了预测函数调用的返回地址,处理器还使 +用栈结构的返回栈缓冲器(RSB)\supercite{rsb}。 + +为了开发出多任务系统的线程级并行性,部分处理器使用了多线程技术,使得一 +个处理器核可以执行多个线程。同时多线程(SMT)\supercite{smt}是一种多线 +程技术,它对超标量处理器做了少量修改,使得多个线程可以共用一组执行单元, +提高执行单元的利用率。 + +\begin{figure}[htbp] + \centering + \includegraphics[width=0.8\textwidth]{skylake.pdf} + \caption{Skylake 微体系结构示意图} + \label{fig:skylake} +\end{figure} + +图\ref{fig:skylake}是 Intel Skylake 微体系结构的示意图\footnote{图片来 + 自 https://mdsattacks.com/images/skylake.svg},它是一个乱序执行超标 +量处理器体系结构,每周期最多可以将 6 个微操作发射至 8 组执行单元中执行, +它的 ROB 使得流水线中可以同时存在 224 个微操作,它的分支预测器可以预测 +分支的方向和目标地址,使处理器在预测的目标处取出指令至指令缓存。 + +2018 年公布的“熔断”(Meltdown)\supercite{meltdown}和“幽灵”(Spectre) +\supercite{spectre} 攻击使人们发现,虽然处理器在执行指令产生异 +常,或推测式执行错误后,通过恢复可以使体系结构层次上的状态保持正确,但 +是这些错误执行的指令在微体系结构中产生了副作用,并且可能泄露系统中的秘 +密数据,破坏了系统的安全。在 Meltdown 和 Spectre 之后,研究者发现了更 +多相似的攻击种类,包括 Foreshadow\supercite{foreshadow}、 +Fallout\supercite{fallout}、RIDL\supercite{ridl}、 +ZombieLoad\supercite{zombie}。 + +面对这些新型攻击,Intel、AMD、ARM 等处理器设计厂商,和 Google、 +Microsoft 等软件厂商,均发布了软件补丁或处理器微码更新,用于减轻这些攻 +击的威胁。Intel 在后续的处理器中,也在硬件上对一些攻击做出了防御 +\supercite{intel-9900k}。当前的基于软件的防御方法,均对性能造成一定的 +损失,并且通常无法防御更新的攻击手段。表\ref{tab:perf_mitigation}列出 +了部分已有的软件和微码防御方法,它们所防御的攻击,和造成的性能损失。 +\supercite{systematic} + +\begin{table}[htbp] + \begin{tabular}{ccc} + \hline + 防御方法 & 防御的攻击种类 & 性能损失\tabularnewline + \hline + KAISER & Meltdown & 0-2.6\%\tabularnewline + Retpoline & Spectre v2 & 5\%-10\%\tabularnewline + IBRS/IBPB/STIPB & Spectre v2 & 20\%-50\%\tabularnewline + SSBD/SSBB & Spectre v4 & 2\%-8\%\tabularnewline + 串行化指令 & Spectre v1 & 62\%\tabularnewline + 推测式装载加固 & Spectre v1 & 29\%\tabularnewline + \hline + \end{tabular} + \centering + \caption{软件防御对性能的影响} + \label{tab:perf_mitigation} +\end{table} + +因此,通过改进微体系结构的设计,低开销地防御 Meltdown 和 Spectre 攻击, +具有重要的研究意义。本文的目标是设计一种微体系结构,防御 Spectre 攻击。 + \section{研究平台与环境} +本文使用 gem5 模拟器\supercite{gem5}作为研究平台。 + +gem5 是一个模拟平台,由 GEMS\supercite{gems} 和 M5\supercite{m5} 两个 +模拟器项目合并而成,同时具有这两个模拟器的优点。M5 提供了一个可配置的 +框架,支持多种指令系统和多种 CPU模型,GEMS 则提供了一个详细而灵活的存 +储系统,支持多种缓存一致性模型和互联模型。gem5 支持 X86, ARM, Alpha, +MIPS, RISC-V 等指令系统。作为一个开源的模拟器,学术界和工业界都为 gem5 +的开发做出贡献,使得 gem5 称为体系结构研究中最流行的模拟器之一。 + +\begin{figure}[htbp] + \centering + \includegraphics[width=0.8\textwidth]{gem5_cpu.pdf} + \caption{gem5 支持的 CPU 模型\supercite{gem5-tutorial}} + \label{fig:gem5_cpu} +\end{figure} + +gem5 的灵活性使得研究者可以根据需要选择不同的系统模型,取得模拟速度和精 +度的平衡。gem5 支持以下模型的配置: + +\begin{enumerate} +\item CPU 模型:如图\ref{fig:gem5_cpu},gem5 支持多种不同的 CPU 模 + 型。AtomicSimpleCPU 模拟一个单周期处理器,模拟速度最 + 快。TimingSimpleCPU 在此之上增加对存储访问时间的模拟。O3CPU 则是一个 + 详细的乱序执行处理器模型。此外,gem5 还支持使用 KVM 虚拟化技术模 + 拟 CPU 的执行。 +\item 系统模式:gem5 可以用系统调用模拟(SE)和全系统(FS)两种模式进行 + 模拟,前者模拟大多数的系统调用,无需对操作系统和设备进行模拟,而后者 + 则模拟了操作系统和设备,同时执行用户态和内核态的指令。 +\item 存储系统:gem5 包含两种存储系统模型,来自 M5 的 Classic 模型容易 + 配置且模拟速度快,而来自 GEMS 的 Ruby 模型则提供了一个可以精确模拟缓 + 存一致性模型的存储系统模拟框架。 +\end{enumerate} + +gem5 模拟器使用 C++ 编写,并集成了 Python,模拟器的核心功能由 C++ 实现, +而 Python 用于初始化、配置和控制模拟器。为了支持多种指令系统和缓存一致 +性协议,gem5 分别使用了两种领域专用语言,指令系统描述语言 +和 SLICC 在gem5 构建时转为 C++ 代码并编译,生成指令系统和缓存一致性协议 +的模型代码。 + +最新的 gem5 还支持功耗的模拟,和 SystemC 协同模拟,同构和异构多核模拟 +等特性。 + \section{论文组织结构} +本文的组织结构如下: + +第一章~\nameref{sec:intro}。阐述本文的选题背景和研究意义、研究平台与环境,并简述论文 +的组织结构。 + +第二章~\nameref{sec:attack}。分析已经发现的 Meltdown 和 +Spectre 攻击的各个变体。 + +第三章~\nameref{sec:defense}。对已经提出的 Meltdown 和 +Spectre 攻击的软硬件防御进行分析。 + +第四章~\nameref{sec:mywork}。提出本文所设计的防御 +Spectre 攻击的方法,并描述在 gem5 模拟器上的实现。 + +第五章~\nameref{sec:eval}。对本文设计的 Spectre 防御方案,进行安全性的 +验证和性能分析。 + +第六章~\nameref{sec:conclusion}。总结本文的主要工作和研究意义,并对未来工作进行展望。 + % vim:ts=4:sw=4 diff --git a/chap/chap2.tex b/chap/chap2.tex index 6546e53..7f6b4f8 100644 --- a/chap/chap2.tex +++ b/chap/chap2.tex @@ -1,14 +1,850 @@ % Copyright (c) 2014,2016 Casper Ti. Vector % Public domain. -\chapter{Meltdown和Spectre攻击} +\chapter{Meltdown 和 Spectre攻击}\label{sec:attack} + +本章首先介绍侧信道攻击,之后对已有的 Meltdown 和 Spectre 攻击的各种变 +体进行分类讲解,最后简单地介绍已有攻击的其他使用形式。 \section{侧信道攻击} -\section{Meltdown和Spectre攻击} +侧信道攻击是利用计算的过程对环境产生的影响,从而获取秘密数据的技术。 +1996年,Paul Kocher 发现通过对私钥的操作进行计时,可以找出 +Diffie-Hellman,RSA 等密码的私钥。\supercite{TimingAttack} 这是最早的 +侧信道攻击的研究。之后研究者发现了更多侧信道,如功耗 +\supercite{MOP2010}、电磁辐射\supercite{EMpower}、温度 +\supercite{hutter}、噪声\supercite{acoustic}等。 + +侧信道攻击的一个用途是用于构造隐蔽信道(covert channel)。隐蔽信道是指 +在系统安全策略定义之下,不被允许传输数据的双方,用于传输数据的信道。 + +现代计算机系统采用多种优化手段,优化可以作用于处理的数据的值、数据的位 +置、数据存放位置的访问频率等,攻击者可以通过这些优化产生的效果,推断出 +计算机系统处理的秘密数据的值。基于软件的微体系结构侧信道攻击 +\supercite{gruss}利用微体系结构优化造成的时间区别,这种攻击不需要物理访问 +计算机系统,只需要在系统上运行代码。 + +高速缓存计时攻击是一种重要的侧信道攻击的方式。当高速缓存中存在一个地址 +的数据时,访问这个地址的时间更短,利用这个性质,攻击者可以得知一个地址 +是否曾经被访问过。缓存计时攻击的常见形式有: + +\begin{itemize} +\item Evict+Time: 攻击者清除一个缓存组,然后对一个算法的运行进行计时, + 检查它的运行时间是否受到影响 +\item Prime+Probe: 受害者运行一段程序后,攻击者访问缓存某一组的每一路, + 观察访问时间是否有变化 +\item Flush+Reload: 攻击者利用 x86 的 clflush 等指令清除一个共享内存地 + 址对应的缓存行,在受害者运行一段程序后,攻击者重新装载该行对应的地址 + 的数据,通过测量访问时间推断受害者是否访问了这个共享的地址 +\end{itemize} + +\section{Meltdown 和 Spectre 攻击的各种变体} + +处理器在执行指令遇到异常,或者推测式执行了错误的指令后,会回卷错误执行 +的指令,丢弃它们对体系结构状态的修改,这些被回卷的指令称为暂态指令 +(transient +instruction)。Meltdown\supercite{meltdown} 和 +Spectre\supercite{spectre} 是最早发现的两个利用暂态指令的攻击。此后发现 +了更多的 Meltdown 和 Spectre 的变体。为了找出更多的攻击类型和分析它们的 +防御方案,Claudio Canella 等人对这些攻击及其防御做了系统性的研 +究\supercite{systematic},将所有暂态执行攻击分为 Meltdown型攻击 +和 Spectre 型攻击两类。 + +\subsection{Meltdown 型攻击} + +Meltdown 型攻击利用的是处理器异常产生的暂态指令,这些指令使用了体系结构 +层次上不可访问的数据,从而绕过硬件的安全策略,泄露体系结构层次上不可访 +问的数据。 + +\subsubsection{“熔断”(Meltdown)攻击} + +内存隔离是现代操作系统的核心安全功能之一。操作系统确保用户程序无法访问 +其他程序的内存或内核的内存。这种隔离是现代计算环境的基石,使得系统上可 +以同时运行多个应用程序,和多个用户的进程。 + +在现代处理器中,内核和用户进程之间的隔离通常由处理器的定义的权限位实现, +这一位定义了内核的页是否可以被访问。这一位只能在进入内核态时设置,并在 +切换到用户态时清除。这个硬件特性使得操作系统可以将内核映射到每个进程的 +地址空间,在中断等事件发生时,可以高效地从用户进程切换至内核。因此,在 +操作系统的实现中,处理器从用户进程切换到内核时,不会改变内存映射。 + +在 Meltdown\supercite{meltdown} 攻击中,任何用户进程都可以简单地读取所在机器的整个 +内核内存(包括映射在内核区域中的所有物理内存),从而完全破坏内存隔 +离。Meltdown 不利用任何软件漏洞,适用于所有主流操作系统。Meltdown 利用了 +大多数现代处理器中的侧信道信息,可以用于 2010 年以来的现代 Intel 处理器, +也可能可用于其他厂商的处理器。 + +侧通道攻击通常需要非常具体地了解目标应用程序,并且只用于泄露其中的秘密 +信息,但 Meltdown 允许攻击者在可被攻击的处理器上,通过运行代码获得整个 +内核地址空间的数据,包括任何映射在内核中的物理内存。Meltdown 之所以简单和强大,是因为它利用了乱序执行产生的副作用。 + +乱序执行是现代处理器用于提高性能的重要特性,用于隐藏功能单元的延迟,例 +如,读取内存的功能单元需要等待存储器中的数据到达。现代处理器在遇到长延 +迟的执行时,不会使处理器停顿,而是可以乱序操作,将后续的操作调度到空闲的功 +能单元中。 + +从安全的角度,有一个发现很重要:易受攻击的乱序处理器允许非特权态的进 +程将数据从特权(内核或物理)地址载入临时的寄存器中。进一步,处理器可以 +基于该寄存器的值进行计算,例如用这个寄存器的值访问数组。如果一条指令不 +应该执行,通过简单地丢弃访问内存得到的结果,处理器可以确保程序执行的正 +确性。因此,在体系结构层次,即处理器执行计算的抽象定义下,不会出现安全 +问题。 + +但是,乱序执行中的内存访问会影响缓存,而缓存的状态又可以通过缓存侧通道 +进行检测。因此,攻击者可以通过在乱序执行的指令流中,读取特权态的内存来, +来得到整个内核内存的数据,并通过微体系结构隐蔽通道传送出来,然后攻击者在隐 +蔽信道的接收端,找出这个临时寄存器的值。因此,在微体系结构层次,即实际的 +硬件实现中,存在可利用的安全性问题。 + +% background: address spaces +为了将不同的进程相互隔离,处理器支持虚拟地址空间,它将虚拟地址翻译为物 +理地址。虚拟地址空间将内存划分为一系列的页,系统通过多级页表将虚拟页翻 +译为物理页。页表是一个多级的结构,存放虚拟页到物理页的映射,同时,它还 +保存了每个页的保护属性,用于处理器进行权限检查,例如可读、可写、可执行、 +用户可读等。操作系统中每一个运行中的进程有一个对应的页表,页表所在的位 +置存放在处理器中的一个特定寄存器中,在上下文切换时,操作系统会更新这个 +寄存器,从而切换到处理器的进程可以使用这个进程对应的页表。利用这个机制, +每个进程的虚拟地址空间映射到不同的物理区域,每个进程只能使用自己地址空 +间中的数据,从而达到进程间隔离的效果。 + +每个地址空间都可以分为用户地址空间和内核地址空间。正在运行的进程可以访 +问用户地址空间,而内核地址空间只有进入内核态后可以访问,操作系统通过在 +页表中设置内核地址空间的页为用户不可访问,来实现这个特性。内核地址空间 +除了包含内核所要使用的数据外,通常还保存了整个物理内存的映射、文件缓存 +等内容。 + +操作系统将内核地址空间映射至每个用户进程的地址空间中。处理器执行访存指 +令时,在将虚拟地址翻译为物理地址的时候,检查地址对应的权限位,判断用户 +是否可访问该地址。Meltdown攻击中,攻击者让处理器从用户不可访问的内核地 +址装载数据至寄存器,由于所有内核地址都可以翻译为合法的物理地址,处理器 +可以读取内核地址空间的数据,在产生异常前,攻击者构造的暂态指令序列可以 +将读取到的数据通过隐蔽信道发送给攻击者。 + +图\ref{lst:meltdown}是一段 Meltdown 攻击的示例代码,通过它可以读取内核地址空间的数据: + +\begin{figure} + \centering +\begin{minted}{nasm} +xor rax, rax +retry: +mov al, byte [rcx] ; 读取内核空间的数据 +shl rax, 0xc +jz retry +mov rbx, qword [rbx + rax] ; 访问探测数组 +\end{minted} +\caption{Meltdown 示例代码} +\label{lst:meltdown} +\end{figure} + +这段 X86 指令读取了以 rcx 为地址的内核空间的数据,在用户态下,这个读取 +内核空间数据的指令会产生异常,但是在处理器产生异常之前,这条指令可以将 +内核空间的数据读至寄存器,并且其后的指令也会执行,访问 rbx 指向的探测数 +组。在处理器回卷了产生异常的指令和其后执行的指令后,高速缓存中仍然保留 +了探测数组和内核数据相关的元素,从而攻击者可以通过扫描探测数组的每一 +项,观察访问时间,以推测内核空间数据的值。 + +Meltdown 打破了处理器内存隔离功能提供的所有安全保障。这种攻击可以用于现 +代台式机、笔记本电脑以及云服务器。 Meltdown 允许非特权进程读取映射在内 +核地址空间中的数据,包括 Linux,Android 和 OS X 上的整个物理内存,以 +及 Windows 上的大部分物理内存。这些内存可能包含其他进程的物理内存,以及 +内核共享的容器沙箱(如 Docker,LXC)或半虚拟化模式下的 Xen 中,虚拟化管 +理程序的内存,和其他虚拟化实例的内存。Meltdown 攻击的性能取决于处理器速 +度、TLB 和高速缓存大小、DRAM 速度等,可以以 3.2KB/s 到 503KB/s 的速度 +读取内核内存。因此,大量系统受到影响。 + +\subsubsection{“预兆”(Foreshadow)攻击} + +% foreshadow introduction +由于现代广泛使用的操作系统和应用程序的大小可以轻松地达到数百万行代码, +并且单个漏洞通常会破坏所有安全保证,所以在安全上很难信任现有的操作系统 +和应用程序。为了应对这些挑战,学术界和工业界开发了可信执行环境 +(Trusted Execution Environment, TEE),其中包含一个处理器常规执行环境 +之外的非分层保护模型,用于隔离应用程序,称为隔离区(enclave)。 TEE 利 +用只含有处理器和微码的最小可信计算基础(Trusted Computing Base),来保 +证相互不信任的隔离区的保密性和完整性。 每个隔离区的私有处理器和 +内存状态只可以由其内部运行的代码访问,并且在任何特权级别(包括潜在的恶 + 意操作系统和虚拟机管理程序)上运行的所有其他隔离区和软件都无法访 +问。除了强大的内存隔离外,TEE 通常还提供一个证明(attestation)原语, +从而可以本地或远程地在运行时从密码学上验证特定的隔离区已经加载到真 +正的(因而被认为是安全的)TEE 处理器上。 + +随着 2013 年 Intel 软件防护扩展(Software Guard eXtention, +SGX)\supercite{sgx}的发布,硬件强制的 TEE 隔离和证明可以在现成的x86处 +理器上使用。由于 Intel SGX 承诺的强大安全保障,越来越多的行业参与者将这 +项技术应用于可受攻击者控制的机器上,需要安全执行的各种应用程序中。Open +Whisper Systems 依靠 SGX 在 Signal 网络中实现隐私友好的联系人发现功 +能。\supercite{signal-sgx} 微软和 IBM 最近都宣布在其云基础架构中支 +持 SGX。各种现成的蓝光播放器以及 4K Netflix 客户端使用 SGX 对高分辨率视 +频流实施数字版权管理(DRM)。新兴的加密货币\supercite{mobilecoin}和的区 +块链\supercite{sawtooth}技术更加依赖于 SGX 的正确性。 + +然而,当前的 SGX 实现并没有满足它的安全目标。Foreshadow 攻击利用现 +代 Intel 处理器中的乱序执行机制,可以从处理器的缓存中泄露明文 +的隔离区数据。Foreshadow 攻击的核心是利用 Meltdown 攻击相同的处理器 +漏洞,即处理器的访问控制逻辑允许攻击者在瞬态的乱序执行指令回滚之前,使 +用未授权内存访问的结果。然而,Meltdown 攻击针对传统的分层保护域, +而 Foreshadow 考虑了一种非常不同的攻击模型,攻击者的目标不是从用户空间 +读取内核内存,而是破坏最先进的地址空间内隔离区保护域,它不在已经部署 +的用于防御 Meltdown 的内核页表隔离技术的保护之内。Foreshadow 使用了一 +种新的漏洞利用方法,并且基本的攻击完全可以由无特权的攻击者使用,而无需 +用 root 权限访问受害者机器。对于有 root 权限的攻击者,还可以使用一组可 +选的内核级优化技术,进一步降低 Foreshadow 攻击的噪声。 + +Foreshadow 对 Intel SGX 所追求的安全模型产生了深远的影响,在没有微码补 +丁的情况下,当前的SGX处理器无法保证隔离区的数据保密性,也无法证 +明隔离区执行的完整性,包括英特尔自己的隔离区架构。此外,尽管 SGX +希望内核级别的攻击者,但现有的 SGX 处理器甚至无法在没有特权的用户空间 +攻击者面前保护隔离区中的秘密数据。 + +所有先前已知的针对 SGX 的攻击都依赖于软件特定的侧信道泄露或软件漏 +洞。 人们普遍认为,精心编写的隔离区可以通过坚持良好的编码实践,例如 +不使用依赖秘密数据的分支,来防止信息泄露。Intel 认为这些攻击都没有破 +坏 SGX 的安全保证,防止侧信道攻击应该是隔离区开发者的责任。 然 +而,Foreshadow 否定了这一论点,因为它完全依赖于基本的 Intel x86 处理器 +的行为,并且不利用任何软件漏洞,甚至不需要知道受害者隔离区的源代码。 + +% foreshadow attack +\begin{figure}[htbp] + \centering + \includegraphics[width=0.8\textwidth]{addr-trans.eps} + \caption{地址翻译过程和 L1 终端错误的原理\supercite{foreshadowNG}} + \label{fig:addr-tran} +\end{figure} + +在现代 Intel x86 处理器中,用一个虚拟内存地址访问内存时,处理器先在TLB +中查询对应的物理地址,如果 TLB 中没有这个地址对应的项,则会在页表中找到 +虚拟地址对应的页表项,以获得对应的物理地址和访问权限信息。 +如果在虚拟机环境中,则需要如图 \ref{fig:addr-tran} 所示,增加一个扩展 +页表(Extended Page Table,EPT)的访问过程,将客户机的物理地址翻译为底 +层物理机的物理地址。最后,启用了 Intel SGX 的处理器还会进一步检查地址 +翻译的结果,确保这个地址翻译遵守硬件强制的隔离区访问控制限制。如果 +这三个独立的阶段报告一个访问违例,则处理器抛出一个页错误,控制流转向异 +常处理代码,而对于 SGX,大多数的隔离区内存违例会被处理器忽视,将内 +存装载指令得到的值设为 abort page 的值 -1. + +在体系结构层次上,以上的地址翻译过程在文档中有精确的描述。现代处理器为 +了加快地址翻译和内存访问,使用了并行访问和额外的缓存结构。在 Meltdown类 +型的攻击中,可以发现 Intel 的 CPU 将内存访问违例检查放到了指令提交的时 +间,使得在页错误发生之前,未授权的内存内容仍然可以到达流水线中其后执行 +的乱序执行的指令。Meltdown 攻击利用了这个时间窗口,在暂态指令中,将只有 +特权态能访问的内存编码至持久的微体系结构状态。 + +现代 Intel 处理器使用虚拟地址索引,物理地址标签的一级缓存。如 +图\ref{fig:addr-tran} 所示,这种缓存索引方式使得地址翻译可以和一级缓存 +的查询并行。在得到虚拟地址对应的一级缓存组后,处理器还需要知道是否有某 +一路缓存含有需要的数据,因此处理器要将地址翻译得到的物理地址和缓存每一 +路的物理地址标签对比,在某一个有效的缓存路存在正确的物理地址时,此时一 +级缓存命中,数据返回至处理器的执行单元。 + +Foreshadow\supercite{foreshadow} 是一种可以读取 Intel SGX 隔离区中秘 +密数据的 Meltdown 型攻击。如果对 SGX 使用 Meltdown 攻击,攻击者读取未授 +权的隔离区内存,不会产生异常,而是读出 abort page 值 -1. 但是 abort +page 只在页权限检查通过后发生,攻击者可以将该页 present 位清除,即将该 +页设为不存在,此时处理器便会产生异常,但由于一级缓存使用虚拟地址索引, +因此仍然可以从一级缓存读取该虚拟地址中的数据,从而暂态指令可以泄露 SGX +隔离区中的数据。 + +通过将一个页设为不存在,绕过地址翻译,从一级缓存读取数据的攻击方 +式,Intel 将其称为L1终端错误(L1 Terminal +Fault)\supercite{l1tf}。Foreshadow-NG\supercite{foreshadowNG} 利用相同 +的原理,新增了Foreshadow-OS 和 Foreshadow-VMM 两种 Foreshadow 类型的攻 +击,可以绕过操作系统和虚拟机的隔离。 + + +% forshadow-OS +操作系统内核将虚拟内存页从内存交换至外部持久存储时,都需要清除页表项的 +存在位。但是,根据处理器的体系结构规范\supercite{intel-spec},内核可以 +根据需要,自由地使用标记为不存在的页表项中的剩余位。例如,操作系统可以 +保持这些位不变,将它们归零,或者使用它们来存储用于把页从磁盘复制回内存 +的元数据。因此,虽然非特权用户空间应用程序不能直接控制页表项,但是当页 +表项取消映射相应的虚拟页时,操作系统在页表项中留下的元数据仍然可以指向 +包含敏感数据的有效物理地址。在内核清除相应页表项中的存在位后,从用户空 +间解引用未映射的页将导致终端错误。 + +Foreshadow-OS 利用了这种错误造成的暂态执行的指令。虽然访问页表中标记为 +不存在的页会触发终端错误存在,在页表项中的元数据表示在缓存中的物理地址 +的情况下,处理器仍然将一级数据高速缓存中未授权数据传递到暂态乱序执行中。 +然后可以和其他暂态执行攻击一样,将秘密数据从微体系结构暂态执行域带入体系结 +构状态中,例如,使用基于缓存的隐蔽通道。更糟糕的是,如果操作系统支持大 +于 4KB 的页(例如,2MB 或 1GB),攻击者可以通过无意的映射访问最大页面大 +小的内存范围。由于所有软件本质上共享相同的物理地址空间,因此元数据创建 +的虚拟到物理映射可能指向属于操作系统内核,VMM 内存,SGX +隔离区,或 SMM 内存的数据。在操作系统通过 munmap 系统调用释放内存时, +将页表项清零的常见情况下,攻击者可以访问存储在物理地址 0x00 的数据。 + +实验结果表明,在一个 i7-6820HQ CPU 上,Foreshadow-OS 通过利用瞬态执行, +可以从已清除存在位的页中读取一级缓存的数据。 + +% foreshadow-VMM + +虽然上述 Foreshadow-OS 变体允许无特权的攻击者使用未经授权的物理内存位置 +上的数据进行暂态计算,但他们无法直接控制访问哪些物理地址。因此, +Foreshadow 攻击使用在可以直接控制客户机器物理地址和一级缓存标签比较的 +不可信虚拟机时时,会变得更有破坏性。这种攻击称为 Foreshadow-VMM. + +根据 Intel 处理器的架构规范\supercite{intel-spec},客户机物理地址经过基 +于 EPT 的转换过程以找到底层主机物理内存地址。英特尔的分 +析\supercite{l1tf}显示,终端错误发生时,虚拟地址到物理地址处于早期阶段, +在经过 EPT 转换之前,将转换出来的客户机物理地址传到一级缓存中进行标签比 +较。因此,恶意虚拟机可以控制用于访问一级缓存的暂态指令的物理地址。特别 +的,不可信的恶意客户虚拟机可以在自己的客户页表中修改页表项,指向客户机 +物理内存。该地址不会经过 EPT 转换,和一级缓存中的标签进行比较,就像它是 +主机物理地址一样。 + +\begin{figure}[htbp] + \centering + \includegraphics[width=0.8\textwidth]{foreshadow-vmm.eps} + \caption{Foreshadow VMM 的一种使用场景\supercite{foreshadowNG}} + \label{fig:foreshadow-vmm} +\end{figure} + +图 \ref{fig:foreshadow-vmm} 展示了一种情况,一个恶意的虚拟机可以利用瞬 +时执行攻击窃取属于同一处理器核的另一个虚拟机中的数据。这种攻击并不局限 +于超线程受害者,因为 Foreshadow-VMM 可以提取处理器物理核心一级数据高速 +缓存中的任何秘密。 + + +\subsubsection{延迟浮点寄存器状态还原(LazyFP)攻击} + +% introduction +LazyFP\supercite{lazyfp} 是一个 Meltdown 类型的攻击,它可以跨越进程和虚 +拟机的边界,泄露浮点处理单元(FPU)寄存器的状态。这种攻击利用 Intel 处 +理器处理设备不可用异常(\Fault{NM})的行为。这个异常用于在操作系统中实 +现延迟 FPU 上下文切换的优化。在 LazyFP 攻击中,没有特权的本地执行的代码, +可以利用 \Fault{NM} 异常的暂态指令,恢复受害者进程的 FPU 寄存器状态。 +由于 AES-NI 的密钥等数据可能存在 FPU 寄存器中,这种攻击导致的数据泄露 +对信息安全是个很大的威胁。 + +% background + +x87 浮点单元(FPU)是 x86 的处理器的一个扩展,其最初目的是加速浮点数的 +运算。它有自己的一组指令和寄存器。自 1989 年推出 Intel 486DX 以来,它是 +每个 x86 微处理器不可或缺的一部分,而在此之前,它是一个可选的外部协处理 +器。在上下文切换中,向内存保存 FPU 状态和恢复 FPU 的状态曾经是一个成本 +很高的操作,因为内存速度慢并且大小有限。此外,那时 FPU 只在少数程序中被 +使用。在 FPU 不被所有进程使用的情况下,在每个上下文切换时,切换 FPU 状 +态会产生不必要的开销。为了能够减少这种开销,x86 处理器引入了一个控制寄 +存器位 cr0.ts,允许操作系统打开和关闭FPU,当FPU关闭时,它会保持其状态, +但用户和内核代码都无法访问。 + +利用 cr0.ts 实现的优化称为延迟 FPU 上下文切换(lazy FPU context +switching)。核心思想是 FPU 寄存器状态仅在必要时进行上下文切换,并保留 +在不使用 FPU 的进程中。这样,操作系统可以避免不必要的保存和恢复 FPU 上 +下文的成本。 + +操作系统跟踪当前 FPU 寄存器状态所属的进程,此进程称为FPU所有者。FPU 可 +以在启用和禁用状态,在 FPU 启用状态下,当前进程是 FPU 所有者,可以自由 +地执行 FPU 指令。当操作系统切换到另一个进程时,FPU 被禁用。在进程尝试执 +行 FPU 指令之前,它将保持禁用状态。由于 FPU 被禁用,使用浮点指令时,处 +理器会生成 \Fault{NM} 异常。操作系统处理 \Fault{NM} 异常的方式取决于当 +前进程是否为FPU 所有者,如果是,则 FPU 寄存器状态属于该进程,操作系统启 +用FPU,该进程再次可以自由执行FPU指令。否则,则操作系统在启用 FPU 的同时, +将当前FPU 寄存器状态存储到 FPU 所有者进程的状态保存区域,并恢复当前进程 +的FPU 寄存器状态,并将该进程设为 FPU 的所有者。 + +这个算法在不同操作系统中的实现可能不同,它们的共同点是,使用 FPU 的进程 +切换到不使用 FPU 的进程时,操作系统不需要上下文切换 FPU 寄存器的状态。 + +虽然延迟 FPU 上下文切换仍然在现代的操作系统中广泛使用,但其基本假设通常 +不再适用。从 Intel MMX 指令集扩展,到后续的 SSE,AVX 和 AVX-512,FPU 寄 +存器状态已经扩展到更大的 SIMD 寄存器。SSE 指令集是 64 位 x86 处理器的必 +须组成部分,并且在几乎所有程序和库中用于实现不同的任务,例如内存复制。 + +虽然更大的 FPU 寄存器状态使得避免 FPU 上下文切换更具吸引力,但在当前的 +软件中,每个进程最终都会使用 FPU 寄存器并触发 \Fault{NM} 异常。因 +此,Linux 内核已经默认将 FPU 寄存器作为普通上下文切换的一部分进行切换, +在正常操作中不会生成 \Fault{NM} 异常。 + +在使用 Intel 的硬件辅助虚拟化技术时,处理器在从客户机切换到管理程序时, +不会切换FPU寄存器状态。虚拟机管理程序负责上下文切换 FPU 寄存器的状态, +并且机制与非虚拟化操作系统的机制相同。因此,延迟 FPU 上下文切换也适用于 +虚拟机管理程序。 + +在使用延迟 FPU 上下文切换的操作系统中,利用 LazyFP 攻击可以使没有特权的 +攻击者获取同一处理器硬件线程中 FPU 寄存器的数据。以下简单的例子可以泄 +露1比特的数据。 + +\begin{figure} + \centering +\begin{minted}{nasm} +movq rax, xmm0 +and rax, 1 +shl rax, 6 +mov rax, dword [mem + rax] +\end{minted} +\caption{LazyFP 示例代码} +\label{lst:lazyfp} +\end{figure} + +在以上代码片段中,由于进程中 FPU 寄存器被禁用,movq 指令产 +生 \Fault{NM} 异常。操作系统会用对应用程序透明的方式处理该异常,恢复进 +程的状态并继续执行。 + +而在处理器结束 movq 指令的执行并产生 \Fault{NM} 之前,已经执行了后续指 +令,虽然最终这些指令引起的体系结构状态更改会被丢弃,但在缓存中的状态仍 +然保留。这段代码使用了受害者进程的 FPU 寄存器和攻击者进程的通用寄存器 +进行暂态指令的执行,通过探测 mem 指向的数组的缓存状态,可以恢复 xmm0 +最低位的值。 + +利用 Intel TSX 等技术处理异常,攻击者可以高效地泄露所有 FPU 寄存器的数 +据。在 Intel Core i7-5600U 处理器中,可以以 3.3MB/s 的速度泄露一个 AVX +寄存器的数据。 + +\subsection{Spectre 型攻击} + +Spectre 型攻击利用处理器对控制流或数据流的预测,并进行推测式执行产生的 +暂态指令。Spectre 型攻击中,暂态指令访问的是程序在体系结构层面能访问的 +数据,可以绕过软件定义的安全策略,如边界检查等。 + +推测式执行的常见形式是控制流的推测式执行。控制流的推测式执行依赖于转移 +预测技术,包含了分支的预测、间接转移目标地址的预测和函数返回地址的预测, +对应于 Spectre 攻击中 Spectre-PHT, Spectre-BTB, Spectre-RSB. 此外,处 +理器预测装载指令和程序序列之前访问地址未知的存储指令地址不冲突, +推测式执行这样的装载指令,它对应 Spectre-STL. + +%%%% gtran: branch prediction + +%% \Todo: 关于处理器执行转移指令的背景知识,是否需要? + +%% \Fixme: 需要重新翻译的内容 + +%% 在推测执行期间,处理器猜测分支指令的可能结果。更好的预测通过增加可成功 +%% 提交的推测性执行操作的数量来提高性能。 + +%% 现代英特尔处理器的分支预测器,例如Haswell Xeon处理器,具有用于直接和间 +%% 接分支的多种预测机制。间接分支指令可以跳转到在运行时计算的任意目标地址。 +%% 例如,x86指令可以跳转到寄存器,存储器位置或堆栈中的地址,例如“jmp eax”, +%% “jmp [eax]”和“ret”。 ARM上也支持间接分支(例如,“MOV pc,r14”),MIPS +%% (例如,“jr \$ ra”),RISC-V(例如,“jalr x0,x1,0”)和其他处理器。与直 +%% 接分支相比,为了补偿额外的灵活性,使用至少两种不同的预测机制来优化间接 +%% 跳转和调用[35]。 + +%% 英特尔[35]描述了处理器的预测 +%% •以静态或单调方式进行“直接呼叫和跳转”, +%% •“间接呼叫和跳转”要么是单调的,要么是以不同的方式,这取决于最近的程序 +%% 行为,以及 +%% •“条件分支”分支目标以及是否将采用分支。 + +%% 因此,几个处理器组件用于预测分支的结果。分支目标缓冲区(BTB)保持从最 +%% 近执行的分支指令的地址到目标地址的映射[44]。即使在解码分支指令之前,处 +%% 理器也可以使用BTB来预测未来的代码地址。 Evtyushkin等。 [14]分析了英特 +%% 尔Haswell处理器的BTB,并得出结论,只有31个最低有效位的分支地址用于索引 +%% BTB。 + +%% 对于条件分支,记录目标地址对于预测分支的结果不是必需的,因为目的地通常 +%% 在指令中被编码,同时在运行时确定条件。为了改进预测,处理器维护分支结果 +%% 的记录,包括最近的直接和间接分支。 Bhattacharya等。 [9]分析了近期英特 +%% 尔处理器中分支历史预测的结构。 + +%% 尽管返回指令是一种间接分支,但是在现代CPU中经常使用用于预测目标地址的 +%% 单独机制。返回堆栈缓冲区(RSB)维护最近使用的调用堆栈部分的副本[15]。 +%% 如果RSB中没有可用数据,则不同的处理器将停止执行或使用BTB作为回退[15]。 + +%% 分支预测逻辑(例如,BTB和RSB)通常不在物理核心之间共享[19]。因此,处理 +%% 器仅从在同一核上执行的先前分支学习。 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +Spectre 攻击使得受害者程序在推测式地执行在严格按序执行的时不会执行的操 +作,这些操作会通过隐蔽信道将秘密信息泄露给攻击者。 + +Spectre 攻击通常从设置阶段(setup phase)开始,攻击者执行一些用于训练 +处理器的操作,使得处理器在后续阶段执行可被攻击者利用的错误的推测式执行。 +此外,设置阶段中,攻击者可以操作高速缓存状态,从缓存中去除预测的分支所 +依赖的数据,使得推测式执行中的指令足够多,从而可以执行攻击者希望处理器 +执行的指令。在这个阶段,攻击者还可以进行隐蔽信道的准备,如 +Flush+Reload 攻击中清除探测数组对应缓存行的操作。 + +在第二个阶段,处理器在推测式执行中,将受害者上下文中的秘密信息,传送至 +微体系结构隐蔽信道。攻击者向受害者通过系统调用等方式发送请求,以出发这个推 +测式执行。攻击者也可以通过自身代码的推测式执行,从同一进程获取敏感信息, +例如在利用 JIT 编译器的环境中,攻击者可以泄露这个环境中不希望其中执行 +的代码访问的数据。 + +最后一个阶段是恢复敏感数据。对于使用 Flush+Reload 的 Spectre 攻击,恢 +复过程的工作之一是对此前清除的缓存行对应的内存地址进行访问计时,从而推 +断出敏感数据。 + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\subsubsection{Spectre-PHT} + +Spectre-PHT 利用分支预测器,攻击者可以训练转移预测器,使得转移预测器执 +行一个分支,该分支的指令序列可以泄露受害者地址空间或寄存器的信息。 + +Spectre v1 是最早提出的 Spectre 攻击,属于 Spectre-PHT 类型。它利用受 +害者程序中的分支,一个例子如下: + +\begin{figure}[htbp] +\centering +\begin{minted}[frame=single,linenos=true]{C} +if (x < array1_size) + y = array2[array1[x] * 4096]; +\end{minted} +\caption{Spectre v1 受害者代码} +\label{lst:spectre_v1} +\end{figure} + +%%%%%%%%%%%%%%%%%%%%%%% gtran: spectre v1 %%%%%%%%%%%%%%%%%%%%%%%%%%% + +% \verb|TODO|: Spectre 论文中 Spectre v1 的内容 + +% \verb|TODO|: 解释 Spectre 攻击中这段代码的运行方式,关于在 Javascript 和 eBPF 下的攻击 + +% \Fixme: 重新翻译 + +这段代码 x 的值做边界检查,确保后续执行代码的安全性,同时该检查也防止 +处理器读取 array1 数组外的敏感内容。否则,越界的数组下标 x 可能触发异 +常,也可以通过构造 x 用于访问敏感数据。 + +\begin{figure}[htbp] + \centering + \includegraphics[width=0.4\textwidth]{spectre_v1.eps} + \caption{边界检查结果和分支预测方向的可能情形\supercite{spectre}} + \label{fig:spectre_v1} +\end{figure} + +图\ref{fig:spectre_v1}是边界检查结果和预测的方向的四种组合。在已知边 +界检查的结果之前,处理器预测最可能的结果,推测式地执行边界检查之后的代 +码。导致边界检查的结果不能及时得出的原因很多,如边界检查期间发生缓存缺 +失,缺少空闲的执行单元,存在复杂的数据依赖。在这些情况下,正确预测的可 +以使执行时间更短。 + +但是,处理器可以在不正确的路径推测式执行指令。在这个例子中,假设攻击者 +可以控制以如下方式运行: + +\begin{itemize} +\item 选择一个恶意越界的 \verb|x| 的值,使得 \verb|array1[x]| 指向受害 + 者内存中的某个秘密字节 \verb|k| +\item \verb|array1_size| 和 \verb|array2| 不在缓存中,但 \verb|k| 在缓 + 存中 +\item 此前的操作中接收到的 \verb|x| 值均有效,使得分支预测器预测 if 为 + 真 +\end{itemize} + +这样的缓存条件可以由攻击者构造,例如,通过构造访问模式造成 +\verb|array1_size| 和 \verb|array2| 被驱逐出缓存,再使受害者在合法的操 +作中使用秘密 \verb|k|. + +在这种条件下,这段代码运行时,处理器比较恶意的 \verb|x| 和 +\verb|array1_size|。读取 \verb|array1_size| 导致高速缓存缺失,从而产生 +很大的延迟,需要处理器从主存中获得这个值,才可以产生分支结果。同时,分 +支预测器预测 if 中的条件为真,因此在推测式执行中,处理器访问 +\verb|array1[x]|,此时缓存命中,获得秘密 \verb|k| 的值,然后用它计算 +\verb|array2[k*4096]| 的地址,再从存储系统发出读取这个地址的请求。当分 +支结果在此之后确定时,处理器从错误的推测式执行恢复。但是推测式执行中读 +取 \verb|array2| 的行为影响了缓存状态,而且读取的地址依赖于秘密 +\verb|k|. + +攻击者通过测量 \verb|array2| 中的哪个位置在缓存中,可以推断出 \verb|k| +的值,因为受害者在推测式执行中将 \verb|array2[k*4096]| 带入了缓存。 + +这种攻击变体可以用在其他场景下,例如分支的条件可以是类型检查,推测式执 +行的代码可以将一个比较结果泄露到一个固定的地址。上述缓存状态在限制更多 +的情形,如 \verb|array1_size| 在缓存中时,攻击也可能可以进行。 + +这种攻击已经在 Intel, AMD 的多个处理器微体系结构,和一些支持推测式执行的 +ARM 处理器上进行验证,确认它们受 Spectre v1 的影响。 + +除了使用原生的机器指令,利用 JavaScript 和 Linux 内核的 eBPF 的 JIT 编 +译器也可以进行 Spectre 攻击。 + +%% 我们在JavaScript中开发了一个概念验证,并在Google Chrome版本62.0.3202中 +%% 对其进行了测试,该版本允许网站从其运行的进程中读取私有内存。代码如清单 +%% 2所示。 + +%% 在分支预测器错误引用过程中,索引(通过位操作)设置为范围内值。在最后一 +%% 次迭代中,index被设置为simpleByteArray的越界地址。我们使用变量 +%% localJunk来确保不优化操作。根据ECMAScript 5.1 Section 11.10 [13],“| +%% 0”操作将值转换为32位整数,作为JavaScript解释器的优化提示。与其他优化的 +%% JavaScript引擎一样,V8执行即时编译以将JavaScript转换为机器语言。虚拟操 +%% 作放在清单2中的代码中,以使simpleByteArray.length存储在本地内存中,以 +%% 便在攻击期间将其从缓存中删除。有关D8的结果反汇编输出,请参见清单3。 + +%% 由于无法从JavaScript访问clflush指令,我们使用缓存逐出[27,51],即,我们 +%% 以某种方式访问其他存储器位置,以便之后逐出目标存储器位置。泄漏的结果通 +%% 过probeTable [n * 4096]的缓存状态传递,n∈0..255,因此攻击者必须驱逐这 +%% 256个缓存行。长度参数(JavaScript代码中的simpleByteArray.length和反汇 +%% 编中的[ebp-0xe0])也需要逐出。 JavaScript不提供对rdtscp指令的访问,并 +%% 且Chrome故意降低其高分辨率计时器的准确性以使用performance.now()[62] +%% 来阻止定时攻击。但是,HTML5的Web Workers功能使创建一个单独的线程变得简 +%% 单,该线程反复递减共享内存位置中的值[24,60]。这种方法产生了一个提供足 +%% 够分辨率的高分辨率计时器。 + +%% 作为利用条件分支的第三个例子,我们开发了一个可靠的概念验证,它通过滥用 +%% eBPF(扩展BPF)接口从未修改的Linux内核泄漏内核内存,而没有针对Specter +%% 的补丁。 eBPF是一个基于伯克利数据包过滤器(BPF)[49]的Linux内核接口, +%% 可用于各种目的,包括根据数据包内容过滤数据包。 eBPF允许非特权用户在内 +%% 核的上下文中触发解释或JIT编译以及随后执行用户提供的,内核验证的eBPF字 +%% 节码。攻击的基本概念类似于针对JavaScript的攻击概念。 + +%% 在此次攻击中,我们仅将eBPF代码用于推测性执行的代码。我们在用户空间中使 +%% 用本机代码来获取隐藏的信道信息。这与上面的JavaScript示例不同,后者的两 +%% 个函数都是用脚本语言实现的。为了推测性地访问用户空间内存中依赖于机密的 +%% 位置,我们对内核内存中的数组执行推测性的越界内存访问,其索引足够大,以 +%% 便访问用户空间内存。概念验证假定目标处理器不支持超级用户模式访问保护 +%% (SMAP)。但是,没有这种假设的攻击也是可能的。它在Intel Xeon Haswell +%% E5-1650 v3上进行了测试,它在默认解释模式和eBPF的非默认JIT编译模式下都 +%% 可以使用。在高度优化的实现中,我们能够在此设置中泄漏高达2000B / s。它 +%% 还在AMD PRO A8-9600 R7处理器上进行了测试,它只能在非默认的JIT编译模式 +%% 下工作。我们将调查原因留给未来的工作。 + +%% eBPF子系统管理存储在内核内存中的数据结构。用户可以请求创建这些数据结构, +%% 然后可以从eBPF字节码访问这些数据结构。为了强制执行这些操作的内存安全性, +%% 内核存储与每个此类数据结构相关联的一些元数据,并对此元数据执行检查。特 +%% 别地,元数据包括数据结构的大小(在创建数据结构时设置一次并用于防止越界 +%% 访问)以及加载到内核中的eBPF程序的引用数量。引用计数跟踪引用数据结构的 +%% 多少eBPF程序正在运行,确保不释放属于数据结构的内存 +%% 加载的eBPF程序引用它。 + +%% 我们通过滥用错误共享来增加边界检查的延迟与eBPF管理的阵列的长度。内核将 +%% 数组长度和引用计数存储在同一缓存行中,允许攻击者将包含数组长度的缓存行 +%% 移动到处于Modified状态的另一个物理CPU核心(参见[16,53])。这是通过加载 +%% 和丢弃引用另一个物理内核上的eBPF阵列的eBPF程序来完成的,这会导致内核在 +%% 另一个物理内核上递增和递减阵列的引用计数器。这种攻击在Haswell CPU上实 +%% 现了大约5000B / s的泄漏率。 + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% \verb|TODO|: Spectre v1.1的内容,需要更详细地解释攻击原理 + +推测式缓冲区溢出(Speculative Buffer Overflow) +\supercite{spec-buffer-overflow} 是 Spectre-PHT 的另一种形式。处理器存 +在一个存储缓冲区(store buffer),往存储系统写入的数据在指令提交前将写 +入数据的地址和值存放在这个缓冲区中,后续的指令要使用这个地址的值时,可 +以将缓冲区中的数据转发给需要的指令。推测式缓冲区溢出利用了这个特性,例 +如图\ref{lst:spec-buf-overflow}中的程序: + +\begin{figure} +\begin{minted}{C} +if (x < len) + a[x] = z; +\end{minted} + \centering + \caption{推测式缓冲区溢出} + \label{lst:spec-buf-overflow} +\end{figure} + +攻击者给出一个超过数组 \verb|a| 大小的 \verb|x| 时,在推测式执行时,会 +将 \verb|a[x]| 的地址和攻击者输入的值 \verb|z| 写入至存储缓冲区。如果 +\verb|a[x]| 的地址是一个函数在栈中存放的返回地址,这段程序之后有返回指 +令,返回指令就会从存储缓冲区读取这个函数的返回地址,并从这个地址开始执 +行指令,从而攻击者可以使程序在推测式执行时执行以 \verb|z| 为地址开始的 +指令流。通过构造输入 \verb|x| 和 \verb|z|,攻击者可以使处理器在推测式 +执行中执行攻击者指定的代码,这些代码可能会将程序中的秘密数据泄露在微架 +构状态中。 + +\subsubsection{Spectre-BTB} + +Spectre v2 利用间接转移的推测式执行,用于预测间接转移的主要部件是 BTB, +因此在分类上称为 Spectre-BTB. + +在 Spectre v2 中,攻击者可以对间接转移进行投毒,从而可以利用由此产生的 +转移预测错误,从另一个上下文(如另一进程)中读取任意内存。如果由于缓存 +缺失等原因,需要较长延迟得到间接转移的目标地址,则处理器从此前预测的目 +标地址处进行推测式执行。 + +\begin{figure}[htbp] + \centering + \includegraphics[width=0.4\textwidth]{spectre_v2.eps} + \caption{转移预测器在不同上下文中训练和使用\supercite{spectre}} + \label{fig:spectre_v2} +\end{figure} + +攻击者可以用恶意的目标地址训练转移预测器,从而处理器转移到攻击者选择的 +地址进行推测式执行。在图\ref{fig:spectre_v2}中,转移预测器可以在上下文 +中 A 中训练,在上下文 B 中,转移预测器根据在 A 中的训练结果进行预测, +导致处理器跳转至攻击者选择的目标地址处进行推测式执行。攻击者可以引导受 +害者推测式执行在正确的程序执行中永远不会执行的位置。由于推测性执行带来 +了可测量的副作用,这种攻击对于攻击者来说及其强大,即使在没有可利用的条 +件分支错误预测的情况下,也可以用它泄露受害者的内存。 + +举一个简单的攻击例子,攻击者试图读取受害者的内存,当发生间接转移时,攻 +击者可以控制两个寄存器。这在现实的二进制程序中很常见,因为操作从外部接 +收数据的函数通常会进行函数调用,此时寄存器包含攻击者控制的值。 + +攻击者还需要找到一个 Spectre 组件,它是一个用于在推测式执行中,将受害者 +的敏感信息转移到隐蔽通道中的代码片段。在这个例子中,一个有效的组件可以 +由两个指令组成。一个将攻击者控制的 R1 指向的内存加到攻击者控制的寄存 +器R2 上,接下来一个指令用 R2 访问内存。在这种情况下,Spectre 组件可以让 +攻击者通过 R1 控制泄露的地址,以及攻击者通过 R2 控制第二条指令读取泄露 +数据对应的地址。Spectre 组件需要在受害者可执行的内存中,由于大多数进程 +在内存中映射了很大的共享库,攻击者有足够多的空间找到这样的组件,而不需 +要搜索受害者程序的代码。 + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% gtran %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% \verb|TODO|: Spectre 的论文中关于 Spectre v2 一节的剩余内容,一直到实验结果部 +%% 分 + +%% \Fixme: 重新翻译以下内容 + +%% 许多其他攻击是可能的,这取决于对手所知道或控制的状态,对手所寻求的信息 +%% 所在的位置(例如,寄存器,堆栈,内存等),对手控制推测执行的能力,指令 +%% 序列可用于形成小工具,以及哪些渠道可能会泄漏来自投机操作的信息。例如, +%% 如果攻击者可以简单地在将来自寄存器中指定的地址的存储器带入高速缓存的指 +%% 令中诱导推测执行,则在寄存器中返回秘密值的加密函数可能变得可利用。同样, +%% 尽管上面的示例假设攻击者控制两个寄存器,但攻击者控制单个寄存器,堆栈上 +%% 的值或内存值对于某些小工具来说已足够。 + +Spectre v2 的攻击方式和面向返回编程(ROP)\supercite{ret2libc} 有相似 +之处。在ROP 中,攻击者从受害程序所用的 C 库等代码中寻找大量的指令序列, +合并到一起形成一个组件,攻击者可以构造出能进行任意计算的组件。而在 +Spectre v2 攻击中,受攻击的程序是正确编写的软件,构造出的组件是暂态执 +行的,指令数目有限,然而攻击者仍然可以让处理器推测式执行复杂的指令序列, +利用侧信道泄露数据。 + +对处理器的分支预测器进行错误的训练是攻击的一个关键步骤。为此攻击者需要 +通过逆向分析出 BTB 的工作方式,用于制造地址冲突。此前已有工作分析了 +Intel 处理器的 BTB.\supercite{jump-over-aslr} + +%% 请注意,历史错误要求因CPU而异。例如,在Haswell i7-4650U上,使用了大约 +%% 29个先前目标地址的低20位,尽管观察到在这些地址上进行了一些进一步的散列。 +%% 在AMD Ryzen上,仅使用大约前9个分支的低12位。附录A中提供了用于更新Intel +%% Xeon Haswell E5-1650 v3上的分支历史缓冲区的反向工程伪代码。 + +%% 此外,我们在攻击者的同一个虚拟地址处设置了一个跳跃,就像在受害者进程中 +%% 一样。注意,这可能不是必需的,例如,如果CPU仅基于跳转地址的低位索引预 +%% 测。在设计分支预测器时,我们只需要模拟虚拟地址;物理地址,时间和进程ID +%% 似乎并不重要。由于分支预测不受其他内核上的操作的影响(参见第II-C节), +%% 因此必须在同一CPU内核上进行任何错误训练。 + +%% 我们还观察到分支预测器从非法目的地的跳跃中学习。虽然在攻击者的进程中触 +%% 发了异常,但这可以很容易地捕获,例如,使用Linux上的信号处理程序或 +%% Windows上的结构化异常处理。与前一种情况一样,分支预测器然后将进行预测, +%% 将其他进程发送到相同的目标地址,但是在受害者的虚拟地址空间(即,小工具 +%% 所在的地址空间)中。 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +\subsubsection{Spectre-RSB} + +返回栈(RSB)用于预测程序函数调用的返回地址。RSB 是一个栈结构,当函数调用指令执行时,处理器将返回地址压入 RSB,用于该函数调用对应的返回指令执行时,预测返回的目标地址。当函数返回时,处理器从 RSB 的栈顶得到一个地址,作为预测的返回地址,处理器从这个地址开始推测式执行。当处理器从体系结构的软件栈中得到返回地址,该地址和预测的返回地址相同时,推测式执行正确,否则推测式执行错误。 + +Spectre-RSB\supercite{spectre-returns}\supercite{ret2spec} 利用了 RSB +预测返回地址错误,导致错误的推测式执行。RSB 预测返回地址错误有四种原因。 + +第一个原因是由于 RSB 大小有限,会产生上溢和下溢的行为。RSB 的大小通常 +和程序调用栈的大小相匹配。调用深度超过 RSB 的大小时,会造成RSB 溢出, +覆盖其中最老的条目,在函数返回时,会发生 RSB 下溢出。在 RSB 下溢出时, +不同处理器用不同方式处理 RSB 为空的情形,如 Intel 的处理器使用 BTB 进 +行转移预测,攻击者可以用 Spectre-BTB 的攻击方式进行攻击。 + +第二个原因是直接污染 RSB,在这种场景下,攻击者可以替换或删除软件调用栈 +中的值,从而 RSB 中的值和软件栈中的值不同,导致错误的推测式执行。 + +第三种方法是推测式污染 RSB. 在一个函数调用指令推测式执行时,返回地址进 +入软件栈和 RSB,当推测式执行错误时,虽然调用指令被撤销,但返回地址仍然 +在 RSB 中。 + +第四种方法是跨上下文使用 RSB. 因为上下文切换时,正在执行线程的 RSB 会 +被新的线程使用,如果新的线程执行返回指令,则会从原线程提供的 RSB 中的 +地址处进行推测式执行。 + +\subsubsection{Spectre-STL} + +Spectre v4 利用的是装载指令的推测式执行。处理器执行装载指令时,如 +果此前有地址未知的存储指令,会认为这个装载指令和这些地址未知的 +存储指令地址不同,并推测式执行这个装载指令,将其地址中的值装入目的 +寄存器。如果在计算出存储的地址后,发现和已执行装载访问了相同数据, +则处理器需要重新执行这个装载和之后的指令。在推测式执行的过程中,暂态 +指令可以泄露这个地址中的旧值。 + +\section{Meltdown 和 Spectre 的其他形式} + +在研究 Meltdown 和 Spectre 攻击的过程中,研究者还发现了一起其他的攻击 +形式,它们基于已有的 Meltdown 和 Spectre 攻击,使用不同的利用方式。 + +\subsection{NetSpectre} + +NetSpectre\supercite{netspectre} 是通过网络进行的 Spectre 攻击,使得 +Spectre 攻击可以用于不运行攻击者控制的代码的系统上,从而更多的设备受到 +Spectre 攻击的影响。 + +和本地 Spectre 攻击类似,远程的 Spectre 攻击需要受害者存在 Spectre 组 +件代码,当这些代码可以通过网络接口调用时,攻击者可以向受害者发送一系列 +精心构造的请求,通过测量相应时间,泄露受害者内存中的秘密数据。 + +访问存储器的延迟可以反映在网络请求的延迟中,因此攻击者可以通过大量的测 +量,远程地区分缓存是否命中。因此,通过使用 Thrash+Reload,一种基于 +Evict+Reload 的远程缓存攻击方式,将 Spectre 攻击用于网络场景,可以每小 +时从目标系统泄露 15 比特数据。通过使用基于 AVX2 指令执行时间的侧信道, +可以在 NetSpectre 中获得更高的性能,在局域网中可以每小时泄露 60 比特。 +通过使用 NetSpectre 攻击,攻击者可以破坏远程系统中部署的地址空间布局随 +机化(ASLR)防御机制。 + +NetSpectre 攻击在网络上使用,需要攻击者访问受害者提供的网络接口,并且 +向受害者发送大量网络数据包。这些操作不一定需要在短时间内进行。 + +在 NetSpectre 攻击中,攻击者需要利用两个 Spectre 组件:泄露组件和传输 +组件,这些组件在收到网络数据包时执行。泄漏组件在攻击者控制的内存地址处 +访问数据,并根据访问的数据改变一些微体系结构状态。传输组件可以进行任意操作, +它的运行时间取决于泄露组件修改的微体系结构状态。这些组件可以存在于网络驱动 +程序,以及网络协议和网络服务的实现。 + +图 \ref{fig:netspectre_leak} 是一个 Spectre v1 组件,它是处理网络数据 +包的程序的一部分,其中 x 由攻击者控制,它构成了 NetSpectre 的泄露组件。 + +\begin{figure}[htbp] + \centering +\begin{minted}{C} +if (x < bitstream_length) + if (bitstream[x]) + flag = true; +\end{minted} +\caption{NetSpectre 的一个泄露组件} +\label{fig:netspectre_leak} +\end{figure} + +为了在远程攻击中使目标系统在推测式执行中改变微体系结构状态,攻击者采用原始 +Spectre 的方法。为了触发远程系统的推测式执行,攻击者进行以下操作: + +\begin{itemize} +\item 攻击者发送多个网络数据包,使得攻击者选择的 x 值总是在边界内,训 + 练分支预测器在后续执行此边界检查的分支时,预测 x 在边界内 +\item 攻击者发送一个数据包,使得 x 越界,\verb|bitstream[x]| 是目标系 + 统中的一个秘密数据位 +\item 分支预测器预测边界检查结果为真,推测式执行存储器的访问 +\end{itemize} + +在图\ref{fig:netspectre_leak}的代码中,虽然 flag 的值没有被修改,但是 +flag 的缓存状态会发生变化。如果 \verb|bitstream[x]| 为 1,则 flag 会进 +入缓存,通过 flag 的缓存状态,可以推断 \verb|bitstream[x]| 的值。 + +传输组件更简单,它只需要在一个操作中使用 flag,它的执行时间取决于 flag +的缓存状态,例如,最简单的一个传输组件是直接返回 flag 的值。由于传输组 +件的响应时间取决于 flag 的缓存状态,因此可以泄露秘密数据位 +\verb|bitstream[x]| 的值。 + +要完成 NetSpectre 攻击,攻击者需要测量一个秘密值泄露时的网络响应时间。 +由于响应时间的差异在纳秒级,因此攻击者需要进行大量的测量,此时可以得到 +明显的微体系结构状态差异。 + +\begin{figure}[htbp] + \centering + \includegraphics[width=0.5\textwidth]{netspectre.eps} + \caption{NetSpectre 的泄露组件和传输组件\supercite{netspectre}} + \label{fig:netspectre_gadgets} +\end{figure} + +\subsection{SgxPectre} + +SgxPectre \supercite{sgxpectre} 将 Spectre 攻击用于泄露 Intel SGX 环境 +中的数据。执行隔离区内的代码时,使用的分支预测器仍然受隔离区外代码影响, +并且暂态执行的代码可以在隔离区外产生可见的缓存状态更改。因此攻击者可以从 +推断出隔离区内的内存或寄存器的数据,破坏了 SGX 保证的保密性。 +SgxPectre 通过在 SGX 隔离区之外污染隔离区的 BTB 和 RSB,改变 SGX +隔离区中的控制流,将秘密数据泄露至 SGX 之外。 -\subsection{Meltdown型攻击} +% \subsection{MeltdownPrime 和 SpectrePrime} +% +% MeltdownPrime 和 SpectrePrime \supercite{meltdownprime} 是一种使用 +% Prime+Probe 方式进行 Meltdown 和 Spectre 攻击的形式。通过利用缓存一致 +% 性协议的缓存行失效机制,可以达到和 Flush+Reload 方式的同等精度。 -\subsection{Spectre型攻击} +\section{小结} -% vim:ts=4:sw=4 +本章首先介绍侧信道攻击,接着分类介绍各个变体的 Meltdown 型攻击和 +Spectre 型攻击,其中 Meltdown 型攻击利用来自异常的暂态指令,主要的攻击 +有 Meltdown, Foreshadow 和 LazyFP,Spectre 型攻击利用错误的推测式执行 +产生的暂态指令,根据执行预测的部件分为 Spectre-PHT, Spectre-BTB, +Spectre-RSB 和 Spectre-STL,最后介绍 NetSpectre 等攻击的其他利用形式。 diff --git a/chap/chap3.tex b/chap/chap3.tex index 781150a..329d223 100644 --- a/chap/chap3.tex +++ b/chap/chap3.tex @@ -1,6 +1,815 @@ -% Copyright (c) 2014,2016,2018 Casper Ti. Vector -% Public domain. +\chapter{Meltdown 和 Spectre 攻击的防御方案及分析}\label{sec:defense} -\chapter{Meltdown和Spectre攻击的防御方案分析} +Meltdown 和 Spectre 及其多种变体被发现后,研究者提出了多种减轻这些攻击 +的防御方法,它们需要对软件或硬件进行修改。 -% vim:ts=4:sw=4 +\section{Meltdown型攻击的防御} + +Meltdown型攻击利用了暂态指令可以读取体系结构层次上不可访问的数据,并且 +用此数据做计算。因此一种防御方式是使体系结构层次上不可访问的数据,在微 +架构层次上仍然不可访问。 + +KAISER\supercite{kaiser}是一种已经部署在 Linux 内核上的一种防御 +Meltdown 攻击的方案。它的作用是在用户空间中去除内核空间的地址映射,使 +得用户空间的执行的指令无法访问内核空间的存储区域。 + +防御 Meltdown 型攻击的第二种方法是阻止异常的产生。例如对于 LazyFP,最 +新的 Linux 内核在上下文切换时,对所有进程都会保存和恢复浮点寄存器,从 +而用户程序使用浮点寄存器都不会产生异常,从而消除这种攻击。 + +\section{Spectre型攻击的防御} + +Spectre 型攻击的防御方案可以分为三类:阻止推测式执行、防止暂态指令访问 +秘密数据、切断隐蔽信道或降低隐蔽信道的精度。研究者在软件和硬件方面都提 +出了防御方案。 + +\subsection{软件防御方案} + +Intel 和 AMD 都提出了在分支指令后插入 lfence 指令阻止推测式执行的方 +法。\supercite{intel-spectre}\supercite{amd-spectre}lfence 指令在此作 +为一条串行化指令使用,可以在 lfence 指令提交前阻止新的指令执行,从而阻 +止了程序在推测式执行中对秘密数据进行操作。 + +由于 lfence 性能开销大,LLVM提出推测式装载指令加固(Speculative +Load Hardening)\supercite{spec-load-hardening} 技术,它的做法是将可能 +为 Spectre 组件的代码转为图\ref{fig:SLH}中的代码。 + +\begin{figure}[htbp] + \centering +\begin{minted}[frame=single]{C} + if (condition) { + // ?: 的实现可以用无分支的 cmov + predicate_state = !condition ? 0 : predicate_state; + // ... a lot of code ... + // 加固指针,使得它不可用于访问 + pointer1 &= predicate_state; + leak(*pointer1); + } else { + predicate_state = condition ? 0 : predicate_state; + // ... more code ... + // 或加固装载得到的数据,使得数据无法泄露 + int value2 = *pointer2 & predicate_state; + leak(value2); + } +\end{minted} +\caption{推测式装载指令加固产生的代码} +\label{fig:SLH} +\end{figure} + +产生的代码在两个分支中,都计算一个分支条件的状态,并将其作为存储访问指 +令或泄露数据指令的一个数据依赖,从而在得出分支结果之前,无法访问或泄露 +一个秘密数据。 + +retpoline\supercite{retpoline} 是 Google 提出的防御 Spectre-BTB 的方法。 +它的作用是把程序中的间接转移指令修改为一个指令序列,最终使用 ret 指令 +完成跳转,从而使用 RSB 而不是 BTB 来进行间接转移的转移预测。 + +% TODO:增加 retpoline 的代码? + +% index masking +Webkit 在数组访问中使用索引掩码(index masking)\supercite{webkit} 方 +法,它让数组下标和一个值进行与操作,去掉下标高位的1,将数组下标控制在 +一定范围内,防止处理器在推测式执行中访问数组指定范围之外的数据。Linux +构造了一个粒度更细的 array\_index\_nospec \supercite{linux-spec},它的 +功能如图\ref{fig:array-index-nospec}: + +\begin{figure}[htbp] + \centering +\begin{minted}[frame=single]{C} + size_t array_index_nospec(size_t index, size_t size) { + mask = ~(signed long)(index | (size - 1 - index)) >> 63; + return (index & mask); + } +\end{minted} +\caption{Linux 中的索引掩码} +\label{fig:array-index-nospec} +\end{figure} + +如果数组索引 index 小于 size,则 mask 为一个所有位为 1 的值,产生的索 +引不变,否则 mask 为 0,产生的索引为 0,从而推测式执行时的数组索引始终 +在数组大小范围内。 + +% poison value +Webkit 还使用了指针投毒(pointer poisoning)\supercite{webkit}的方法, +它考虑分支用于做类型检查的情形。对于不同类型的数据,Webkit 将这种类型的 +指针和一个类型对应的值异或,要使用的时候再异或这个值得到指向数据的指针, +如果类型不匹配,则得到的指针会指向一个程序无法访问的内存区域。通过这种 +方法,程序在推测式执行中无法通过这种指针访问到程序中的数据,从而避免了 +秘密数据的泄露。 + +% site isolation +Google 为 Chrome 浏览器使用了站点隔离(site isolation)技术,使得浏览 +器用不同的进程访问不同的网站,从而攻击者无法通过用 Javascript 通过侧信 +道攻击获取另一站点相关的数据。\supercite{here-to-stay} + +% timer reduction +降低计时器精度可以降低计时攻击所用侧信道的精度,一个例子是在浏览器中降 +低 Javascript 引擎中 performance.now 等计时器的精度。 +\supercite{webkit} 但是相关研究发现,攻击者可以使用其他方式构造高精度 +的计时器\supercite{js-timer},因此降低计时器精度不是一个有效的防御方法。 + + +\subsection{硬件防御方案} + +\subsubsection{SafeSpec} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% gtran %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%\Todo: SafeSpec III. SAFESPEC :LEAKAGE - FREE SPECULATION 一章,包含一 +%\Fixme: 需要重新翻译 + +SafeSpec\supercite{safespec}提出了一种设计原则保护处理器免受推测式执行 +攻击,同时保持推测式执行带来的性能提升。SafeSpec 的总体设计如图 +\ref{fig:safespec}所示,使用临时结构(图中的影子状态)来保存任何推测式 +执行的指令产生的状态,而不影响处理器的主要结构(在图中称为提交状态)。 +例如,如果推测式执行中的装载指令需要向缓存中填入一个缓存行,则改行保存 +在临时结构中,而不是高速缓存。如果这个指令被取消,则它产生的效果也一起 +被清除,从而错误的推测式执行不会改变缓存状态;如果指令提交,则将这个缓 +存行从临时结构移动至缓存中。 + +\begin{figure}[htbp] + \centering + \includegraphics[width=0.8\textwidth]{safespec.eps} + \caption{SafeSpec 总体设计} + \label{fig:safespec} +\end{figure} + +虽然SafeSpec原则上很简单,但必须解决许多与其安全性,复杂性和性能相关的 +问题。 + +将状态从影子状态移动到提交状态有两种选择。第一种选择是等待分支(Wait + For Branch,WFB),当一个指令依赖的所有分支结果都已经得出时,这个指 +令不再是推测式执行的指令。WFB 可以防御 Spectre v1 和 v2,它们依赖于错误 +的分支预测,没有任何错误的推测式执行产生的状态进入提交状态。而 +Meltdown 不依赖于分支预测,因此 WFB 不能防御 Meltdown. 第二种选择是等 +待提交(Wait For Commit,WFC),在指令提交的时候,才将推测式执行产生的 +状态更新至提交状态。 + +影子状态的大小是另一个设计选择。如果保存影子状态的结构太小,则会导致推 +测式执行的状态被替换,或指令需要在发射前停顿,直到影子状态有足够的空间。 +因此,影子状态应当设计为能符合一般程序产生的推测式执行状态数量的大小。 +暂态推测式攻击从安全的角度,说明影子状态的大小要足够大。 + +SafeSpec 防止推测式执行的产生的值影响提交状态,从而阻止了 Spectre 攻击 +通过隐蔽信道传送数据。但是 SafeSpec 并没有隔离推测式执行中的指令的状态, +这可能造成暂态推测式攻击(Transient Speculation Attack)。由于指令在提 +交前可在推测式执行的状态,在一段时间内,它可以和错误推测式执行的指令共 +享状态。 + +例如,考虑一个非常小的影子结构(如只有一个条目),恶意的推测式执行的代 +码可以读取一个特权数据,隐蔽地通过影子状态传送这个数据至接收者。它可以 +替换影子状态中的条目,使得接收者发现其推测式执行状态丢失。如果在影子状 +态满时阻塞执行,接收者可以发现它的执行时间变长。 + +%SafeSpec 的一个问题是如果一个长延迟指令,例如从内存中读取数据的指令, +%在执行过程中被取消,它的状态需要丢弃。因此,如果一个长延迟指令的结果返回, +%而没有匹配的事务,则丢弃这个结果。 + +SafeSpec 原则可以用于在推测式执行中保护缓存和 TLB,方法是在处理器中加 +入以下影子结构: + +\begin{itemize} +\item 数据缓存:在已有的 Spectre 攻击中都用到了数据缓存作为隐蔽信道。 + 它的影子结构保存了推测式执行中获取的缓存行。在装载/存储队列中,将获 + 得了数据的推测式执行的装载指令指向影子结构的对应项,在同一个分支下访 + 问同一行缓存的指令可以使用影子结构中的内容。指令提交时,缓存行从影子 + 结构移动至缓存。如果指令被丢弃,则释放影子结构对应的一项。在这种设计 + 中,被丢弃的推测式执行的装载指令不但不会修改缓存中的内容,也不会改变 + 缓存替换算法的状态。 +\item 指令缓存:构造一种利用指令缓存的 Spectre 攻击是可能的,因此指令 + 缓存也需要保护,方法和数据缓存类似。 +\item TLB:TLB 也可以作为隐蔽信道使用,攻击者可以检查访问一个页的时间 + 判断 TLB 是否命中。现代处理器进行地址翻译是个复杂的过程,在访问页表 + 时,页表项也会带入数据缓存,这个过程也使用装载存储队列,因此数据缓存 + 的保护足够保护这个过程。因此对 TLB 的保护只需要添加 TLB 本身的影子结 + 构。 +\end{itemize} + +使用 MARSSx86 模拟上述 SafeSpec 模型,可以发现运行 SPEC2017 有平均 3\% +的性能提升。性能提升的原因是影子结构增大了有效缓存的容量,避免了错误推 +测式执行路径污染缓存。 + +\subsubsection{InvisiSpec} + +InvisiSpec \supercite{invisispec} 使推测式执行产生的副作用在数据缓存中 +不可见,从而可以防御利用推测式执行的攻击。它的目标是阻止由推测式执行的 +装载操作产生的微体系结构侧信道和隐蔽信道,如缓存占用、缓存行替换算法信息、 +缓存一致性状态等。和 SafeSpec 不同,InvisiSpec 支持多处理器。 + +Spectre 等攻击由暂态指令引起,为了定义 InvisiSpec 的攻击模型, +表\ref{tab:transient_insn}列出了各种攻击中暂态指令的来源。InvisiSpec 关 +注基于缓存的侧信道和隐蔽信道,因此只考虑装载指令。InvisiSpec 不但要防 +御 Spectre 攻击,并且还要防御未来的攻击。未来的攻击中有多种暂态指令的来 +源。根据这两类攻击,InvisiSpec 设计了两种模型模 +型:Spectre 和 Futuristic. + +\begin{table} +\begin{tabular}{|c|c|} +\hline +攻击 & 暂态指令的来源\tabularnewline +\hline +\hline +Meltdown & \multirow{2}{*}{虚拟内存异常}\tabularnewline +\cline{1-1} +L1TF & \tabularnewline +\hline +LazyFP & \multirow{2}{*}{读取禁用的或者特权寄存器发生异常}\tabularnewline +\cline{1-1} +Rogue System Register Read & \tabularnewline +\hline +Spectre & 控制流预测错误\tabularnewline +\hline +Speculative Store Bypass & 装载指令和更早的存储指令地址别名\tabularnewline +\hline +未来的攻击 & 异常、控制流预测错误、访存别名、一致性违例、中断等\tabularnewline +\hline +\end{tabular} +\caption{暂态指令的来源} +\label{tab:transient_insn} +\centering +\end{table} + +InvisiSpec 的微体系结构基于两种机制。第一个机制中,不安全的推测式执行的装载 +操作将数据读入至推测式执行缓冲区(Speculative Buffer,SB)中,而不读入 +缓存,从而不修改缓存存储层次的状态。由于缓冲区中的数据不产生缓存一致性 +事务,因此可能造成内存一致性违例。第二个机制解决这个问题,当推测式执行 +的装载操作变得安全时,处理器将这个操作重新发射至存储系统,使其对整个系 +统可见。如果这个装载指令可能造成访存违例,InvisiSpec 验证读出的指令是 +否正确,如果验证失败,则重新执行这个访存指令及其后续指令。 +% squash the load + +InvisiSpec 在不同的内存一致性模型下,会使用不同的执行策略。内存一致性模 +型(或内存模型)指定在一个共享内存的系统中,处理器核执行访存操作,并使 +其对其他处理器核可见的顺序。在存储指令执行结束后,存储的数据存放在写缓 +冲区中,随后写入缓存。当写操作写回缓存后,其他核可以看见这个数据,存储 +操作在此时完成。而装载操作在提交前从存储系统读取数据,当它得到数据时, +则称为装载操作完成。装载操作的完成可以在程序序列中其他的访存操作之前, +可以导致内存一致性违例,此时处理器需要用恢复机制重新执行这个装载指令及 +其后的指令。 + +TSO(Total Store Order)是 x86 体系结构所用的内存模型。TSO 允许一个装载 +操作在不同地址的存储操作之前完成,除此之外禁止所有可见的装载和存储的重 +排序。在实现中,为了防止可见的装载指令的重排序,需要确保一个装载操作读 +入的数据,在提交时仍然有效。如果处理器核遇到一个外部的缓存失效请求,则 +需要重新执行这个装载操作。存储指令的顺序由先入先出的写缓冲区保证。 + +RC(Release Consistency)则允许任何访存操作的重排序,除非使用同步指令。 + +InvisiSpec 关注不安全的推测式执行的装载指令(Unsafe Speculative +Load,USL),在 Spectre 的攻击模型中,USL 是在未决分支之后的装载指令, +在得到分支结果后,正确路径上的 USL 转为安全的装载指令。而在未来攻击的模 +型中,USL 变为安全仅当指令到达 ROB 头部,或不被可能中断该指令的事件回 +卷。 + +InvisiSpec 的目的是使 USL 在缓存层次结构中不可见,这意味着 USL 不可以用 +其他线程可见的方式修改缓存层次结构,包括一致性状态。到了一个时间 +点,USL 可以转为安全的装载操作,这个时间称为可见时间点(Visibility +Point),这时其他线程可以看到这个操作在存储系统中的效果。InvisiSpec 通 +过重新装载数据,将数据存入本地缓存,改变缓存层次结构的状态。 + +在 USL 发射至可见的时间段里,它不改变任何缓存一致性状态,处理器核可能无 +法接收对 USL 对应的缓存行的失效请求,从而检测不到这个装载指令对内存一致 +性模型的违例。为了解决这个问题,InvisiSpec 需要进行一个验证的步骤,它在 +可见时间点重新装载数据。 + +USL 请求的缓存行在 USL 发射时有可能已经在一级缓存中,这个缓存行也被载 +入推测式执行缓冲区。处理器可能接收对这一行的失效请求,但是 USL 会忽视 +这个请求,这个失效请求的效果的会在可见时间点处理。 + +%\Todo: InvisiSpec V: INVISISPEC: THWARTING SPECULATION ATTACKS + +%\Fixme: 重新翻译以下内容 + +%1)不安全的推测负载:严格地说,任何在到达ROB头部之前启动读取的负载都是推测负载。在这项工作中,我们对可能由于推测而产生安全漏洞的(大)投机负载子集感兴趣。我们称这些负载为Unsafe Speculative Loads(USLs)。作为USL的一组推测性负载取决于攻击模型。 + +%在Spectre攻击模型中,USL是遵循未解决的控制流指令的推测性负载。一旦控制流指令解决,跟随它的USL在分支的正确路径中转换到安全负载 - 尽管它们仍然是推测性的。 + +%在我们的未来攻击模型中,USL是所有可以被先前指令压扁的推测性负载。一旦USL变为(i)非推测性的,因为它到达ROB的头部或者(ii)推测不能通过任何先前的指令(或推测性的不可压缩的短路)变为安全负载。推测性非可压缩负载是(i)不在ROB的头部并且(ii)在ROB之前仅通过指令而不是由表I中的任何压扁事件压缩的未来的负载。请注意,在表中,其中一个压缩事件是中断。因此,使负载安全包括延迟中断直到负载到达ROB的头部。 + +%要了解为什么这两个条件允许USL过渡到安全负载,请考虑以下内容。 ROB头上的负载本身不能是瞬态的;它可以被压扁(例如,由于异常),但它是一个正确的指令。关于推测性非可压缩负载也可以这样说。这是因为,虽然不在ROB头部,但是它们不能被任何先前的指令压扁,因此可以被认为是ROB头部处的指令的逻辑扩展。 + +%2)使USLs看不见:InvisiSpec背后的想法是让USL隐形。这意味着USL无法以任何其他线程可见的方式修改缓存层次结构,包括一致性状态。 USL将数据加载到我们称为Speculative Buffer(SB)的特殊缓冲区中,而不是加载到本地缓存中。如上所述,USL可以转换到安全负载的时间点。此时,称为可见性点,InvisiSpec采取的行动将使USL可见 - 即,将使USL在内存层次结构中的所有副作用对所有其他线程都明显。 InvisiSpec通过重新加载数据使USL可见,这次将数据存储在本地缓存中并更改缓存层次结构状态。负载可能仍然是推测性的。 + +%3)维护内存一致性:负载的可抑制可见性窗口是从USL发出负载到使其自身可见之间的时间段。在此期间,由于USL不会更改任何一致性状态,因此核心可能无法接收针对USL加载的线路的无效。因此,负载违反内存一致性模型存在未检测到的风险。这是因为这种违规通常是通过传入的失效来检测的,并且通过压缩负载来解决。要解决此问题,InvisiSpec可能必须在负载的可见点重新加载数据时执行验证步骤。 + +%当USL发布并且线路加载到SB时,USL请求的线路可能已经在核心的L1缓存中。在这种情况下,核心可能会收到该行的无效。但是,USL忽略了这种失效,因为USL是不可见的,并且这种失效的任何影响都将在可见点处理。 + +在可见时间点重新装载数据,有两种操作形式:验证(Validation)和曝光 +(Exposure)。验证操作将 USL 用到的数据,和存储系统中这些数据的最新的值 +做比较,如果不相同,USL 和其后的所有指令都需要重新执行。这个操作用于满 +足内存一致性模型,方法类似于基于值的内存保序方法。\supercite{cain-lapasti} + +%如果在该窗口期间,核心已经收到USL加载的行的无效,则验证是在可抑制可见性窗口期间(由于内存一致性考虑)使可见的USL可见的方法。验证操作包括将USL使用的实际字节(存储在SB中)与从缓存层次结构加载的最新值进行比较。如果它们不相同,USL及其所有连续指令都会被压扁。这是满足内存一致性模型所必需的。这一步让人想起Cain和Lipasti的基于价值的记忆排序[31]。 + +USL 在验证阶段不能提交,需要等待验证结束,在这个时间段需要从存储系统获 +取缓存行并写入缓存,比较推测式执行缓冲区和读入的缓存行中,USL 所要使用 +的数据。如果 USL 在 ROB 队头并且 ROB 已满,会导致流水线停顿。 + +InvisiSpec 可以识别很多在 USL 可见之前,不会违反内存一致性模型的 USL, +并对它们使用开销较低的曝光操作。这个操作只需要将读取到的一行数据存入缓 +存,当请求发送至存储系统后,指令即可提交,从而不会使流水线停顿。 + +%值得庆幸的是,InvisiSpec识别出许多在其抑制可见性窗口期间无法违反内存一致性模型的USL,并允许它们以廉价的曝光可见。 如果在该窗口期间核心已经收到USL加载的行的无效,则这些USL在禁用可见性窗口期间不会被内存一致性模型压扁。 在曝光中,缓存层次结构返回的行只是存储在缓存中而不进行比较。 一旦将行请求发送到缓存层次结构,持续曝光的USL就会退出。 因此,USL不会阻止管道。 + +%总而言之,有两种方法可以使USL可见:验证和曝光。 内存一致性模型确定需要哪一个。 图2显示了具有验证和曝光的USL的时间线。 + +%InvisiSpec的负载有两个步骤。首先,当它作为USL发布到内存时,它访问缓存层次结构并获得所请求的缓存行的当前版本。该行仅存储在本地SB中,本地SB与L1高速缓存一样靠近核心。 USL不修改高速缓存一致性状态,高速缓存替换算法状态或任何其他高速缓存层次结构状态。没有其他线程(本地或远程)可以看到任何更改。但是,核心使用USL返回的数据来取得进展。 SB存储行而不是单个词来利用空间局部性。 + +%当可以使USL可见时,并且总是在它收到其请求的高速缓存行之后,硬件触发验证或暴露事务。这样的事务再次重新请求该行,这次修改缓存层次结构,并将该行带到本地缓存。如第V-A4部分所述,验证和暴露交易的运作方式不同,并且具有不同的性能影响。 + +InvisiSpec 针对 Spectre 和 Futuristic 两种攻击模型的设计略有不同。对 +于 Spectre 攻击模型,USL 在此前所有的控制流指令得出结果后,则进入可见时 +间点,此时处理器可以为这个指令执行验证或曝光操作。同时这些验证和曝光操 +作在时间上可以重叠。 + +而对于 Futuristic 模型,USL 在两种情况下可以进入可见时间点:它到达 +了 ROB 的队头,或者它不再可能被取消。当处理器执行验证操作时,其他验证或 +曝光操作不可以与之重叠,因为验证和曝光操作会改变缓存的状态,而正在验证 +的指令如果验证失败,会导致后续的指令被取消,重叠的验证或曝光操作可能泄 +露数据至缓存状态。而对于曝光操作,直至下一个验证操作之前的所有曝光操作 +均可以重叠执行。 + +总的来说,当验证操作阻止 ROB 队头的指令提交,并且 ROB 已满时,流水线的 +停顿才可能发生。这种情况更可能发生在 Futuristic 模型中。 + +%我们将这些设计称为InvisiSpec-Spectre(或IS-Spectre)和InvisiSpec-Future(或IS-Future)。它们显示在表II的第一行中。为了进行比较,第二行显示了如何使用基于栅栏的方法防御这些相同的攻击 - 遵循当前提出的防御幽灵的建议[32]。我们将这些设计称为Fence-Spectre和Fence- Future。前者在每个间接或有条件的分支后放置围栏;后者在每次装载前放置围栏。 + +和基于 fence 的方法相比,InvisiSpec 性能更优,因为和传统的不安全的机器 +相比,装载指令执行的时间不变。通过将更多的验证操作转化为曝光操作,可以 +减少流水线的停顿。最后一个问题是,InvisiSpec 会在存储系统中产生更大的 +流量和缓存端口的竞争。 + +对于 TSO 内存模型,如果一个装载指令之前不存在更老的装载指令或者 fence, +则它不会被对它读取的行的失效请求取消,因此,这些 USL 在可见时间点可以使 +用曝光操作。相反,如果一个 USL 之前有其他的装载指令,则需要执行验证操 +作。而对于 RC 模型,只有在 USL 之前有 fence 的情况下,才需要执行验证操 +作。 +% TODO!!! + +%从这个讨论中,我们看到在TSO下观察停止管道验证的机会最高的设计是IS-Future。为了减少这些事件的发生,InvisiSpec实现了两种机制。第一个允许一些使用验证的USL代替使用曝光。第二个标识可以使用验证的USL,如果验证失败的可能性很大,则提前将它们压扁。我们接下来考虑这些机制。 + +%1)将验证USL转换为曝光USL:假设在TSO下,USL1在ROB中存在较早的负载时启动读取。通常,InvisiSpec会将USL1标记为需要验证。但是,假设在读取时,早于USL1的ROB中的所有负载已经获得了他们请求的数据 - 特别是,如果它们是USL,则他们请求的数据已经到达SB并且已经到达传递到登记册。在这种情况下,USL1不会相对于任何早期的负载重新排序。因此,TSO不会要求在收到对其加载的线路无效时压缩USL1。因此,USL1被标记为需要曝光,而不是验证。 + +%为了支持这种机制,我们用一个名为Performed的位来标记每个USL。当USL请求的数据已在SB中接收并传递到目标寄存器时设置。 + +%2)USL的早期压缩需要验证:假设核心接收到其缓存中的行的失效,该行也恰好被标记为需要验证的USL加载到其SB中。接收失效表示该行已更新。此类更新通常会导致USL在可见性失败时的验证。如果此失效是由错误共享引起的,或者如果对该行的所有更新的净效果直到验证结果是无声的(即,它们将数据恢复到其初始值),则验证才能成功。由于这些条件不太可能发生,InvisiSpec会因接收失效而挤压这样的USL。还有第二个USL的案例,验证失败的可能性很高。假设USL1需要验证并且在SB中有数据。此外,有一个较早的USL2到同一行(但对于该行的不同单词),其在SB中也有其数据并需要验证。当USL2执行验证并将线路连接到核心时,InvisiSpec还会将该线路与SB中的USL1数据进行比较。如果数据不同,则表明USL1已读取陈旧数据。那时,InvisiSpec保守地压制了USL1。 + + % skips subsection D, E + +一个 USL 执行两个内存访问,一个在首次发射的时候,另一个在验证或曝光的 +时候。如果第一个访问在末级缓存缺失并访问主存,则第二个访问也很可能访问 +主存。 + +为了提高性能,InvisiSpec 为每个核添加一个末级缓存推测式执行缓冲区 +(LLC-SB),USL 的第一个访问如果来自主存,则将获取的一行同时放入LLC-SB, +此后在验证时,就可以从 LLC-SB 获取数据,而无需访问主存。而在另一个核访 +问了这一行时,为了防止 LLC-SB 获取过时的数据,才需要使 LLC-SB 中的这一 +行失效,验证和曝光操作将会从存储系统中存有最新数据的地方获取数据。 + +%%%%%%%%%%%%%%%%%%% + +在 gem5 模拟器下, 使用 SPEC CPU2006 和 PARSEC 对 InvisiSpec 进行评测, +以 Spectre 为威胁模型,在 TSO 内存模型下,InvisiSpec 平均性能损失为 +21\%,而使用 fence 性能下降 74\%. + +InvisiSpec 的性能开销来源于三个方面,一个是验证导致的流水线停顿,在大 +多数程序中,这部分开销可以忽略;第二个是取消了错误执行路径后,它装载的 +数据无法被后续的指令复用;第三个是每个 USL 需要两次存储访问,造成资源 +的竞争。 + +InvisiSpec 会增大存储系统中各个缓存之间,和缓存和主存之间的网络流量, +在 TSO 下,以 Spectre 为威胁模型,相对于原处理器,流量增大 34\%. + +\subsubsection{DAWG} + +隐蔽信道是在已有的保护机制下,在不允许通信的进程之间传输信息的信道。例 +如,当侧信道用于向攻击者传送秘密数据时,这种攻击包含一段在受害者保护域 +内执行的代码,用于访问秘密数据,和一个发送器,用于将秘密传递给攻击者。 +这些部分构成了一个数据通道,它基于秘密信息调制这个信道。由攻击者控制, +并在受害者保护域之外的接收器,可以监听信道上的信号,并对其进行解码以确 +定该秘密。图\ref{fig:dawg-schema}描述了这种攻击模式。 + +\begin{figure}[htbp] + \centering + \includegraphics[width=0.8\textwidth]{dawg-schema.eps} + \caption{不同安全域间通过隐蔽信道传送秘密数据} + \label{fig:dawg-schema} +\end{figure} + +经典的对 RSA 的攻击中,代码使用了一段依赖于秘密的执行序列,将私密信息通 +过执行序列传送到了指令缓存状态中,这造成了一个攻击者可以推断秘密数据的 +隐蔽信道。在这种情况中,访问秘密数据和传送秘密数据的代码均在已有的 RSA +代码中。共享指令缓存的攻击者可以用一个接收器解码来自缓存信道的信息。 + +Meltdown 和 Spectre 提供了新了构造数据通道的方式。通过利用错误的推测式 +执行,攻击者可以使处理器执行通常无法访问的代码路径。在 Meltdown 中,攻 +击者推测式执行一段代码,作为数据通道,它可以非法访问秘密数据,并在异常 +发生之前通过微体系结构副作用传输至接受者。在 Spectre 中,攻击者使分支预测器 +预测错误,使处理器沿着攻击者选择的路径推测式执行,这在受害者中形成了数 +据通道。因此,构建数据通道有三种方法: + +\begin{itemize} +\item 数据通道在受害者的代码中已经存在,例如对 RSA 的攻击 +\item 攻击者编写了这个数据通道,如 Meltdown +\item 攻击者从受害者已有的代码中合成数据通道 +\end{itemize} + +这个框架可以用于除缓存状态之外的侧通道,描述通过分支预测器或 TLB 状态造 +成的数据泄露。在未来,可能有更多种类的构造数据通道的方法。 + +DAWG(Dynamically Allocated Way Guard)\supercite{dawg} 是利用保护域之 +间的强隔离防止数据提取的方法,它阻止了任何一对发送器/接收器共享相同的信 +道。这是一种用于缓存等组相联结构设计的的安全路划分机制。DAWG 为组相联的 +结构添加保护域信息,以提供强隔离。和 Intel CAT 不同,DAWG 不允许跨保护 +域发生缓存命中。 + +DAWG 的目标是阻止任何攻击者和受害者安全域之间的基于缓存的信道。实现方 +式是将所有缓存状态的修改隔离在一个保护域内,从而任何受害者域中的传送器 +均不能连接至攻击者域中的接收器,从而阻止了受害者到攻击者的数据泄露。 + +\begin{figure}[htbp] + \centering + \includegraphics[width=0.8\textwidth]{dawg-cache.pdf} + \caption{DAWG 缓存设计\supercite{dawg}} + \label{fig:dawg-cache} +\end{figure} + +组相联缓存包含多个路,每一路是一个直接映射缓存。DAWG 将这些路分组,分 +配到不同的保护域,将缓存请求所属保护域的缓存命中和行替换,限制在所分配 +的路之内。在此之上,缓存所带的元数据,如替换策略的状态,也要在保护域内 +定义,并安全地划分。 + +图\ref{fig:dawg-cache}展示了 DAWG 缓存的结构。处理器中增加几个 MSR,用 +于记录处理器当前所在的保护域,和保护域的策略。每个逻辑核在访问存储器时 +均带有一个域标识字段。 + +除了硬件修改之外,DAWG 还需要软件的支持,用于管理程序的保护域,和每个 +域对应的安全策略。 + +在 zsim 模拟器中使用 SPEC CPU2006, PARSEC, GAPBS 进行模拟,相对于 +Intel CAT,在不同的评测程序和划分方式下,大多数程序性能下降为 4\% 至 7\%. + +\subsubsection{Context-Sensitive Fencing} + +%\Todo: CSF introduction + +%\Fixme: 重新翻译 + +% 为了在对性能影响最小的情况下执行安全的微码定制,这项工作利用了上下文敏 +% 感解码(CSD)[68],这是最近提出的对英特尔(和其他人)微操作转换机制的 +% 扩展,可实现按需和上下文敏感自定义动态微操作指令流。此外,这项工作还利 +% 用了CSD提供的重新配置框架,允许操作系统和其他可信实体动态控制通过外科 +% 手术插入微操作流的投机栅栏的频率,类型和行为,以确保投机安全执行。 + +% 这项工作分析了一套显着扩展的围栏,考虑了不同的可能的执法阶段和执法策略。 +% 特别是,我们引入了一个新的栅栏,可以防止推测性更新缓存状态,同时在指令 +% 的动态调度中具有最小的干扰。 + +% 上下文敏感的防护能够通过基于解码器级信息流跟踪的新型检测机制自动识别网 +% 格插入点。由于处理器前端通常以比管线的其余部分高得多的速率搅拌指令,因 +% 此解码器级的信息流跟踪易于频繁过度和不确定的情况。虽然由于栅栏插入的频 +% 率增加而导致过度拉伸可能会损害性能,但是对于短暂的窗口来说,不确定会破 +% 坏系统的安全性。通过早期低开销的错误检测和恢复机制解决这些挑战,本文进 +% 一步确定了解码器级信息流跟踪作为一种有效的攻击检测机制的可行性。 + +% 这项工作进一步提出了新的微操作流程,保护分支预测器和返回地址堆栈,防止 +% 跨不同保护域的错误训练和/或逆向工程。虽然与英特尔提出的间接分支预测器 +% 屏障(IBPB)指令的精神相似,但这些微操作流程更广泛地应用于更广泛的分支 +% 预测器和返回地址堆栈,并提供更细粒度的控制。 + +% \Todo: 更详细地介绍 CSF + +Context-Sensitive Fencing(CSF)\supercite{context-sensitive-fencing} 是 +一种微码级防御多种类型 Spectre 攻击的方法。它基于 Context-Sensitive +Decoding (CSD)\supercite{context-sensitive-decoding},一种微码翻译机制 +的扩展,用于动态按需自定义微操作指令流。CSF 利用 CSD,在微指令流中注入 +fence 等微码,阻止不安全指令的推测式执行。 + +CSD 是一种根据执行上下文,把指令翻译为不同的自定义的微码的技术。操作系 +统、运行时系统等软件可以通过配置 MSR,设定不同的微码翻译模式。它可以在 +不重新编译的情况下,使不安全的程序变为安全的程序,把优化性能的代码变为 +功耗优化的代码。系统软件可以利用已有的微码更新功能将自定义的微码更新至 +寄存器。CSD 可以通过多种事件触发自定义微码翻译模式。 + +CSF 由以下几个关键部件组成: +\begin{itemize} +\item 微码自定义机制 CSD:使处理器精确地在指令流中插入 fence,减轻推测 + 式执行中不期望的副作用 +\item 译码级信息流追踪(DLIFT)框架:用于检测潜在不安全的执行模式,触 + 发微码自定义机制 +\item 错误训练防御:用于保护分支预测器、返回地址栈等部件 +\end{itemize} + +为了降低 fence 的性能开销,CSF 还提出了3种新的用于防 +御 Spectre 的 fence. 在 fence 操作的设计上有以下考虑: + +\begin{itemize} +\item 作用位置:x86 的 lfence 作用在指令队列阶段,使得后续的指令 + 在lfence 提交前无法进入指令队列后的流水线结构。fence 作用在更晚的阶段 + 的结构,可以减少 fence 对性能的影响,而保护的侧信道更少。 +\item 严格和宽松的 fence:严格的 fence 会阻止所有指令越过 fence,而宽松 + 的 fence 允许某些指令越过它们。例如 lfence 是个严格 + 的 fence,而 sfence 允许存储指令之外的指令越过 fence,是个宽松 + 的 fence. +\end{itemize} + +表 \ref{tab:csffence} 是 CSF 定义的三种 fence,它们防御的 Spectre 变体 +有所不同。 + +\begin{table} + \centering +\begin{tabular}{cccccc} +\hline +fence & 作用位置 & 严格/宽松 & 不允许的指令 & 防御的攻击种类\tabularnewline +\hline +LSQ-LFENCE & LSQ & 宽松 & 装载 & v1\tabularnewline +\hline +LSQ-MFENCE & LSQ & 宽松 & 装载和存储 & v1,v1.1,v1.2\tabularnewline +\hline +CFENCE & 缓存控制器 & 宽松 & 无 & v1\tabularnewline +\hline +\end{tabular} +\caption{CSF 新定义的三种 fence} +\label{tab:csffence} +\centering +\end{table} + + +CSF 防御 Spectre 的开销在 8\% 以下。 + +\subsubsection{Conditional Speculation} + +Conditional Speculation \supercite{conditional-speculation} 是一种检测 +推测式执行中的潜在的泄露数据的访存指令,并阻止其执行的方法。为了检测可 +能在推测式执行中泄露数据的指令,此工作提出安全依赖(security +dependence)的概念,类似于数据依赖和控制依赖,这种新的依赖性用于描述泄 +漏微体系结构信息具有潜在安全风险的推测性执行的指令。对于信道 $c$,指令 $j$ +安全依赖于指令 $i$,如果: + +\begin{itemize} +\item 在程序序列中,指令 $j$ 在 $i$ 之前 +\item $j$ 在 $i$ 之前推测式地执行,并且 $j$ 会通过信道 $c$ 泄露数据 +\end{itemize} + +因为信息可以从多种信道上泄露,所以安全依赖的定义指定了某种信道。针对缓 +存信道,如果指令 $j$ 不修改缓存的内容,则它对于缓存信道不具有安全依赖, +尽管它可能会泄露某些信息。 + +根据以上定义,表\ref{tab:secdep}总结了 Spectre 攻击中的主要的安全依赖。 +Spectre 攻击的安全依赖性来自两种情况,访存-访存推测和分支-访存推测。 + +\begin{table} + \centering +\begin{tabular}{|c|c|c|} +\hline +Spectre 变体 & 指令 $i$ & 指令 $j$\tabularnewline +\hline +\hline +Spectre v1 & 条件分支 & 访存\tabularnewline +\hline +Spectre v2 & 间接转移 & 访存\tabularnewline +\hline +Spectre v4 & 访存 & 访存\tabularnewline +\hline +SpectrePrime & 条件分支 & 访存\tabularnewline +\hline +\end{tabular} +\caption{Spectre 攻击中的安全依赖} +\label{tab:secdep} +\centering +\end{table} + +在条件推测式执行的流水线中,在发射队列中引入了安全冒险检测,以识别具有 +安全依赖的可疑的不安全指令。只要在执行阶段确认了真正的冒险,那些不安全 +的推测式执行将会使用现有的重执行和推测式执行恢复机制终止并丢弃。 + +% the following is from gtran + +\begin{figure}[htbp] + \centering + \includegraphics[width=0.8\textwidth]{conditional-spec.eps} + \caption{安全冒险的检测\supercite{conditional-speculation}} + \label{fig:cond-spec} +\end{figure} + +安全冒险的检测逻辑用一个矩阵实现。处理器中通常用矩阵跟踪数据依赖,而在 +安全检测中,处理器使用安全依赖矩阵确定要发射的指令是否存在安全相关。添 +加了安全依赖矩阵的发射阶段如图\ref{fig:cond-spec}所示。 + +安全依赖矩阵是一个 NxN 比特的数组,其中 N 为发射队列大小,用发射队列的 +位置索引。对于指令队列中位置为 X, Y 的指令,如果该矩阵 Matrix 的位 +置 $Matrix[X,Y]$ 为 1,则 X 安全依赖于 Y. + +当新的指令分发至发射队列时,处理器在发射队列的位置 X 处分配一个条目, +此时对发射队列中所有有效的指令 Y,计算 $Matrix[X,Y]$: + +\begin{align*} +Matrix[X,Y] {}={} & (IQ[X].opcode == Memory) \\ + & \&{} (IQ[Y].opcode == Memory {} || {} IQ[Y].opcode == Branch) \\ + & \&{} IQ[Y].valid \\ + & \&{} !IQ[Y].issued +\end{align*} + +这个公式的含义如下:X 在进入发射队列之前 Y 有效,则意味着 Y 在 X 之前; +对于多种 Spectre 变体,只需要检查访存指令是否依赖于先前的分支或访存指 +令;如果在访存指令发出时,此前的分支或访存仍在等待,则认为新的访存指令 +存在安全相关。 + +在实现中,图\ref{fig:cond-spec}展示了发射队列的三个阶段。第一阶段中,数 +据依赖矩阵生成一个依赖向量;第二阶段中,该向量发送至年龄矩阵,用于选择 +最老的可发射的指令;在第三阶段,处理器将被选择要发射的指令放进安全依赖 +矩阵,查询它们的安全相关性。当一个将要发射的指令存在安全冒险时,它会被 +标上可疑推测式执行(\emph{suspect speculation})标记。 + +在指令 X 发射后,更新向量寄存器中的对应位设为0,在下一周期,依赖矩阵中 +X 对应的一列将会重置,意味着待发射指令和 X 的之间的安全相关被清除。 + +一种简单的冒险消除方式是阻止发射队列中标记了可疑推测式执行指令的执行, +但是这种策略会导致性能下降。为了实现性能,安全性和透明性的平衡,条件推 +测式执行提出了两种过滤机制,以找出错误识别的安全安全冒险。基于缓存命中 +的冒险过滤器针对命中缓存的推测式执行指令。因为它们的推测式执行不会改变 +缓存的内容,所以它们是安全的。另一个提出的过滤器,基于可信页面缓冲区 +(Trusted Page Buffer, TPBuf)的冒险过滤器,从另一个角度识别安全的推测 +推测式执行的指令。对于使用基于共享内存(例如 Flush+Reload)的缓存侧通道 +攻击窃取内存信息的 Spectre 变体,他们对恶意组件的推测式执行具有名 +为 S-Pattern 的共同特征。 TPBuf 从所有推测式执行中捕获 S-Pattern,对于 +任何推测式执行的访存指令,如果它与 S-Pattern 不匹配,则被认为是安全的。 + +% hit-based + +考虑到大多数程序有良好的时间局部性和空间局部性,一级缓存命中的访存请求 +不会修改缓存的内容,因此可以使用基于缓存命中的冒险过滤器,以减少阻止可 +疑推测式执行的指令造成的性能损失。只要访存指令的访问命中一级缓存,则该 +指令正常执行,但是如果缓存缺失,则该指令将会重新回到发射队列,直到安全 +依赖得到解决,才可疑重新发射。这个过滤器只需要对一级缓存的控制逻辑做少 +量修改,即不处理标记为可疑推测式执行的访存请求。 + +% TPBuf +如果一个程序的一级缓存命中率低,则基于缓存命中的冒险过滤器仍然会阻止大 +量的推测式执行。对于利用共享内存构造侧信道的 Spectre 攻击方式,并非所有 +的一级缓存缺失都可作为隐蔽信道使用。因此可以使用基于可信页面缓冲区的冒 +险过滤器,检测这些指令中安全的指令。在这些攻击中,Spectre 组件的执行中 +包含两个特殊的访存指令,记为 A 和 B,它们有如下的行为: + +\begin{itemize} +\item A 推测式地访问敏感数据,B 推测式地访问攻击者和受害者共享的内存区 + 域,用于构造受害者和攻击者之间的侧信道。通常秘密数据的内存区域和用于 + 构造侧信道的共享内存区域在不同的内存页,因此它们访问不同的页。 +\item 为了构造缓存侧信道,攻击者需要清除共享内存对应的缓存行,其后处理 + 器推测式执行中访问 B 造成缓存缺失,重新将缓存行载入一级缓存,攻击者 + 再探测共享内存的缓存行发现这一变化。因此要通过缓存侧信道泄露信息,需 + 要 B 在缓存中不命中。 +\item 指令 B 依赖于指令 A,A的结果用于计算共享内存区域的索引。这种设计 + 也是攻击者推断处秘密数据要点。 +\end{itemize} + +在 TPBuf 过滤器中,以上行为模式称为 S-pattern. 如果观察到推测式执行的 +指令序列具有以下特征,则认为它具有 S-pattern: + +\begin{itemize} +\item 至少有两个指令 A 和 B 访问不同的内存页 +\item 指令 B 导致一级缓存缺失 +\item B 依赖于 A +\item A 和 B 之间可能有多个指令 +\end{itemize} + +TPBuf 它记录了所有推测式的存储器访问请求,当一个新的请求在一级缓存中缺 +失时,其页地址将会和 TPBuf 中其他访问的页地址比较,如果有至少一个访问访 +问了不同的页,并且正在写回阶段,则认为新的请求不安全。 + +\begin{figure}[htbp] + \centering + \includegraphics[width=0.8\textwidth]{tpbuf.eps} + \caption{TPBuf 的结构\supercite{conditional-speculation}} + \label{fig:tpbuf} +\end{figure} + + +TPBuf 的结构如图\ref{fig:tpbuf}所示。TPBuf 的条目和 LSQ 的条目一一对应, +它的条目分配、提交等操作和 LSQ 一起进行。TPBuf 包含了所有进行中的推测式 +的访存指令。为了避免攻击者访问未授权的数据,并将其传播到自己的地址空间, +需要先用 TLB 获得访问的物理地址,将其写入 TPBuf 中该访问对应的一 +项。TPBuf 检测 S-pattern,并将结果再传至缓存命中过滤器,决定是否阻止一 +个可疑推测式执行的请求。 + +% 分配:当在LSQ中分配存储器访问指令时,它们也在TPBuf中分配并且A位被置位。并且根据TPBuf中的A位生成掩码。 +% 它指示TPBuf中的哪些内存指令比程序顺序中的新条目旧。 + +% 更新:使用存储器指令附带的可疑推测标志更新S位。当PPN记录在TPBuf中时,V位置位。当存储器指令获取的数据可供其他指令使用时,W置位。 + +% 检测:当传入请求进入TPbuf时,TPBuf将其PPN与现有条目的PPN进行比较,然后生成地址匹配向量(匹配)。这些矢量,包括Match,V,W和S,用作等式1逻辑的输入,以确定请求是否安全。特别地,“|”表示减少OR,它对向量中的所有位进行OR运算以生成1位输出。 +%%%%%%% + +在 gem5 模拟器中用 SPEC CPU2006 进行评测,使用基于缓存命中的过滤器时, +平均性能开销为 12.8\%,再加上 TPBuf 过滤器,平均性能开销可以再降低至 +为 6.8\%. + +\subsubsection{SpectreGuard} + +SpectreGuard\supercite{spectreguard} 是一种以数据为中心的软硬件结合 +的Spectre 防御方案。这种方案考虑到对于软件开发人员来说,识别程序中的秘 +密数据(如密钥)比识别可能受到攻击的 Spectre 组件代码容易。因 +此,SpectreGuard 在操作系统中提供接口,使程序可以标记敏感的内存区域,硬 +件上只需要简单的微体系结构扩展,就可以阻止 Spectre 攻击。和已有的防御方案相 +比,它不需要依靠编译器识别程序中可能受攻击的代码,也不需要复杂的硬件修 +改。 + +Spectre 攻击需要分为三个步骤:从存储系统装载秘密数据,将秘密数据转发至 +依赖于这个数据的指令,执行依赖于这个数据的指令,通过微体系结构隐蔽信道泄露 +秘密。数据的泄露在第二、三步进行,如果秘密数据被装载,但不被转发,秘密 +也不会泄露给攻击者。 + +因此,SpectreGuard 允许第一步发生,但将第二步延迟至装载秘密数据的指令 +之前所有分支均已解决。并且,在经过软件标记之后,第一步中仅当数据在敏感 +内存区域时,才需要延迟转发。当秘密数据不经常访问时,总体开销可以忽略。 + +敏感数据的标记通过在页表中添加一个位实现,在软件中可以扩展操作系统 +的mmap, mprotect 等接口,或通过运行库、编译器、连接器实现。在微体系结构中, +指令执行后,执行结果将转发至后续依赖于这个指令的指令,而如果指令是访问 +了敏感区域的指令,则推迟它的转发。 + +在 gem5 模拟器中用 SPEC CPU2006 对几种标记方案进行评测,方案 SG(All) 标 +记内存的所有页,平均性能开销为 20\%, SG(Heap) 只标记堆区域,性能开销减 +少至8\%. 在使用 OpenSSL 的合成基准测试中,如果只标记私钥为秘密数据,则 +性能可以接近原处理器的性能。 + +% \begin{comment} +% +% MI6: Secure Enclave in a Speculative Out-of-Order processor +% +% abs: 一个考虑了Spectre等攻击设计的enclave方案 +% +% +% Data Oblivious ISA(OISA)是一种 ISA 扩展,用于阻止信息通过侧信道泄露。 +% 设计原则: +% \begin{itemize} +% \item ISA的安全性和微体系结构无关 +% \item ISA不会阻止现代微处理器的优化技术 +% \end{itemize} +% +% OISA有以下组件: +% \begin{itemize} +% \item 动态跟踪敏感数据:使用DIFT跟踪程序运行时私密数据在处理器中的传 +% 播。所有数据都有 confidential/public 标记,标签在读取操作数时必须 +% 解析 +% \item 指令定义操作数可以接受 public 还是 public/confidential 数据 +% \end{itemize} +% \end{comment} +% +% % vim:ts=4:sw=4 + +\section{Meltdown 和 Spectre 的防御方案分析} + +由于 Meltdown 型攻击和 Spectre 型攻击利用的暂态指令不同,因此防御方案 +也不同。 + +对于 Meltdown 型攻击,防御方法相对简单。只要使产生异常的指令在微体系结构层 +次上无法访问体系结构层次上无法访问的数据,即可以阻止 Meltdown 型攻击。 +在现有的处理器中,需要使用 KAISER 等防御方案,会造成一定性能的损失。 + +SafeSpec 和 InvisiSpec 也将防御 Meltdown 型攻击作为它们的目标之一,但 +是在现有的 Meltdown 型攻击中,泄露数据的隐蔽信道由攻击者构造,攻击者可 +以利用缓存之外的信道泄露数据,因此只阻止缓存信道不能有效地防御 +Meltdown 型攻击。 + +Spectre 攻击的防御相对复杂。对于软件防御方案,在分支后添加串行化指令或 +数据依赖,阻止推测式执行的发生,会有 30\% 以上的性能下降。 +\supercite{spec-load-hardening} 使用静态分析工具 +\supercite{oo7}\supercite{spectector}寻找程序中受影响的分支,可以检测 +出受 Spectre 攻击影响的分支,并只对这些分支进行防御,但是这些工具仍然 +未能投入使用。而且,这些方法都只能防御 Spectre v1. Retpoline 有 5\% 至 +10\% 的性能开销\supercite{systematic},只能用于防御 Spectre v2. 索引掩 +码只用于数组边界检查一类分支,站点隔离只用于浏览器等特定场景。 + +总的来说,软件防御方案防御的攻击类型有限,而且需要对软件进行修改,而硬 +件防御方案通常不要求软件修改,可以防御多种变体的攻击,这是硬件防御方案 +相对于软件防御方案的优点。 + +现有的硬件防御方案主要关注高速缓存侧信道。在现有的大部分 Spectre 类型 +攻击中,都使用高速缓存侧信道,因此针对高速缓存侧信道的防御方法可以抵抗 +大多数的攻击。随着侧信道攻击研究的发展,未来的处理器可能需要考虑更多的 +信道。 + +SafeSpec 的方法是使用临时结构。InvisiSpec 为了处理内存一致性的问题,在 +添加一个推测式执行缓冲区之外,还要增加一个验证步骤,使得 InvisiSpec 具 +有较大的性能开销。 + +基于缓存隔离的 DAWG 的主要缺点是需要操作系统的支持。此外,DAWG 不能防 +御 NetSpectre 等来源于同一安全域的攻击。 + +Context-Sensitive Fencing 基于译码阶段的微码自定义,它只适用于使用微码 +的处理器。 + +Conditional Speculation 定义了安全相关的概念,并将其用于安全冒险检测, +这个概念可以用于所有可泄露数据的侧信道。对于缓存侧信道,基于缓存命中的 +过滤器和 TPBuf 过滤器结合,性能开销较小。TPBuf 主要用于防御基于共享内 +存的侧信道攻击,而不能防御不利用共享内存的缓存侧信道攻击,这是一个主要 +缺点。 + +SpectreGuard 是基于隐私数据标记的防御方法,它针对 Spectre 攻击中所有的 +侧信道,而不限于缓存信道。它的设计简单,但是需要软件的支持。 + +\section{小结} + +本章介绍了现有的 Meltdown 和 Spectre 的防御方法,重点介绍 Spectre 的防 +御方法,包括软件防御和硬件防御。最后分析了各种防御方案的特性和缺点。 diff --git a/chap/chap4.tex b/chap/chap4.tex index e9f03dc..73ac113 100644 --- a/chap/chap4.tex +++ b/chap/chap4.tex @@ -1,9 +1,406 @@ -\chapter{可抵抗Spectre攻击的微架构的设计与实现} +\chapter{针对 Spectre 攻击的微体系结构设计}\label{sec:mywork} + +本章讲解本文提出的一种防御 Spectre 攻击的方法,该方法使用动态信息流追 +踪的方法,检测 Spectre 组件指令流中可能泄露秘密数据的访存指令,并使用 +一种安全的方法执行这些访存指令。 + +这种微体系结构设计不需要软件的支持,未修改的软件和操作系统可以直接在采用这 +种微体系结构改进的处理器中执行。 \section{威胁模型} -\section{InvisiSpec} +本文对攻击者做如下假设:攻击者知道受害者程序的代码、进程中的地址分布信 +息,攻击者和受害者可以在同一进程,共享同一处理器核,或在不同处理器核上。 + +本文设计的方法用于防御利用控制流推测式执行的 Spectre-PHT, Spectre-BTB, +Spectre-RSB 攻击,此方法可以扩展至 Spectre-STL 攻击。攻击者在 Spectre +攻击中使用高速缓存作为隐蔽信道,其他信道不在本文的考虑范围。本文不考虑 +其他的侧信道攻击。本文针对攻击者通过 Spectre 攻击获取内存中秘密数据的 +情形,不考虑攻击者通过攻击获取寄存器中秘密数据的情形。 + +\section{基于动态信息流追踪的 Spectre 检测方法} + +动态信息流追踪(Dynamic Information Flow Tracking)\supercite{dift}是 +一种硬件安全策略,通过识别可疑的信息流,并限制可疑信息的使用,保护程序 +的安全。它最早用于防止攻击者利用缓冲区溢出攻击执行恶意代码,也可以用于 +检测跨站脚本攻击、SQL注入等攻击。\supercite{raksha} + +DIFT 可以作为 Spectre 攻击的检测手段之一。Spectre 的论文中指出处理器可 +以追踪数据是否在推测式执行中获取,进而阻止在后续可能泄露这个数据的操作 +中使用,作为阻止数据进入隐蔽信道的方法\supercite{spectre},本文所用的方 +法则是这种观点的一种具体设计。在其他使用了 DIFT 的防御 Spectre 的设计中, +所追踪的对象有所不同。CSF\supercite{context-sensitive-fencing} 中的译码 +级信息流追踪框架 DIFT,用于追踪处理器使用的数据是否来源于用户输入,从而 +处理器可以根据此信息判断是否需要插入 fence 微码。有的指令系 +统\supercite{oisa}在定义中即包含了 DIFT 技术,用于追踪一个数据是否为秘 +密数据。 + +和 Conditional Speculation +\supercite{conditional-speculation} 的 TPBuf 过滤器一样,本文的工作同样 +实现了一个用于识别一条指令是否泄露数据的方法。和 TPBuf 不同的是,基 +于DIFT 的方法并不检测不同的访存指令之间的地址关系,而是直接寻找读取数据 +的指令和泄露数据的指令之间直接或间接的依赖关系。TPBuf 过滤器不能防范非 +共享内存区域的缓存侧信道攻击,但是基于 DIFT 的方法可以。 +而SpectreGuard\supercite{spectreguard} 中可以不依赖软件实现 +的 SG(Full)方案,目的也是阻止推测式执行中从存储系统读取的数据不被泄露, +方法是直接禁止读出的数据被后续的推测式执行的指令使用,本文的方法允许这 +样的数据被使用,但是使用这个数据的指令需要用不产生侧信道的方式执行。 + +在本文的工作中,DIFT 的作用是在运行时动态识别可能泄露秘密数据的指令。以 +图\ref{lst:spectre_v1}的 Spectre v1 组件代码为例。攻击者希望通 +过 Spectre攻击泄露 \verb|array1[x]| 的值,方法是让处理器在分支的推测式 +执行中,访问 \verb|array2[array1[x] * 4096]|,从而将一个依赖 +于 \verb|array1[x]| 的地址处的数据写入了缓存中。使用了基于 DIFT 的检测 +手段后,可以识别出 \verb|array2[array1[x] * 4096]| 的地址依赖 +于 \verb|array1[x]| 的值,从而处理器可以阻止对这个地址的访问。 + +为了达到这个目的,我们为所有的物理寄存器都添加一个标记,用于表示它的值 +是否来源于推测式执行中,从内存中读出的值。在上述例子中,有一条将内 +存 \verb|array1[x]| 读取至寄存器的指令,该指令的目的寄存器的标记将会被 +设为1. + +\begin{figure} +\begin{minted}[frame=single,linenos=true]{nasm} + xor eax, eax + cmp qword [rip + 0x2b157f], rdi + jbe loc.funcret + lea rax, [rip + 0x2b14ae] + add rax, rdi + movzx eax, byte [rax] + shl eax, 12 + lea rdx, [rip + 0x2b425d] + mov eax, dword [rdx + rax] + loc.funcret: ret +\end{minted} +\caption{Spectre 组件的汇编代码} +\label{lst:spectre_v1_asm} +\centering +\end{figure} + +上述 Spectre v1 的组件代码可以产生图\ref{lst:spectre_v1_asm}所示的指令。 +我们用表\ref{tab:spectre_dift}展示 DIFT 在推测式执行分支中的指令的行为, +其中 T 表示寄存器的标记,在分支推测式执行前,所有寄存器的标记为0,为了 +描述方便,这里用体系结构寄存器进行描述,实现中为物理寄存器的标记。 + +\begin{table} +\begin{tabular}{|c|c|c|} +\hline +指令 & 指令的语义 & DIFT 行为\tabularnewline +\hline +\hline +lea rax, {[}rip + 0x2b14ae{]} & rax <- rip + 0x2b14ae & T{[}rax{]} <- T{[}rip{]} = 0\tabularnewline +\hline +add rax, rdi & rax <- rax + rdi & T{[}rax{]} <- T{[}rax{]} | T{[}rdi{]} = 0\tabularnewline +\hline +\multirow{2}{*}{movzx eax, byte {[}rax{]}} & \multirow{2}{*}{eax <- (uint8\_t){[}eax{]}} & T{[}rax{]} = 0, 指令安全\tabularnewline +\cline{3-3} + & & T{[}rax{]} <- 1\tabularnewline +\hline +shl eax, 12 & eax <- eax {*} 4096 & T{[}rax{]} <- T{[}rax{]} = 1\tabularnewline +\hline +lea rdx, {[}rip + 0x2b425d{]} & rdx <- rip + 0x2b425d & T{[}rdx{]} <- T{[}rip{]} = 0\tabularnewline +\hline +\multirow{2}{*}{eax, dword {[}rdx + rax{]}} & \multirow{2}{*}{eax <- {[}rdx + rax{]}} & (T{[}rdx{]} | T{[}rax{]}) = 1, 指令不安全 \tabularnewline +\cline{3-3} + & & T{[}rax{]} <- 1\tabularnewline +\hline +\end{tabular} +\caption{分支中代码产生的 DIFT 行为} +\label{tab:spectre_dift} +\centering +\end{table} + +以下描述这个检测方法的具体细节。 + +标记的设置:在推测式执行时,对于所有从内存读取数据的指令,将其所有目的 +寄存器的标记设为1. + +标记的传播:标记的传播在处理器的执行阶段进行,在这个阶段,处理器在读源 +寄存器的同时,将它们对应的标记读出。对于不同类型的指令,标记传播的方式 +如下: + +\begin{itemize} +\item 对于算术类指令,它的源操作数均来源于寄存器,其目的寄存器的标记设 + 为所有源寄存器标记做或运算的结果。 +\item 对于装载类指令,它从内存中读取数据,这是标记设置的基本条件,因此 + 目的寄存器的标志设为1. +\item 对于存储类指令,它没有目的寄存器。和一般的 DIFT 实现不同,我们不 + 对任何内存进行标记。因为要使用存入内存中的数据,需要有一套指令将其重 + 新从内存中读出,这个操作会设置这条指令目的寄存器的标记。 +\item 对于转移类指令,我们为每个指令添加一位标记,如果源寄存器中有标记 + 为1的指令,则设置这个指令的标记为1,否则设置为0.转移指令的的标记将在 + 下文描述。 +\end{itemize} + +标记的清除:当一条指令不再处于推测式执行的状态,即该指令此前的所有分支 +都执行完成并通过验证,则要将这条指令所有目的寄存器的标记重置为0.对于转 +移类指令,则清除该转移指令的标记。 + +寄存器中的标记可以处理读取内存中数据的指令,和泄露内存中数据的指令,存 +在直接或间接数据相关的情形。读取内存的指令使得存放它的寄存器被标记,此 +后和它存在直接或间接数据相关的指令,会将这个标记传播至这些指令的目的寄 +存器。 + +考虑攻击者在 Spectre 攻击中利用缓存侧信道泄露内存中的数据,则 +在 Spectre 的组件代码中,泄露数据的指令为装载指令,该装载指令的地址直接 +或间接依赖于内存中的数据。在加入上述的 DIFT 检测机制后,由于该装载指令 +依赖于内存中的数据,它必定有一个被标记的源寄存器,从而处理器可以得知该 +指令不安全。 + +转移指令的标记用于处理可能泄露数据的指令,和内存中数据的值存在控制相关 +的情形,如图\ref{lst:victim_v10}的例子\supercite{msvc}: + +\begin{figure}[htbp] +\begin{minted}[frame=single,linenos=true]{C} +void victim(size_t x, uint8_t k) { + if (x < array1_size) { + if (array1[x] == k) + temp &= array2[0]; + } +} +\end{minted} +\caption{泄露数据的指令和内存中的数据存在控制相关的情形} +\label{lst:victim_v10} +\centering +\end{figure} + +这个例子读取的 \verb|array1[x]| 和攻击者猜测的值 \verb|k| 进行比较,如 +果两个值相等,则会访问 \verb|array2[0]|,即访问 \verb|array2[0]| 的指令 +和访问 \verb|array1[x]| 的指令存在控制相关,攻击者可以通过探 +测\verb|array2[0]| 是否在缓存中,判断 \verb|array1[x]| 的值是否 +和\verb|k| 相等。只使用寄存器的标记,并不能检测出读取 \verb|array2[0]| +的指令和 \verb|array1[x]| 的值存在依赖关系。 + +因此我们需要转移指令中的标记。如果一条指令在被标记的转移指令之后执行, +则该指令和一个被标记的数据存在依赖关系,如果指令为装载指令,由于它改变 +了缓存的状态,攻击者可以通过缓存信道得知该指令被执行过,推测出被标记转 +移指令的执行结果,从而推测出内存中秘密数据的值,因此这样的装载指令也是 +不安全的指令。 + +这种检测方案的微体系结构实现如图\ref{fig:spectre_dift}所示。 + +\begin{figure}[htbp] + \centering + \includegraphics[width=0.8\textwidth]{spectre_dift.eps} + \caption{基于 DIFT 的 Spectre 检测方法的微体系结构示意图} + \label{fig:spectre_dift} +\end{figure} + +\section{不安全指令的执行方式} + +对于检测到的不安全的指令,最简单的方式是阻止它的执行,直到指令因推测式 +执行错误回卷,或确认为安全状态,再重新调度至执行单元执行。这种做法会导 +致推测式执行中,后续所有依赖于这条指令的指令都会被推迟,降低流水线的利 +用率,导致性能下降。 + +一种方法是使用 InvisiSpec \supercite{invisispec},和 Spectre 攻击的检测 +机制结合后,可以作为单条不安全指令的执行机制。它将不安全指令从内存中读 +到的数据放入推测式执行缓冲区中,后续的指令可以使用这条指令的执行结果, +确保指令流的继续执行。在推测式执行错误时,推测式执行缓冲区的内容会被丢 +弃,缓存状态不会改变,因此不会产生侧信道。推测式执行被验证为安全时,缓 +冲区中的数据将会更新至存储系统。为类确保不发生访存违例 InvisiSpec 需要 +在确认指令安全后,对读到的数据做一次验证,因此需要再次访问存储系统。 + +由于缓存命中的指令不会改变缓存的内容,因此还有一种方法是在推测式执行时, +如果一级缓存命中,则允许该指令继续执行,否则中止该指令的执行,等待指令 +被回卷或转为安全的指令。如果在推测式执行时,缓存命中率高,则这种方案不 +会阻止后续指令的执行,如果程序在推测式执行中缓存命中率低,则性能损失较 +大。这种方法和 Conditional Speculation +\supercite{conditional-speculation} 中的基于缓存命中的过滤器基本相同。 + +\section{针对 Spectre 攻击的微体系结构在 gem5 中的实现} + +以下介绍这种可抵抗 Spectre 攻击的微体系结构在 gem5 模拟器中的实现。首先分 +析 gem5 中乱序执行处理器的实现,然后分别介绍 InvisiSpec 和本文使用的 +DIFT 方案在 gem5 中的实现。 + +\subsection{gem5 的乱序执行处理器} + +%\Todo: 做一个 gem5 流水线的示意图? + +gem5 的乱序执行处理器实现在 FullO3CPU 类中,它又用类实现类处理器的以下 +流水级:取指(Fetch)、译码(Decode)、重命名(Rename)、发射/执行/回 +写(IEW)、提交(Commit)。 + +gem5 的取指和译码阶段由 DefaultFetch 和 DefaultDecode 两个类实现。在 +DefaultFetch 中,取指部件从指令缓存中取出处理器 PC 位置的指令,并用指 +令系统对应的译码器进行译码,再取出指令对应的微指令,将微指令传至译码阶 +段,译码阶段再将其传到重命名阶段。取指阶段取出的指令在 DynInst 类的实 +例中保存。 + +gem5 的重命名阶段由 DefaultRename 类实现,它对指令的源寄存器和目的寄存 +器进行重命名。重命名后,指令的 DynInst 实例中的源寄存器和目的寄存器均 +保存它们对应的物理寄存器,同时还保存目的寄存器原来对应的物理寄存器用于 +恢复。 + +gem5 的发射、执行和回写三个阶段由一个类 DefaultIEW 实现,它模拟了处理 +器将指令发射至功能单元和处理器执行指令的过程。gem5 中用一个专门的语言 +定义了每个指令系统的指令的语义,为每个指令和微指令生成一个 StaticInst +类,里面定义了指令的执行方式。对于存储访问类指令,gem5 用 LSQ 类定义处 +理器中的装载和存储指令队列,这些指令在执行时添加至队列中,进行存储访问 +操作。 + +gem5 的提交阶段由 DefaultCommit 类实现,它提交 ROB 队列头部的指令,更 +新 ROB 的状态。 + +\subsection{安全执行装载指令方案的实现} + +图\ref{fig:load_exec}是 gem5 中执行一条装载指令的总体流程。 + +\begin{figure}[htbp] + \centering + \includegraphics[width=0.8\textwidth]{load_exec.eps} + \caption{gem5 O3CPU 执行装载指令的过程} + \label{fig:load_exec} +\end{figure} + +在执行阶段,处理器将装载指令传递至 LSQ,装载指令将会按序进入 LQ. gem5 +用指令系统特定的 initiatAcc 方法模拟该指令系统中装载指令访问存储系统的 +方式。最后 LSQ 将装载指令的信息封装为一个请求,用 sendTimingReq 将这个 +请求发送至存储系统。 + +发送至存储系统的读请求并不会立刻得到结果,需要等待来自存储系统的响应。 +图\ref{fig:load_exec}的右半部分是处理器接收响应的流程, +在 recvTimingResp 后,处理器可以得到此前发送的请求对应的结果,根据得到 +的结果,LSQ 执行回写操作,将结果写入至指令的目的寄存器,并将指令送至提 +交阶段,完成指令的执行。 + +对于不安全指令的执行,可以为其增加一种 SpecLoad 请求,不同于普通的Load +请求,SpecLoad 执行后,不会改变任何缓存状态和缓存一致性状态,因此不会留 +下缓存的侧信道。 + +% 一致性协议 + +对于 InvisiSpec,在指令确认安全后,还需要向存储系统再发一个请求,以验 +证 SpecLoad 读取的结果正确,或直接确认 SpecLoad 的结果,因此还需要再增 +加一个 Expose 请求,用于确认或验证结果。 + +在 gem5 中,多核系统的缓存和缓存一致性模型由 Ruby 存储系统模拟。本文模 +拟一个带二级缓存的处理器,缓存一致性协议为 MESI,需要修改的相关文件 +为 src/mem/protocol 下以 MESI\_Two\_Level 开头的文件。 + +对于一级缓存,为了增加对不安全内存读取的支持,我们修改状态机文 +件 MESI\_Two\_Level-L1cache.sm. 除了添加 SpecLoad 和 Expose 两个请求外, +还要处理从其他处理器转发的响应的请求。此外,在处理器的实现中,状态机接 +收到处理器的请求,到从存储系统得到数据之间,状态机处于一个过渡状态,因 +此在状态机中添加一个状态 IX,表示接收了 SpecLoad 之后缓存缺失,向下级存 +储系统发送读请求,还未得到响应。 + +InvisiSpec 中,一级缓存处理 SpecLoad 和 Expose 的部分状态如 +图\ref{fig:invisispec_mesi}所示。 + +\begin{figure}[htbp] + \centering + \includegraphics[width=0.8\textwidth]{invisispec_mesi.eps} + \caption{InvisiSpec 一级缓存处理 SpecLoad 和 Expose 请求} + \label{fig:invisispec_mesi} +\end{figure} + +其中,对于任意一种状态,接收到 Expose 请求后,处理器都会更新缓存状态, +将指令从存储系统中读到的数据写入缓存。对于 SpecLoad 缓存命中的情 +形,spec\_load\_hit 取出缓存行,返回至处理器,和 load\_hit 的区别是推测 +式执行中访问缓存,不会更新缓存替换算法的状态,避免产生侧信道信息。 + +% hit based + +% 而对于只在缓存命中时执行装载指令的方案,设计相对简单。它只需要处理 +% SpecLoad 请求。 + +% 在这种情形下,不需要添加额外状态。缓存行在任一状态下,接收 SpecLoad 时 +% 状态不变。缓存命中时,则执行 spec\_load\_hit 将缓存行中的内容返回至处 +% 理器。 + +% 而在缓存缺失时,则在其中添加一个 spec\_load\_miss 操作,它向处理器返回 +% 一个缓存缺失的响应。LSQ 在写回的过程中处理这个响应,为其对应的缓存缺失 +% 的指令清除表\ref{tab:inst_status}中的 ReadyToExpose 属性,并通知指令队列需 +% 要推迟这条访存指令的执行。 + +\subsection{执行流水线的修改} + +我们在 DynInst 类为指令添加新的状态和属性,添加的主要的指令状态和属性 +见表\ref{tab:inst_status}。 + +\begin{table} +\begin{tabular}{|p{0.25\textwidth}|p{0.75\textwidth}|} +\hline +指令状态和属性 & 含义\tabularnewline +\hline +\hline +PrevBrsResolved & 记录指令之前的分支是否得出结果\tabularnewline +\hline +IsTainted & 在基于 DIFT 的检测方案中,记录指令是否依赖于被标记的寄存器\tabularnewline +\hline +AfterTaintedBranch & 在基于 DIFT 的检测方案中,记录指令是否在被标记的转 + 移指令之后\tabularnewline +\hline +L1Hit & 记录指令的 SpecLoad 请求是否命中一级缓存并且缓存内容不变,如果 + 是,则不需要发送验证请求\tabularnewline +\hline +ExposeSent & 已发送 Expose 请求\tabularnewline +\hline +ExposeCompleted & Expose 已执行完成\tabularnewline +\hline +ValidationCompleted & 数据已验证完成\tabularnewline +\hline +NeedPostFetch & 需要再次发送 Expose 请求\tabularnewline +\hline +ReadyToExpose & 指令已确认安全,可以发送 Expose 请求,或直接用基本的方 + 式执行指令\tabularnewline +\hline +NeedExposeOnly & 只需要发送 Expose,而不需要通过再次读取数据用于验证\tabularnewline +\hline +FenceDelay & 指令被阻止执行,直到确认安全,在 InvisiSpec 之外的执行方 + 案中使用\tabularnewline +\hline +\end{tabular} +\caption{新增的指令状态} +\label{tab:inst_status} +\centering +\end{table} + +在每一周期,处理器扫描 ROB 中的每条指令,更新流水线中每条指令的 +PrevBrsResolved 状态。在 LSQ 中,对于每一个未完成的装载指令,根据指令 +之前是否存在未决分支,判断指令是否安全,设定 ReadyToExpose 属性,取消 +FenceDelay 标志。 + +执行单元执行一条装载指令时,根据 ReadyToexpose 属性判断是否需要用 +InvisiSpec 等安全的方式执行。修改后的执行流程如图\ref{fig:is-load}, +LSQ 每周期都要将已转为安全指令的装载指令的验证或曝光,发送请求的 +LSQUnit::read 过程需要支持 SpecLoad 请求的发送,对地址翻译的过程做一个 +微小的修改,对 TLB 不命中的推测式执行的指令要延迟执行,防止产生 TLB 的 +侧信道。 + +\begin{figure}[htbp] + \centering + \includegraphics[width=0.8\textwidth]{is-load.eps} + \caption{安全执行指令的流程} + \label{fig:is-load} +\end{figure} + +\subsection{动态信息流追踪的实现} + +动态信息流追踪的实现分为标记设置、传播、清除和使用四个部分,以下分别介 +绍它们在 gem5 中的实现。 + +对所有推测式执行中的装载指令,其目的寄存器都需要设置标记。在扫描 LSQ +中指令的时候,指令前存在未决分支,则对这个指令的目的寄存器设置标记。 + +标志的传播在执行阶段进行。对于非访存类指令,如果指令有设置了标记的源寄 +存器,则设置该指令的目的寄存器的标记。同时也设置指令的 IsTainted 属性, +它作为转移指令的标记。 + +指令的 IsTainted 属性和目的寄存器的标记在更新 ROB 中每条指令 +的 PrevBrsResolved 状态的时候清除,这个过程同时更新指令 +的 AfterTaintedBranch 属性。 + +标记的使用在更新 LSQ 中指令状态的时候发生,在加入动态信息流追踪的设计中, +指令的 ReadyToExpose 属性设定的条件有:(1)指令已设置 +了 PrevBrsResolved 属性,或者(2)AfterTaintedBranch 未设置,并且源寄存 +器均未被标记。 -\section{基于信息流追踪的Spectre检测方法} +\section{小结} -\section{可抵抗Spectre攻击的微架构的实现} +本章前两节介绍本文设计的基于信息流追踪的 Spectre 组件的检测方法,讨论 +了执行可能泄露数据的装载指令的几种方法。第三节介绍了在 gem5 中实现这些 +技术的方法,包括对 gem5 流水线的分析,gem5 装载指令执行流程的分析,对 +执行流水线作出的修改,实现装载指令安全执行的方法。 diff --git a/chap/chap5.tex b/chap/chap5.tex index df3e01b..2c83fe3 100644 --- a/chap/chap5.tex +++ b/chap/chap5.tex @@ -1,11 +1,260 @@ -\chapter{评测} +\chapter{功能验证与性能评测}\label{sec:eval} + +本文设计了一种可用于防御 Spectre 攻击的微体系结构。本章对这种微体系结构进行功能验证,说明它满足威胁模型所要求的安全性质,并且对这种设计进行性能评测。 \section{评测环境} +本文对 gem5 模拟器修改,对以下 5 种配置进行评测:Baseline, Fence, +Fence+DIFT, IS, IS+DIFT. Baseline 表示受 Spectre 攻击影响的处理器模型, +Fence 和 IS 分别表示对所有推测式执行中的装载指令,推迟执行和用 +InvisiSpec的方案执行,Fence+DIFT 和 IS+DIFT 则是使用动态信息流追踪识别 +可能泄露秘密数据的装载指令,只对这些装载使用相应的安全的执行方案。 + +表\ref{tab:gem5_conf}中列出了所有处理器配置的基本配置。 + +\begin{table} +\centering +\caption{模拟的处理器的基本配置} +\label{tab:gem5_conf} +\begin{tabular}{|c|c|} +\hline +参数 & 配置 \tabularnewline +\hline +\hline +指令系统 & x86\_64\tabularnewline +\hline +\multirow{9}{*}{功能单元} & IntAlu\tabularnewline +\cline{2-2} + & IntMult + IntAlu\tabularnewline +\cline{2-2} + & FloatAdd + FloatCmp + FloatCvt\tabularnewline +\cline{2-2} + & FloatMult + FloatMultAcc + FloatMisc + FloatDiv + FloatSqrt\tabularnewline +\cline{2-2} + & MemRead + FloatMemRead\tabularnewline +\cline{2-2} + & SIMD\tabularnewline +\cline{2-2} + & MemWrite + FloatMemWrite\tabularnewline +\cline{2-2} + & MemRead + MemWrite + FloatMemRead + FloatMemWrite\tabularnewline +\cline{2-2} + & IprAccess\tabularnewline +\hline +提交宽度 & 8\tabularnewline +\hline +ROB & 192\tabularnewline +\hline +LDQ & 32\tabularnewline +\hline +STQ & 32\tabularnewline +\hline +发射队列大小 & 64\tabularnewline +\hline +转移预测 & TournamentBP, 4096 BTB, 16 RAS\tabularnewline +\hline +L1 I-Cache & 32KB, 4路组相联, 1周期延迟\tabularnewline +\hline +L1 D-Cache & 64KB, 8路组相联, 1周期延迟\tabularnewline +\hline +L2 Cache & 2MB, 16路组相联, 8周期延迟\tabularnewline +\hline +\end{tabular} +\end{table} + \section{评测指标} -\section{评测结果} +本文评测每种微体系结构设计的安全性和性能。安全性表现为是否受 Spectre +攻击的影响,本文构造测试程序测试微体系结构的安全性。性能指标使用每个微 +体系结构设计运行基准程序,和 Baseline 的运行时间的比值,平均性能取这些 +比值的几何平均数。 + +\subsection{功能验证} + +本文构造一个测试程序对每种配置的处理器进行安全性的测试,用于验证实现的 +方案可以防御 Spectre 攻击。 + +由于 gem5 的 Ruby 存储模型不支持 clflush 指令,因此测试程序使 +用Evict+Reload 的方式进行攻击。由于配置的系统末级缓存为 2MB,可以对一 +个2MB 的存储区域进行访问,以清除缓存内原有内容,具体代码可 +见附件\ref{lst:poc_for_gem5}。 + +在此验证程序中,攻击者要通过受害者执行的函数 victim 的推测式执行泄 +露 victim 在正常执行中无法访问的 X 的值。攻击者先训练 victim 的分支预测 +器,清除缓存中原有的内容,之后我们设置 X 为 123,然后攻击者再让 victim +执行访问 X,最后扫描 array2 检查其中是否有元素在缓存中命中。 + +在 Baseline 配置中,执行上述程序,可以看到 \verb|array2[123 * 64]| 在 +缓存中命中,在 array2 的其他位置缓存缺失,从而攻击者可以通过 Spectre +攻击得到 X 的值 123. 而在其他配置中,array2 的所有位置都发生缓存缺失, +从而攻击者无法得出 X 的值,说明这些配置都能防御 Spectre 攻击。 + +\section{SPEC CPU2006 的性能评测与分析} + +本文对 21 个 SPEC CPU2006 基准测试进行评测,基准测试的数据集使用 ref +集。所有的基准程序均用 GCC 8.3.0 编译,编译优化选项为 -O2,并且和 +Glibc 2.24 静态链接。 + +由于 gem5 模拟器运行 SPEC CPU2006 所需时间过长,因此评测时选取部分指令, +方法是先用 gem5 的 AtomicSimpleCPU 运行 10000000000 条指令进行程序的预 +热,再用待评测的处理器配置运行 1000000000 条指令,得出评测结果。 + +%% 表\ref{tab:spec2006}中列出每个 SPEC CPU2006 在 Baseline 模式下运行的指 +%% 令数和操作数,在其他处理器配置下,实际运行的指令数可能有增加或减少,相 +%% 应的操作数也有增加或减少。 + +%% \begin{table} +%% \begin{tabular}{|c|c|c|c|} +%% \hline +%% 基准测试程序 & 类型 & 指令数 & 操作数\tabularnewline +%% \hline +%% \hline +%% 401.bzip2 & int & 1000000015 & 1607899217\tabularnewline +%% \hline +%% 429.mcf & int & 1000000012 & 1308544223\tabularnewline +%% \hline +%% 445.gobmk & int & 1000000014 & 1932674840\tabularnewline +%% \hline +%% 456.hmmer & int & 1000000013 & 1980694497\tabularnewline +%% \hline +%% 458.sjeng & int & 1000000010 & 1827828221\tabularnewline +%% \hline +%% 462.libquantum & int & 1000000011 & 1714852019\tabularnewline +%% \hline +%% 464.h264ref & int & 1000000017 & 1545541668\tabularnewline +%% \hline +%% 471.omnetpp & int & 1000000011 & 1971636254\tabularnewline +%% \hline +%% 473.astar & int & 1000000010 & 1702905457\tabularnewline +%% \hline +%% 410.bwaves & fp & 1000000011 & 1839010239\tabularnewline +%% \hline +%% 433.milc & fp & 1000000018 & 1285963875\tabularnewline +%% \hline +%% 434.zeusmp & fp & 1000000014 & 1524235186\tabularnewline +%% \hline +%% 435.gromacs & fp & 1000000013 & 1630938771\tabularnewline +%% \hline +%% 436.cactusADM & fp & 1000000014 & 1320986203\tabularnewline +%% \hline +%% 437.leslie3d & fp & 1000000010 & 1415843900\tabularnewline +%% \hline +%% 444.namd & fp & 1000000009 & 1333316425\tabularnewline +%% \hline +%% 450.soplex & fp & 1000000013 & 1664925057\tabularnewline +%% \hline +%% 454.calculix & fp & 1000000010 & 1691328153\tabularnewline +%% \hline +%% 459.GemsFDTD & fp & 1000000014 & 1320385828\tabularnewline +%% \hline +%% 470.lbm & fp & 1000000011 & 1191402714\tabularnewline +%% \hline +%% 482.sphinx3 & fp & 1000000016 & 1618883137\tabularnewline +%% \hline +%% \end{tabular} +%% \caption{SPEC CPU2006 各基准程序的指令数和操作数} +%% \label{tab:spec2006} +%% \end{table} + +图\ref{fig:is_spec06_result}是每种配置的处理器运行 SPEC CPU2006 相对于 +Baseline 的运行时间。其中 cactusADM 和 lbm 由于每种配置的相对运行时间 +都接近 1,故未列入图中。 + +\begin{figure}[htbp] + \centering + \includegraphics[width=\textwidth]{result.eps} + \caption{每种配置的处理器运行 SPEC CPU2006 的相对运行时间} + \label{fig:is_spec06_result} +\end{figure} + +从评测结果可以看出,在使用 DIFT 识别可能泄露数据的装载指令后,推迟这 +些指令的执行,有 15\% 的性能开销,平均性能开销比 InvisiSpec 小。在此基 +础上,用 InvisiSpec 的方案执行这些装载指令,可以进一步将性能开销减少 +至 8.5\%. 其中在 IS+DIFT 方案中,有 12 个基准程序的性能开销在 3\% 以下, +6 个在 10\% 至 20\%. 性能开销最大的是 omnetpp, 所有安全的方案都会造成 +94\% 以上的性能开销。 + +\begin{figure}[htbp] + \centering + \includegraphics[width=\textwidth]{specload_ratio.eps} + \caption{SPEC CPU2006 中 SpecLoad 在所有操作中的比例} + \label{fig:specload} +\end{figure} + +%% \begin{table}[htbp] +%% \begin{tabular}{|c|c|c|c|} +%% \hline +%% 基准测试 & IS & IS+DIFT & SpecLoad 减少量\tabularnewline +%% \hline +%% \hline +%% astar & 34.80\% & 19.79\% & 43.13\%\tabularnewline +%% \hline +%% bwaves & 10.75\% & 0.23\% & 97.89\%\tabularnewline +%% \hline +%% bzip2 & 12.12\% & 5.49\% & 54.74\%\tabularnewline +%% \hline +%% cactusADM & 0.51\% & 0.13\% & 74.51\%\tabularnewline +%% \hline +%% calculix & 9.89\% & 3.06\% & 69.04\%\tabularnewline +%% \hline +%% GemsFDTD & 6.29\% & 0.13\% & 97.91\%\tabularnewline +%% \hline +%% gobmk & 12.61\% & 2.60\% & 79.38\%\tabularnewline +%% \hline +%% gromacs & 0.76\% & 0.06\% & 92.74\%\tabularnewline +%% \hline +%% h264ref & 5.43\% & 0.94\% & 82.68\%\tabularnewline +%% \hline +%% hmmer & 9.52\% & 4.82\% & 49.35\%\tabularnewline +%% \hline +%% lbm & 1.39\% & 0.00\% & 100.00\%\tabularnewline +%% \hline +%% leslie3d & 5.98\% & 0.11\% & 98.23\%\tabularnewline +%% \hline +%% libquantum & 1.99\% & 0.00\% & 99.99\%\tabularnewline +%% \hline +%% mcf & 10.56\% & 2.11\% & 79.99\%\tabularnewline +%% \hline +%% milc & 3.22\% & 0.10\% & 97.04\%\tabularnewline +%% \hline +%% namd & 2.67\% & 0.84\% & 68.73\%\tabularnewline +%% \hline +%% omnetpp & 5.94\% & 1.94\% & 67.37\%\tabularnewline +%% \hline +%% sjeng & 13.19\% & 2.72\% & 79.35\%\tabularnewline +%% \hline +%% soplex & 9.68\% & 4.63\% & 52.22\%\tabularnewline +%% \hline +%% sphinx3 & 6.63\% & 1.41\% & 78.68\%\tabularnewline +%% \hline +%% zeusmp & 6.70\% & 0.03\% & 99.58\%\tabularnewline +%% \hline +%% \end{tabular} +%% \centering +%% \caption{SPEC CPU2006 中 SpecLoad 在所有操作中的比例} +%% \label{tab:specload} +%% \end{table} +%% +为了观察使用基于信息流追踪的检测机制的效果,可以统计 IS 和 IS+DIFT 方 +案中 SpecLoad 请求的数量。图\ref{fig:specload}列出两种方案中,SpecLoad +请求的数量和程序的总操作数(gem5 模拟后得出的 sim\_ops 结果)的比例。 + +可以看出,几乎所有的基准程序中,DIFT 可以过滤一半以上被认为不安全的装 +载操作,其中 bwaves, GemsFDTD, libquantum, milc 中,推测式执行中的装载 +指令只有 3\% 以下需要用安全的方式执行,因此使用 Fence+DIFT 即可以获得 +与 Baseline 几乎同等的性能。 + +在 IS+DIFT 性能开销最大的 omnetpp 中,SpecLoad 的数量只减少了 67\%,而 +性能开销接近 20\% 的 calculix 和 astar,SpecLoad 减少的数量也在 70\% +以下。而在 calculix 和 astar 中,对不安全的装载指令,用 InvisiSpec 策 +略执行,比阻止这些指令的执行,有明显的性能提升。 -\subsection{微架构安全性测试} +%\Todo: 评测结果的分析 +\section{小结} -\subsection{SPEC CPU2006的性能评测} +本章先介绍了评测环境,列出了各个处理器配置的基本参数。其后给出了评测指 +标,包括安全性的测试和性能测试的指标。最后给出了安全测试的方法和结果, +以及用 SPEC CPU2006 进行性能评测得出的性能结果与分析。功能验证表明,本 +文使用的基于 DIFT 的检测方法和 InvisiSpec 装载指令执行策略,都能阻止 +Spectre 攻击泄露内存中的数据。通过将这两种方法结合,防御 Spectre 攻击 +的性能开销为 8.5\%. diff --git a/chap/chap6.tex b/chap/chap6.tex index 08b5e49..2b40f0d 100644 --- a/chap/chap6.tex +++ b/chap/chap6.tex @@ -1,5 +1,39 @@ -\chapter{总结与展望} +\chapter{总结与展望}\label{sec:conclusion} -\subsection{本文工作总结} +\section{本文工作总结} -\subsection{未来工作展望} +计算机系统的安全越来越受到重视,基于软件的微架构侧信道攻击是对计算机系 +统安全的威胁之一,它不依赖于软件漏洞,难以被检测与防 +范。Meltdown 和Spectre 利用暂态指令形成的侧信道,展示了一种新的攻击方式。 +其中 Spectre利用了现代微处理器的推测式执行机制,而推测式执行是提高指令 +级并行性的重要手段,如何在防御 Spectre 的同时保持推测式执行带来的性能提 +升,是一个值得研究的问题。只通过软件的修改难以防御多种类型的 Spectre +攻击,因此需要通过改进微架构的设计,以解决 Spectre 攻击的问题。本文主 +要工作如下: +\begin{itemize} +\item 首先调研已有的 Meltdown 和 Spectre 的攻击变体,包括 + 对 Meltdown 和 Spectre 的分类,各类攻击的原理,和它们的利用方式。 +\item 调研已有的 Meltdown 和 Spectre 的防御方法,包括软件防御、硬件防御 + 和软硬件结合的防御方法。其中最重要的是硬件防御方法,主要介 + 绍InvisiSpec 和 Conditional Speculation 两种,并分析了各种防御方案设 + 计特点,可防御的攻击种类,和它们的优缺点。 +\item 设计一种防御防御 Spectre 攻击的微架构,并在 gem5 中进行实现。这种 + 防御方案利用动态信息流追踪技术检测指令流中可能被用于 Spectre 攻击泄露 + 数据的装载指令,并采用 InvisiSpec 方案执行检测为不安全的装载指令。 +\item 最后对实现的 Spectre 防御方案进行评估,首先构造了一个能用于 gem5 + 的概念性验证程序,用于测试所实现的微架构的安全性。为了评估这种微架构 + 的性能开销,使用 SPEC CPU2006 评测了这种微架构的性能,和原有的不安全 + 的处理器相比,性能开销为 8.5\%,优于只用 InvisiSpec 执行推测式执行的 + 指令或阻止检测出的不安全指令的方法。 +\end{itemize} + +\section{未来工作展望} + +本文实现了一种 Spectre 攻击中泄露数据指令的检测技术,并结合已有 +的InvisiSpec 方案,实现了一种可防御 Spectre 攻击的微架构。当前的工作只 +考虑了利用控制流推测式执行的 Spectre 攻击,后续的工作可以加入 +对 Spectre-STL 攻击的防御,再评估此模型的性能开销。 + +此外,本工作只在模拟器中进行模拟,而未在真实的处理器中实现。后续的工作 +可以在 RISC-V BOOM 等真实处理器上实现这种微架构设计,以评估这种设计在 +实现中的可行性,和对真实处理器性能、功耗的影响。 diff --git a/chap/encl1.tex b/chap/encl1.tex index 1858c65..6a8e62a 100644 --- a/chap/encl1.tex +++ b/chap/encl1.tex @@ -3,4 +3,66 @@ \chapter{附件} -% vim:ts=4:sw=4 +\section{在 gem5 中验证处理器模型安全性的代码}\label{lst:poc_for_gem5} + +\begin{minted}{C} +#include <stdio.h> +#include <stdint.h> +#include <string.h> +#include <x86intrin.h> + +/* default: 64B line size, L1-D 64KB assoc 2, L1-I 32KB assoc 2 + , L2 2MB assoc 8 */ +#define LLC_SIZE (2 << 20) + +uint8_t dummy[LLC_SIZE]; +size_t array_size = 4; +uint8_t array1[200] = {1, 2, 3, 4}; +uint8_t array2[256 * 64 * 2]; +uint8_t X; +uint8_t array3[4096]; +uint8_t tmp; + +uint8_t victim(size_t idx) +{ + if (idx < array_size) { + return array2[array1[idx] * 64]; + } + return 0; +} + +int main() +{ + unsigned long t[256]; + volatile uint8_t x; + + victim(0); + victim(0); + victim(0); + victim(0); + victim(0); + + memset(dummy, 1, sizeof(dummy)); // flush L2 + X = 123; // set the secret value, and also bring it to cache + + _mm_mfence(); + + size_t attack_idx = &X - array1; + victim(attack_idx); + + for (int i = 0; i < 256; i++) { + unsigned int junk; + unsigned long time1 = __rdtscp(&junk); + x ^= array2[i * 64]; + unsigned long time2 = __rdtscp(&junk); + t[i] = time2 - time1; + } + + printf("attack_idx = %ld\n", attack_idx); + for (int i = 0; i < 256; i++) { + printf("%d: %d, %s\n", i, t[i], + (t[i] < 40)? "hit": "miss"); + } +} +\end{minted} + diff --git a/chap/origin.tex b/chap/origin.tex index 49d25b5..d0ac318 100644 --- a/chap/origin.tex +++ b/chap/origin.tex @@ -34,7 +34,7 @@ % 学校书面要求本页面不要页码,但在给出的 Word 模版中又有页码且编入了目录。 % 此处以 Word 模版为实际标准进行设定。 - \specialchap{北京大学学位论文原创性声明和使用授权说明} + \chapter*{北京大学学位论文原创性声明和使用授权说明} \mbox{}\vspace*{-3em} \section*{原创性声明} |