From cc9cb9a141de42cee0e2637a5f53fdd3e4f24bb8 Mon Sep 17 00:00:00 2001 From: Iru Cai Date: Sun, 12 May 2019 00:34:29 +0800 Subject: upd --- chap/chap4.tex | 95 +++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 67 insertions(+), 28 deletions(-) diff --git a/chap/chap4.tex b/chap/chap4.tex index 6c058f1..e2de2f7 100644 --- a/chap/chap4.tex +++ b/chap/chap4.tex @@ -22,8 +22,6 @@ Spectre-RSB 攻击,此方法可以扩展至 Spectre-STL 攻击。攻击者在 \section{基于动态信息流追踪的Spectre检测方法} -\Todo: 这一节是否可以写到3页? - 动态信息流追踪(Dynamic Information Flow Tracking)\supercite{dift}是 一种硬件安全策略,通过识别可疑的信息流,并限制可疑信息的使用,保护程序 的安全。它最早用于防止攻击者利用缓冲区溢出攻击执行恶意代码,也可以用于 @@ -37,10 +35,19 @@ CSF\supercite{context-sensitive-fencing} 中的译码级信息流追踪框架 DI 断是否需要插入 fence 微码。OISA\supercite{oisa} 在指令系统的定义中即包 含了 DIFT 技术,用于追踪一个数据是否为秘密数据。 -以图\ref{lst:spectre_v1}的 Spectre v1 组件代码为例,这段代码产生 -图\ref{lst:spectre_v1_asm}所示的指令。 +在本文的工作中,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]| 的值, +从而处理器可以阻止对这个地址的访问。 -\begin{figure}[htbp] +为了达到这个目的,我们为所有的物理寄存器都添加一个标记,用于表示它的值 +是否来源于推测式执行中,从内存中读出的值。在上述例子中,有一条将内 +存 \verb|array1[x]| 读取至寄存器的指令,该指令的目的寄存器的标记将会被 +设为1. + +\begin{figure} \begin{minted}[frame=single,linenos=true]{nasm} xor eax, eax cmp qword [rip + 0x2b157f], rdi @@ -57,7 +64,10 @@ CSF\supercite{context-sensitive-fencing} 中的译码级信息流追踪框架 DI \label{lst:spectre_v1_asm} \end{figure} -这些指令中,在分支后执行的指令,DIFT 的行为如表\ref{tab:spectre_dift}所示。 +上述 Spectre v1 的组件代码可以产生图\ref{lst:spectre_v1_asm}所示的指令。 +我们用表\ref{tab:spectre_dift}展示 DIFT 在推测式执行分支中的指令的行为, +其中 T 表示寄存器的标记,在分支推测式执行前,所有寄存器的标记为0,为了 +描述方便,这里用体系结构寄存器进行描述,实现中为物理寄存器的标记。 \begin{table} \begin{tabular}{|c|c|c|} @@ -86,31 +96,52 @@ lea rdx, {[}rip + 0x2b425d{]} & rdx <- rip + 0x2b425d & T{[}rdx{]} <- T{[}rip{]} \label{tab:spectre_dift} \end{table} -本文使用 DIFT 检测 Spectre 组件中泄露数据的 load 指令。详细设计如下: - \Todo: 解释为什么使用这种方法,和其他相似方法(DLIFT, TPBuf, SG(Full))的比较 \Todo: 增加结构示意图和代码描述 -\Todo: 使用更加详细的描述 +以下描述这个检测方法的具体细节。 + +标记的设置:在推测式执行时,对于所有从内存读取数据的指令,将其所有目的 +寄存器的标记设为1. + +标记的传播:标记的传播在处理器的执行阶段进行,在这个阶段,处理器在读源 +寄存器的同时,将它们对应的标记读出。对于不同类型的指令,标记传播的方式 +如下: \begin{itemize} -\item 为每个物理寄存器添加一位标记,表示这个寄存器的数据是否来自于推测 - 式执行中从内存读取的数据 -\item 如果在推测式执行中,一条指令从内存中读取了数据,则设置这条指令的 - 目的寄存器的标志为1 -\item 对于非访存指令,如果存在标记为1的源寄存器,则设置这条指令的目的 - 寄存器标志为1,否则设置标志为0 -\item 当一条指令之前所有分支指令执行完成,确认推测式执行正确后,设置这 - 条指令的目的寄存器标志为0 -\item 在推测式执行的过程中执行 load 指令时,如果存在标记为1的源寄存器, - 则这条指令为不安全的 load +\item 对于算术类指令,它的源操作数均来源于寄存器,其目的寄存器的标记设 + 为所有源寄存器标记做或运算的结果。 +\item 对于装载类指令,它从内存中读取数据,这是标记设置的基本条件,因此 + 目的寄存器的标志设为1. +\item 对于存储类指令,它没有目的寄存器。和一般的 DIFT 实现不同,我们不 + 对任何内存进行标记。因为要使用存入内存中的数据,需要有一套指令将其重 + 新从内存中读出,这个操作会设置这条指令目的寄存器的标记。 +\item 对于转移类指令,我们为每个指令添加一位标记,如果源寄存器中有标记 + 为1的指令,则设置这个指令的标记为1,否则设置为0.转移指令的的标记将在 + 下文描述。 \end{itemize} -以上 DIFT 实现只考虑了泄露的 load 指令和读取秘密数据的 load 指令存在数 -据相关,此外还要考虑控制相关的情形,如以下例子\supercite{msvc}: +标记的清除:当一条指令不再处于推测式执行的状态,即该指令此前的所有分支 +都执行完成并通过验证,则要将这条指令所有目的寄存器的标记重置为0.对于转 +移类指令,则清除该转移指令的标记。 -\begin{minted}{C} +寄存器中的标记可以处理读取内存中数据的指令,和泄露内存中数据的指令,存 +在直接或间接数据相关的情形。读取内存的指令使得存放它的寄存器被标记,此 +后和它存在直接或间接数据相关的指令,会将这个标记传播至这些指令的目的寄 +存器。 + +考虑攻击者在 Spectre 攻击中利用缓存侧信道泄露内存中的数据,则 +在 Spectre 的组件代码中,泄露数据的指令为装载指令,该装载指令的地址直接 +或间接依赖于内存中的数据。在加入上述的 DIFT 检测机制后,由于该装载指令 +依赖于内存中的数据,它必定有一个被标记的源寄存器,从而处理器可以得知该 +指令不安全。 + +转移指令的标记用于处理可能泄露数据的指令,和内存中数据的值存在控制相关 +的情形,如图\ref{lst:victim_v10}的例子\supercite{msvc}: + +\begin{figure}[htbp] +\begin{minted}{C}[frame=single,linenos=true] void victim(size_t x, uint8_t k) { if (x < array1_size) { if (array1[x] == k) @@ -118,14 +149,22 @@ void victim(size_t x, uint8_t k) { } } \end{minted} +\caption{泄露数据的指令和内存中的数据存在控制相关的情形} +\label{lst:victim_v10} +\end{figure} 这个例子读取的 \verb|array1[x]| 和攻击者猜测的值 \verb|k| 进行比较,如 -果两个值相等,则会访问 \verb|array2[0]|,即访问 \verb|array2[0]| 的指 -令和访问 \verb|array1[x]| 的指令存在控制相关,对 \verb|array2[0]| 的访 -问可能泄露 \verb|array1[x]| 的数据。因此,如果一条控制指令依赖于被标记 -的寄存器,则对它进行标记,其后的所有 load 指令都认为不安全。 - -\Todo: 解释怎样处理以上的情形 +果两个值相等,则会访问 \verb|array2[0]|,即访问 \verb|array2[0]| 的指令 +和访问 \verb|array1[x]| 的指令存在控制相关,攻击者可以通过探 +测\verb|array2[0]| 是否在缓存中,判断 \verb|array1[x]| 的值是否 +和\verb|k| 相等。只使用寄存器的标记,并不能检测出读取 \verb|array2[0]| +的指令和 \verb|array1[x]| 的值存在依赖关系。 + +因此我们需要转移指令中的标记。如果一条指令在被标记的转移指令之后执行, +则该指令和一个被标记的数据存在依赖关系,如果指令为装载指令,由于它改变 +了缓存的状态,攻击者可以通过缓存信道得知该指令被执行过,推测出被标记转 +移指令的执行结果,从而推测出内存中秘密数据的值,因此这样的装载指令也是 +不安全的指令。 \section{使用推测式执行缓冲区} -- cgit v1.2.3