\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检测方法}

\Todo: 这一节是否可以写到3页？

动态信息流追踪（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 技术，用于追踪一个数据是否为秘密数据。

以图\ref{lst:spectre_v1}的 Spectre v1 组件代码为例，这段代码产生
图\ref{lst:spectre_v1_asm}所示的指令。

\begin{figure}[htbp]
\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}
\end{figure}

这些指令中，在分支后执行的指令，DIFT 的行为如表\ref{tab:spectre_dift}所示。

\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}
\end{table}

本文使用 DIFT 检测 Spectre 组件中泄露数据的 load 指令。详细设计如下：

\Todo: 解释为什么使用这种方法，和其他相似方法（DLIFT, TPBuf, SG(Full)）的比较

\Todo: 增加结构示意图和代码描述

\Todo: 使用更加详细的描述

\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 指令都认为不安全。

\Todo: 解释怎样处理以上的情形

\section{使用推测式执行缓冲区}

\Todo: 说明在检测到不安全的访存指令后，推迟它的执行和用 InvisiSpec 的 SpecBuf 执行的区别

\Todo: 为什么只对部分指令使用，对推测式执行中的部分指令使用 InvisiSpec 是否需要修改

\Todo: 本文使用的基于 DIFT 的检测方法和 InvisiSpec 结合

\section{针对 Spectre 攻击的微架构在 gem5 中的实现}

\Todo: 这节介绍怎样在 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{InvisiSpec的LSQ的实现}

\Todo: InvisiSpec 所用的 load 指令执行逻辑在 gem5 LSQ 中的实现

\subsection{推测式执行缓冲区的实现}

\Todo: InvisiSpec 的 SpecBuf 在 gem5 中的实现

\subsection{InvisiSpec对缓存一致性协议的修改}

\Todo: InvisiSpec 的 SpecBuf 在 gem5 中的实现

\subsection{动态信息流追踪的实现}

\Todo: 本文所用的 DIFT 方案在 gem5 中的实现，和已有 InvisiSpec 代码的结合

\Todo: 如何添加一个总结性的章节？
