您的位置  > 互联网

俄亥俄州立大学:CPU乱序执行和预测执行导致的安全问题

分享几个当前可用的CPU漏洞(,

)使用POC验证代码:

其次,对这两个漏洞的详细成因、原理、利用及危害分析进行了深入的阐述。 文章原文:

CPU乱序执行和预测执行带来的安全问题

乱序 [1] 和预测执行 ( ) [2] 是现代 CPU 常用的提高性能的优化方法。 乱序是指CPU不按照程序严格指定的顺序执行。 预测是指CPU根据之前的经验,预先执行稍后可能执行的代码。 传统的观念认为,由于CPU在运行过程中丢弃了乱序执行和预测执行导致的不正确的计算结果,因此乱序执行和预测执行不会对程序的正确性和安全性产生任何影响。 然而,最新研究结果表明,攻击者可以利用这两种CPU功能进行旁道攻击。 目前已知的攻击和攻击是两种典型的攻击例子[3]。

本质上,这两种攻击都属于基于CPU缓存的旁路攻击。 这种旁路攻击近十年来在国外计算机安全研究领域非常流行。 他们的基本假设是攻击者在目标主机上拥有一定的执行权限(比如操作系统的普通进程、云计算中的虚拟主机、浏览器中的一段Java代码),然后控制自己的内存通过数据空间(如读取等)来间接控制CPU的缓存。 由于CPU缓存是在攻击者和目标主机上的目标程序之间共享的,因此攻击者可以利用这种对缓存的间接控制来推测目标程序的行为。 例如,如果攻击者和目标程序共享物理内存(例如,同一操作系统上的两个程序常常共享同一个动态链接库),攻击者可以重复使用CPU指令来更改此内存的某个地址。 清除CPU缓存(Flush阶段),然后在一定时间间隔后读取该地址的内存数据并测量读取时间(阶段)。 这样,攻击者就可以清楚地知道该地址是否已经被目标程序读取过,因为一旦目标程序读取了该地址,其对应的内存就会被导入到CPU缓存中,从而让攻击者能够自己访问这个地址。 更快(因为从缓存读取比从内存读取快得多)。 这种攻击方式称为Flush+[6]攻击。 此外,针对CPU缓存侧通道还有Evict+Time[7]、Prime+Probe[8]等攻击方式。

然而,以往的侧通道攻击都是针对攻击者的内存读取模式,例如是否执行某条指令或是否访问某条数据,但无法直接读取攻击者的内存。 攻击[4]和[5]的目标是未经授权的内存读取,例如读取(转储)整个内核的内存数据。 这使得此类旁路攻击的后果更加严重。 这就是为什么这个CPU漏洞被媒体如此大肆宣传的原因。 下面我们将介绍这两种攻击的基本形式和本质。

攻击

该攻击利用现代CPU的乱序特性,彻底打破了原本由硬件保证的内存隔离,使得只有普通进程权限的攻击者可以通过简单的方式读取内核内存。 需要强调的是,该攻击不是针对 KASLR 的攻击[9]。 攻击KALSR比较简单,因为它的目标只是获取内核内存的虚拟地址,而攻击目标则是获取内核内存的内容。

该攻击的本质是利用CPU的安全检查和乱序执行之间的竞争,为攻击者创造一个较短的攻击窗口。 乱序执行是指当CPU中的某些指令需要等待某些资源时,例如内存读取,CPU不会停在当前指令处,而是会利用空闲的计算能力继续执行后续指令。 这大大提高了计算能力的利用率,从而提高了CPU性能。 在支持乱序执行的CPU上,指令不是按顺序执行的。 例如,后续指令可以在前一指令的执行结束之前开始执行。 但为了保证程序的正确性,指令()必须顺序执行,只有在指令退休时才进行CPU的安全检查。 其结果是,在CPU对一条指令进行安全检查之前,该指令后面的一些指令会因为CPU的乱序执行而提前执行。 例如,访问内核内存的用户空间指令将导致CPU抛出异常。 然而,只有当指令退出时,异常才会被CPU处理,并且由于乱序执行而提前执行的指令将被CPU丢弃。 由于CPU保证了程序的正确性,乱序执行不会造成安全风险。 然而,由于乱序执行指令的缓存操作在这些指令被丢弃时不会被重置,因此攻击者可以通过缓存侧通道获取乱序执行的信息,从而导致攻击。 本质上,攻击的原理是相同的。 我们稍后会介绍。

以下是简化攻击的基本说明:

1 ; rcx = ; rbx = 探针 mov al,字节​​ [rcx]4 shl rax,0xc5 mov rbx,qword [rbx + rax]

首先,在指令3中,具有用户级权限的攻击者访问目标内核内存地址(存储在寄存器rcx中)。 由于访问的是内核地址,因此该指令将触发异常,从而该指令以及后续指令对寄存器的所有修改都将被丢弃。 但在等待CPU执行完指令的过程中,由于乱序执行,最后两条指令实际上已经执行完毕,此时的计算是基于指令3中读取的数据,不受CPU的权限。 限制。 指令4会将这个数据乘以4096,并将其用作指令5中的数组探针数组。由于内存页的大小为4KB,所以不同的数据将导致不同的内存页被访问并存储在CPU缓存中。 此后,另一个攻击者进程可以使用缓存侧通道攻击来了解哪个内存页面已被访问,从而推断出所访问的内核内存数据。

具体的缓存攻击方法包括Flush+[6]、Evict+Time[7]或Prime+Probe[8]。 在这种场景下(探针数组在攻击者自己的内存空间中),一种比较简单有效的攻击方法是Flush+,其基本思想前面已经介绍过了。 简单来说,Flush+攻击首先用指令将探针数组对应的内存从CPU缓存中清除出来,然后执行上述攻击代码后,逐一访问探针数组的每个内存页,并记录访问情况时间。 较短的访问时间表明CPU在执行上述代码的过程中已经将相应的内存页加载到了缓存中。 原因是这个内存页对应的是内核空间中rcx指向的内存内容。

一般来说,攻击指令由两部分组成:第一部分使用乱序执行来访问受限内存,第二部分根据读取的值重新编码对内存的访问,并通过缓存侧通道提取信息。 攻击的关键在于,乱序执行的两条指令必须在读取内核内存的指令退役之前,即权限审核之前执行。 此外,由于访问受限内存会导致操作系统抛出异常,攻击者可以抑制异常[11]或通过其他方式处理异常[4],从而重复、不间断地遍历对受限内存的访问。

攻击

该攻击利用CPU的预测执行来攻击系统。 推测执行是另一个 CPU 优化功能。 当执行分支指令时,由于分支指令的执行可能需要内存读取(数百个CPU周期),因此在分支指令执行结束之前,CPU会预测将执行哪个分支,提取相应的指令代码并执行它可以提高CPU指令管道的性能。 CPU 的预测执行是通过分支预测单元(BPU)来执行的。 简单理解,BPU存储的是某条分支指令最近执行的分支跳转的结果。 当CPU的预测执行遇到分支指令时,会根据BPU的预测结果进行跳转。 当预测执行检测到预测错误时,预测执行的结果将被丢弃,CPU状态将被重置。 然而,与乱序执行类似,推测执行对 CPU 缓存的影响被保留。 这一点与攻击类似。

攻击主要分为三个阶段:

准备阶段:在这个阶段,攻击者通过一些操作训练CPU的BPU,使其在运行目标代码时执行特定的预测执行。 同时,攻击者可以进行一些操作来增加预测执行的概率,比如将条件判断所需的数据从缓存中挤出,这样就会拉长分支指令的执行时间。 另外,攻击者还可以在这个阶段为侧通道做准备,比如Flush+攻击的Flush部分。

攻击阶段:攻击者利用CPU的推测执行将目标的机密数据传输到微架构侧通道中。 下面详细介绍具体的攻击方法。

机密数据提取阶段:通过测量Flush+或其他缓存攻击方法的内存时间,攻击者可以从缓存侧通道提取目标机密数据。 这与攻击非常相似。

在攻击阶段,攻击者利用CPU的推测执行将目标的机密数据传输到微架构侧通道中。 常见的分支指令包括条件分支指令和间接分支指令。 所以相对攻击有两种不同的方法。 主要思想是攻击者控制目标程序的一个变量或寄存器,使其能够读取攻击者指定的内存地址。 这里攻击者指定的内存地址的内容就是攻击者试图获取的机密数据(例如用户密码)。 如果目标程序包含以内存方式访问此机密数据的指针或数组,则攻击者可以使用缓存侧通道提取所访问的内存地址,然后提取目标机密数据。

攻击的危险

本质上,两者都是基于侧通道的攻击,主要用于信息泄露,并且不能任意修改目标内存地址。 当攻击者的代码由于权限限制而无法任意读取其所在的内存地址空间时,常常会使用攻击。 例如,在操作系统中,内核内存将被映射到所有普通进程的地址空间。 虽然普通进程可以通过虚拟地址访问所有受限内存,包括内核的地址空间,但直接访问内核地址会抛出异常并终止。 而攻击可以帮助攻击者完成这样的操作。 云计算的虚拟机架构也存在类似问题,允许虚拟机通过攻击任意读取云服务器主机虚拟机管理器(VMM)的内存地址。 该攻击利用目标程序的特殊结构,通过系统调用或函数调用来控制其中的某个变量,从而泄漏目标程序(或内核)地址空间中的内存内容。 例如,文献[5]提出了一种Java代码访问整个浏览器进程内存的方法。 文献[10]提出利用内核即时编译(Just-in-time)特性来进行权限提升攻击。 正是因为即时编译产生的代码具有攻击所需的特殊结构。

该攻击攻击的不是软件漏洞,而是CPU设计本身的安全缺陷。 因此,该攻击适用范围广泛,后果严重。 已被证明在2010年以后发布的所有Intel桌面和服务器CPU架构上都是可行的。实验证明,个人电脑和云服务器都会受到影响,成功入侵的操作系统包括Linux、MS和LXC。 在ARM和AMD处理器上,虽然攻击所依赖的硬件漏洞也被证实存在,但目前还没有完整的攻击。 可能的原因包括指令执行太慢、CPU ()太短等。相反,攻击需要目标程序具有特殊的结构,因此受到目标软件的限制。 如果目标程序没有这种特殊的结构,攻击就很难进行。 不过,虽然该攻击目前仅限于 Intel 处理器,但该攻击适用于 Intel、AMD 和 ARM 等许多处理器。

防御漏洞

虽然 和 都是CPU漏洞,但短时间内很难通过CPU升级来修补漏洞。 目前主要的防御方法是通过软件完全隔离用户态和内核态,尽管有分析称这样的程序性能可能会大幅下降。 防守更是困难。 使用编译器进行程序分析并添加顺序执行指令(例如cpuid)是一种可能的解决方案。 我们还将继续跟踪重要厂商修补的漏洞并测试这些修补方法。 我们实验室还将研究和开发其他安全技术来防止这些攻击。

对于普通用户来说,只要不执行恶意代码,比如不访问恶意网站,就不会有不受信任的代码进入内存执行,就不会受到攻击。 因此,个人用户仍然可以利用现有的防御方法(例如拦截恶意网站)来保护自己。 同时,还应关注操作系统厂商、浏览器厂商等系统软件厂商的补丁,并随时更新。

对于在云中,由于攻击者可以租用虚拟环境来执行攻击者想要执行的任何代码,因此攻击者可以利用它们从虚拟机用户态读取主机的内核状态和虚拟状态关键数据,从而攻击其他计算机。 虚拟机。 因此,云厂商有责任尽快修补软件中的这些CPU漏洞。 企业用户应采取积极主动的态度配合或推动漏洞管控。

关于作者

张银前:俄亥俄州立大学助理教授。 主要研究方向为侧通道安全、云计算安全。 林志强:俄亥俄州立大学副教授。 主要研究方向为虚拟化安全、软件安全。

参考

[1]

[2]

[3]

[4]

[5]

[6]

[7]

[8]

[9]

[10]

[11]