% Copyright (c) 2014,2016,2018 Casper Ti. Vector
% Public domain.

\chapter{Meltdown和Spectre攻击的防御方案分析}\label{sec:defense}

Meltdown 和 Spectre 及其多种变体被发现后，研究者提出了多种减轻这些攻击
的防御方法，它们需要对软件或硬件进行修改。也有研究者提出通过修改现有的
指令系统\supercite{oisa}，使得用这种指令系统的程序不受 Spectre 攻击的
影响。

\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} 技术，它的作用是在指令
流中添加数据相关，使得装载指令使用的地址依赖于分支结果。

retpoline\supercite{retpoline} 是 Google 提出的防御 Spectre-BTB 的方法。
它的作用是把程序中的间接转移指令修改为一个指令序列，最终使用 ret 指令
完成跳转，从而使用 RSB 而不是 BTB 来进行间接转移的转移预测。

% index masking
Webkit 在数组访问中使用 index masking\supercite{webkit} 方法，它让数组
下标和一个值进行与操作，去掉下标高位的1，将数组下标控制在一定范围内，
防止处理器在推测式执行中访问数组指定范围之外的数据。Linux 构造了一个粒
度更细的 array\_index\_nospec 宏\supercite{linux-spec}，使得在推测式执
行的过程中，数组的索引始终在界内，避免了推测式的访问秘密数据。

% poison value
Webkit 还使用了指针投毒（pointer poisoning）的方式，它考虑分支用于做类
型检查的情形。对于不同类型的数据，Webkit 将这种类型的指针和一个类型对
应的值异或，要使用的时候再异或这个值得到指向数据的指针，如果类型不匹配，
则得到的指针会指向一个程序无法访问的内存区域。通过这种方法，程序在推测
式执行中无法通过这种指针访问到程序中的数据，从而避免了秘密数据的泄露。

% site isolation, FIXME: needs citing
Google 为 Chrome 浏览器使用了站点隔离（site isolation）技术，使得浏览
器用不同的进程访问不同的网站，从而攻击者无法通过用 Javascript 通过侧信
道攻击获取另一站点相关的数据。

% timer reduction
降低计时器精度可以降低计时攻击所用侧信道的精度，一个例子是在浏览器中降
低 Javascript 引擎中 performance.now 等计时器的精度。
\supercite{webkit} 但是相关研究发现，攻击者可以使用其他方式构造高精度
的计时器\supercite{js-timer}，因此降低计时器精度不是一个有效的防御方法。


\subsection{硬件防御方案}

\subsubsection{SafeSpec}

SafeSpec\supercite{safespec} 提出了一种设计准则：使用临时结构保存推测式执行产
生的状态，而不影响处理器的主要微架构状态。在实现中，SafeSpec 为缓存和
TLB 添加了影子结构，推测式执行的指令对缓存和 TLB 修改临时写入至相应的
影子结构，直到此前分支正确或指令提交时，再将影子结构的数据更新至主结构。

\subsubsection{InvisiSpec}

InvisiSpec\supercite{invisispec} 和 SafeSpec 类似，使用一个称为推测式
执行缓冲区（Speculative Buffer）的结构存放推测式执行的 load 指令从存储
系统中获取的数据，直到这条指令安全的时候再让它更新缓存。和 SafeSpec 不
同的是，InvisiSpec 考虑了缓存一致性和存储一致性的问题，在 load 指令确
认安全之后，增加一个验证的步骤，确认使用没有违反存储一致性。

在 gem5 模拟器下， 使用 SPEC CPU2006 和 PARSEC 对 InvisiSpec 进行评测，
以 Spectre 为威胁模型，在 TSO 内存模型下，InvisiSpec 平均性能损失为
21\%，而使用 fence 性能下降 74\%.

\subsubsection{DAWG}

Dynamic Allocated Way Guard(DAWG)\supercite{dawg} 是一种防御缓存侧信道
攻击的缓存设计。DAWG让不同的程序使用不同的安全域，一个安全域中的程序只
能使用缓存中的某些路，和 Intel CAT 允许程序在缓存任意一路命中不同，
DAWG 不允许程序在安全域规定的路之外中发生缓存命中。

在 zsim 模拟器中使用 SPEC CPU2006, PARSEC, GAPBS 进行模拟，相对于
Intel CAT，在不同的评测程序和划分方式下，大多数程序性能下降为 4\%\~7\%.

DAWG 的主要缺点是需要操作系统的支持。此外，DAWG 不能防御 NetSpectre 等可
在同一安全域内进行的攻击。

\subsubsection{Context-Sensitive Fencing}

Context-Sensitive Fencing(CSF)\supercite{context-sensitive-fencing} 是
一种微码级防御多种类型 Spectre 攻击的方法。它基于 Context-Sensitive
Decoding (CSD)\supercite{context-sensitive-decoding}，一种微码翻译机制
的扩展，用于动态按需自定义微操作指令流。CSF 利用 CSD，在微指令流中注入
fence 等微码，阻止不安全指令的推测式执行。为了降低 fence 的性能开销，
CSF 还提出了3种新的用于防御 Spectre 的 fence.

CSF 由以下几个关键部件组成：
\begin{itemize}
\item 微码自定义机制 CSD：使处理器精确地在指令流中插入 fence，减轻推测
  式执行中不期望的副作用
\item 译码级信息流追踪（DLIFT）框架：用于检测潜在不安全的执行模式，触
  发微码自定义机制
\item 错误训练防御：用于保护分支预测器、返回地址栈等部件
\end{itemize}

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{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}

在条件推测式执行的流水线中，在发射队列中引入了安全冒险检测，以识别具有
安全依赖的可疑的不安全指令。只要在执行阶段确认了真正的冒险，那些不安全
的推测式执行将会使用现有的重执行和推测式执行恢复机制终止并丢弃。

% the following is from gtran

我们设计了基于比特矩阵的安全检测逻辑，如图2所示。比特矩阵是一些商品处理器用来跟踪数据依赖和年龄信息的流行方式[26]，[27]，[28]。通常，数据依赖矩阵和年龄矩阵一起可以确定要发布的指令。对于安全检测模块，安全依赖矩阵还必须确定要发布的指令是否具有任何安全依赖性。

矩阵组织：安全依赖矩阵需要有效地支持行和列访问。假设问题队列具有N个项，则安全依赖性矩阵将包含NxN位的寄存器阵列。它由IQPos（问题队列位置）编制索引。此矩阵的读端口数等于调度宽度，写端口数等于发布宽度。给定任何指令X，IQPos X表示其在问题队列中的位置。如果Matrix [IQPos X，IQPos Y]的值为1，则X对Y具有安全依赖性。否则，这意味着它们之间没有安全依赖性。矩阵初始化：当新指令X被分派到问题队列中时，一个条目被分配索引IQPos X.对于此时在问题队列中有效的每个指令Y，计算Matrix [IQPos X，IQPos Y]根据以下公式。

Matrix[X, Y ] = (IssueQ[X].opcode == MEMORY)
and (IssueQ[Y ].opcode == MEMORY or BRANCH)
and IssueQ[Y ].valid
and \!IssueQ[Y].issued

此公式基于以下逻辑来确定指令之间的安全依赖性。首先，如果在X被分派到问题队列之前Y是有效的，则意味着Y在X之前。其次，对于Specter变体，我们仅检查存储器指令是否依赖于先前的分支或存储器指令。第三，如果在发出存储器指令时，先前的分支或存储器指令仍然在问题队列中等待，则该存储器指令将被认为具有安全依赖性。

危险检测：图2说明了问题队列的三个阶段选项。在第一阶段，数据依赖矩阵生成依赖向量。在第二阶段，然后将该向量发送到年龄矩阵以选择要发布的最早的就绪指令。在第3阶段，对于选择发布的那些指令，查询安全依赖矩阵以获得它们的安全依赖性，然后更新问题队列的相应条目的状态。特别是，安全依赖矩阵的每一行中的位由OR运算处理，结果表明是否存在潜在的安全隐患。当选择发出一条指令并检测到安全危险时，它将被标记为可疑推测标记。

依赖性清除：在发出一条指令X后，更新向量寄存器中的相应位将被设置为0.由IQPos X索引的安全依赖矩阵列将在下一个周期复位。这种操作意味着清除了相应指令和X之间的安全依赖性。

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


为了性能，安全性和透明性的平衡，条件推测式执行提出了两种过滤机制，以找
出错误识别的安全安全冒险。基于缓存命中的冒险过滤器针对命中缓存的推测式
执行指令。因为它们的推测式执行不会改变缓存的内容，所以它们是安全的。
另一个提出的过滤器，基于可信页面缓冲区（Trusted Page Buffer, TPBuf）的
冒险过滤器，从另一个角度识别安全的推测推测式执行的指令。对于使用基于共
享内存（例如 Flush+Reload）的缓存侧通道攻击窃取内存信息的 Spectre 变体，
他们对恶意组件的推测式执行具有名为 S-Pattern 的共同特征。 TPBuf 从所有
推测式执行中捕获 S-Pattern，对于任何推测式执行的访存指令，如果它与
S-Pattern 不匹配，则被认为是安全的。

% gtran

一种简单的危险消除方法是简单地阻止在发布队列中标记有可疑推测标记的所有指令。这样的政策显然会导致性能下降。同时，只有导致高速缓存未命中的内存请求将改变高速缓存内容，并且大多数应用程序表现出良好的时间和空间局部性。受这两个观察的启发，基于缓存命中的危险过滤器被提议用于减少保守地不执行具有可疑推测标记的指令的性能影响。

% hit-based

对于标记有可疑推测标志的存储器指令，它将被推测性地发布到存储器访问管线。如果推测性存储器访问命中L1高速缓存，则其执行将继续作为正常存储器指令。但是，如果遇到L1高速缓存中的未命中，则丢弃的请求将被丢弃。信号从L1高速缓存发送回问题队列，重新发出逻辑应该应用于存储器指令，直到其安全依赖性得到解决。这些被阻止的指令在发布队列中等待安全依赖性在重新发布之前清除。此设计仅需要L1高速缓存控制逻辑中的最小更改：将不会处理具有可疑推测标记的未命中请求。

% TPBuf
基于缓存命中的危险过滤器仅考虑在L1 DCache中命中的推测性内存指令是安全的，并允许它们被推测性地执行。对于具有高L1 DCache未命中率的应用程序，它将无法恢复投机执行的大部分好处。对于这些应用，我们提出了一种新的危险过滤器可信页面缓冲器（TPBuf）来检测L1 DCache中丢失的指令的安全推测。 TPBuf基于以下观察：并非所有推测性缓存未命中都可用于构建推测性侧通道。基于第3节中定义的威胁模型，我们关注使用共享内存（例如，Flush + Reload）范例和非法访问内存页面信息的Spectre变体。如图3所示，恶意小工具的推测性执行在我们的目标Spectre攻击中被用作通用内存访问模式。特别是，观察到恶意推测执行流程总是包含两个特殊的存储器指令（A和B）。这两条指令具有以下用法和行为。

1）A用于推测性地访问敏感数据。 B推测访问攻击者共享的内存区域，用于构建受害者和攻击者之间的缓存侧通道。由于用于侧信道的秘密数据和存储区域通常位于不同的存储页面，因此这两条指令访问不同的页面。

2）为了构建缓存侧通道，攻击者需要首先刷新特定的共享内存数据。然后，B的诱导推测执行具有高速缓存未命中，因此将高速缓存行重新加载到L1 DCache中。攻击者可以通过缓存侧信道感知状态信息的这种变化。因此，B的高速缓存未命中对于通过高速缓存侧信道泄漏敏感信息是必要的。

3）B是数据依赖于A.A的结果用于计算共享存储区域的索引。这种精心设计的依赖性也是攻击者推断秘密价值的另一个重要点。

在上述观察的推动下，我们将上述共同特征行为称为S模式。具体地，如果观察到推测执行的指令序列具有以下特征，则我们认为该推测指令序列具有S模式行为。

1）至少有两个指令（A和B）分别访问不同的存储页面。

2）指令B导致L1 DCache未命中。

3）指令B具有数据依赖于指令A.

4）A和B之间可能有多个指令（计算，存储器或其他类型的指令）。

  尽管Spectre攻击的恶意小工具被称为S-Pattern行为，但应该注意的是，具有S-Pattern的指令流不一定是幽灵攻击。出于安全原因，我们试图在微体系结构层面上防止形成具有S-Pattern的推测性指令流。在确保安全性的同时，这种机制自然也会导致性能损失。在第6节中，我们详细评估了该策略的性能，并分析了正常程序（如SPEC CPU 2006）中S-Pattern的比例。

  TPBuf旨在通过所有推测执行的S-Pattern捕获内存访问行为。 它记录所有动态推测存储器访问请求并跟踪它们的执行状态（例如，是否重新填充所请求的高速缓存行）。 当一个错过L1 DCache的新内存请求时，TPBuf会将其页面地址与其历史记录进行比较。 并且它根据表II中描述的逻辑决定这种新的推测指令是否安全。

  TPBuf的微体系结构如图4所示。一个主要的设计原则是尽可能利用现有逻辑来降低实现的复杂性，例如避免TPBuf成为核心管道内的新时序关键路径。 TPBuf靠近加载存储队列（LSQ），其条目与LSQ的条目具有1：1映射。 TPBuf条目的分配，提交和压缩与LSQ的Head和Tail指针的移动一起操作。此外，TPBuf涵盖了推测执行窗口中的所有动态推测存储器指令。为了防止攻击者直接推测性地访问未授权数据然后将数据传播到他自己的存储空间，必须首先检查访问地址并使用TLB获取物理页码（PPN）。 TPBuf记录并使用PPN作为每个条目的标记。此外，每个TPBuf条目都存储一个掩码和许多状态位。 TPBuf检测S模式并将结果传递给Cache-hit过滤器，该过滤器决定是否应该阻止可疑的推测性未命中请求。这样，原始内存一致性模型和缓存一致性不受影响。 TPBuf的查找如图4所示。

分配：当在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 进行评测，平均性能开销为 6.8\%.

\subsubsection{SpectreGuard}

SpectreGuard\supercite{spectreguard} 是一种软硬件结合防御 Spectre 攻击
的方法。软件在页表中标记一个页是否存在秘密数据，如果一条指令在推测式执
行中读取了带标记的页中的数据，处理器则禁止这条指令将读取的值转发至其他
指令，直到这条指令之前的所有预测都已验证，确认推测式执行正确。

在 gem5 模拟器中用 SPEC CPU2006 评测，如果标记内存的所有页，则
SpectreGuard 的平均性能开销为 20\%, 而如果标记堆区域，则性能开销减少至
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
