\chapter{可抵抗Spectre攻击的微架构的设计与实现}\label{sec:mywork} 本章讲解本文提出的一种防御 Spectre 攻击的方法,该方法使用动态信息流追 踪的方法,检测 Spectre 组件指令流中可能泄露秘密数据的访存指令,并使用 InvisiSpec 的方法执行这些访存指令。 %这个设计有如下特点: %\begin{itemize} %\item 它不需要任何软件修改 %\item \section{威胁模型} 本文对攻击者做如下假设:攻击者知道受害者程序的代码、进程中的地址分布信 息,攻击者和受害者可以在同一进程,共享同一处理器核,或在不同处理器核上。 本文设计的方法用于防御利用控制流推测式执行的 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} CSF\supercite{context-sensitive-fencing} 中的译码级信息流追踪框架 DIFT, 用于追踪处理器使用的数据是否来源于用户输入,从而处理器可以根据此信息判 断是否需要插入 fence 微码。OISA\supercite{oisa} 在指令系统的定义中即包 含了 DIFT 技术,用于追踪一个数据是否为秘密数据。 本文使用 DIFT 检测 Spectre 组件中泄露数据的 load 指令。详细设计如下: \begin{itemize} \item 为每个物理寄存器添加一位标记,表示这个寄存器的数据是否来自于推测 式执行中从内存读取的数据 \item 如果在推测式执行中,一条指令从内存中读取了数据,则设置这条指令的 目的寄存器的标志为1 \item 对于非访存指令,如果存在标记为1的源寄存器,则设置这条指令的目的 寄存器标志为1,否则设置标志为0 \item 当一条指令之前所有分支指令执行完成,确认推测式执行正确后,设置这 条指令的目的寄存器标志为0 \item 在推测式执行的过程中执行 load 指令时,如果存在标记为1的源寄存器, 则这条指令为不安全的 load \end{itemize} 以上 DIFT 实现只考虑了泄露的 load 指令和读取秘密数据的 load 指令存在数 据相关,此外还要考虑控制相关的情形,如以下例子\supercite{msvc}: \begin{minted}{C} void victim(size_t x, uint8_t k) { if (x < array1_size) { if (array1[x] == k) temp &= array2[0]; } } \end{minted} 这个例子读取的 \verb|array1[x]| 和攻击者猜测的值 \verb|k| 进行比较,如 果两个值相等,则会访问 \verb|array2[0]|,即访问 \verb|array2[0]| 的指 令和访问 \verb|array1[x]| 的指令存在控制相关,对 \verb|array2[0]| 的访 问可能泄露 \verb|array1[x]| 的数据。因此,如果一条控制指令依赖于被标记 的寄存器,则对它进行标记,其后的所有 load 指令都认为不安全。 \section{可抵抗 Spectre 攻击的微架构的实现} 以下介绍这种可抵抗 Spectre 攻击的微架构在 gem5 模拟器中的实现。首先分 析 gem5 中乱序执行处理器的实现,然后分别介绍 InvisiSpec 和本文使用的 DIFT 方案在 gem5 中的实现。 \subsection{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{InvisiSpec 的实现} % 本文使用 InvisiSpec 执行检测为不安全的 load 指令。相对于阻止该 load 指 % 令的执行,使用 InvisiSpec 执行该指令,可以使依赖于这个指令的指令可以继 % 续执行,减少性能损失。以下分析 InvisiSpec 的详细设计,在下一节中分析将 % xSpectre 检测技术和 InvisiSpec 结合的方法。 % InvisiSpec 使用推测式执行缓冲区保存推测式执行中 load 指令得到的数据, % 这部分代码在。 \subsection{动态信息流追踪的实现}