Inferring Fine-grained Control Flow Inside SGX Enclaves with Branch Shadowing 重点整理

文章主旨

在SGX环境中,LBR可以记录时间信息,且精准度比RDTSC更精准,所以利用LBR(last branch record测量时间和以及获得预测是否成功信息,分析执行流。最根本原因是enclave切换过程中并没有更新清除预测历史。

背景

Intel SGX

英特尔CPU支持基于硬件的TEE通过安全扩展模块Intel SGX。 SGX提供了一组指令,允许应用程序实例化一个enclave(飞地),用于保护内部的代码和数据免受特权软件(如操作系统或管理程序),硬件固件,甚至硬件单元(CPU除外)的影响。 为了提供这种保护,SGX强制执行严格的内存访问机制:只允许飞地代码访问相同飞地的内存。 此外,SGX利用片上存储器加密引擎,在将嵌入式内容写入物理内存之前对其进行加密,并仅在加密内容执行或飞地模式期间进入CPU封装时解密加密内容。
飞地内容交换
为了支持飞地与非飞地模式之间的上下文切换,SGX提供了诸如启动飞地执行的EENTER和终止飞地执行的EEXIT等指令。 另外,ERESUME在发生异步飞地退出(AEX)后恢复飞地执行。 AEX的原因包括例外和中断。 在上下文切换期间,SGX执行一系列检查和操作以确保安全性,例如,刷新翻译旁视缓冲区(TLB)。 但是,我们观察到SGX并未清除所有缓存的系统状态,例如分支历史记录

分支预测Branch Prediction

分支预测是现代流水线处理器最重要的特性之一。 在高层次上,一条指令流水线由四个主要阶段组成:读取,解码,执行和回写。 在任何特定的时间,都有很多指令正在进行中。 处理器利用指令级并行和无序执行来最大化吞吐量,同时仍然维持指令的退休顺序。分支指令会严重降低指令吞吐量,因为处理器无法执行分支直到分支的目标和结果被确定。 如果减少,分支机构将导致管道失速,也称为气泡。 因此,现代处理器使用分支预测单元(BPU)来预测分支结果和分支目标。 虽然BPU增加了通用性,但值得注意的是,在预测失误的情况下,惩罚相当高,因为处理器需要清除流水线并回滚任何推测性执行结果。 这就是为什么英特尔提供专用硬件功能(LBR)来分析分支执行的原因
Branch and branch target prediction.
分支预测是预测条件分支的下一条指令的过程,通过猜测它是否会被采用。 分支目标预测是在执行分支之前预测和获取分支的目标指令的过程。 对于分支目标预测,现代处理器具有BTB来存储所采用的分支指令的计算出的目标地址,并且当相应的分支指令被预测为采取时获取它们。
BTB structure and partial tag hit.
BTB是一种类似缓存的关联结构。地址位用于计算集合索引和标签字段。用于设置索引的位数由BTB的大小决定。与使用标签的所有剩余地址位的高速缓存不同,BTB使用标签剩余位的子集(即部分标签)。例如,在64位地址空间中,如果将ADDR [11:0]用于索引,而不是对标记使用ADDR [63:12],则只有部分数量的位(如ADDR [31:12]被用作标签。这种选择的原因如下:首先,与数据缓存相比,BTB的大小非常小,并且完整标签的开销可能非常高。其次,一个程序中的高阶比特通常倾向于相同。第三,与需要保持精确的微体系结构状态的缓存不同,BTB只是一个预测器。即使部分标记命中导致错误的BTB命中,也会在执行阶段计算正确的目标,并且如果预测错误(即,它仅影响性能,而不影响正确性),则管道将回滚。
Static and dynamic branch prediction.
静态分支预测是一个默认的规则,用于在没有历史的情况下预测分支指令之后的下一个指令[25]。 首先,处理器预测将不会采用前向条件分支(其目标地址高于其自身的条件分支),这意味着下一条指令将被直接提取(即,下降路径)。 其次,处理器预测将会采用后向条件分支 - 目标地址低于其自身的条件分支; 也就是说,将获取指定的目标。 第三,处理器预测不会采取间接分支,类似于前向条件分支情况。 第四,处理器预测将采取无条件分支,类似于后向条件分支情况。 相反,当分支在BTB中有历史记录时,处理器将根据历史记录预测下一条指令。 这个过程被称为动态分支预测。

Last Branch Record

没有任何性能下降,记录最近32条分支信息,包括源地址 目标地址 时间cycle消耗 预测成功或失败,但是此LBR需开启调试模式才会记录。

分支影子攻击

主要包括三种类型攻击:条件分支 非条件分支 间接跳转,主要依据静态分支预测规则可能带来的漏洞攻击。

攻击模型

威胁模型基于英特尔SGX的原始威胁模型和受控通道攻击[60]:攻击者损害了操作系统并利用它来攻击目标飞地程序。
1)攻击者通过静态或动态分析其源代码或二进制文件知道目标飞地程序(即分支指令及其目标序列)的可能控制流。 这与在飞地内运行未经修改的遗留代码的重要用例一致[5,6,51,57]。 不可观察的代码(例如,自修改代码和来自远程服务器的代码)超出了我们的攻击范围。 此外,攻击者可以将目标飞地程序映射到特定的内存地址,以指定每个分支指令的位置及其目标地址。 自我分页[22]和ASLR[15]的实时再随机化不在我们的攻击范围之内。
2)攻击者推断目标飞地的哪部分代码是通过可观察的事件运行的,例如调用飞地外的页面函数和页面错误。 攻击者使用此信息将目标代码的执行与分支影子代码同步。
3)攻击者尽可能频繁地中断目标飞地的执行,以运行分支影子代码。 这可以通过操纵本地APIC定时器和/或禁用CPU缓存来完成
4)攻击者通过监视硬件性能计数器(例如LBR)或测量分支错误预测罚分来识别影子代码的分支预测和错误预测
最后,攻击者可以阻止目标区域接收可靠的高分辨率时间源,以避免因减速而检测到攻击。 为每个中断或页面错误探测目标飞地会减慢飞行区域,使攻击者需要隐藏它。 SGX版本1已经满足这样的要求,因为它不允许RDTSC。 对于SGX版本2(尚未发布),攻击者可能需要操纵模型特定的寄存器(MSR)来挂接RDTSC。 尽管目标飞地可以依靠外部时间源,但由于网络延迟和开销,它也不可靠。 此外,攻击者可以故意丢弃或延迟这些数据包。

条件分支影子

rdtsc
先前的分支定时攻击尝试使用RDTSC或RDTSCP指令来衡量这种回滚损失。 然而,我们的实验显示(表1)分支预测误差的时间相当嘈杂。 因此,在正确的预测和错误预测之间设置一个明确的界限是困难的。 这是因为考虑到最新英特尔CPU的高度复杂的内部结构(例如无序执行),由于分支预测错误而导致错误执行的指令数量难以预测。 因此,我们认为基于RDTSC的推断在实践中很难使用,因此我们的目标是使用LBR来实现精确的攻击,因为它让我们知道分支误预测信息,并且其经过的循环特征几乎没有噪声(表1)。
mean 平均数 o 偏离 偏离越小越好
表一
这里写图片描述
从执行轨迹推断(intel PT)
我们可以使用Intel PT来测量目标分支的误预测惩罚,因为它可以在每个PT分组之间提供精确的经过周期(称为CYC分组)。 但是,CYC数据包不能立即用于我们的目的,因为英特尔PT将一系列有条件和无条件的分支汇总为单个数据包作为优化。 为了避免这个问题,我们有意在目标分支后面插入一个间接分支,使得所有分支在单独的CYC数据包中正确记录它们的使用时间。 英特尔PT关于分支预测失误的时间信息与基于RDTSCP的测量(表1)相比差异小得多。
精确泄露(LBR)
图2显示了使用BTB,BPU和LBR进行条件分支遮蔽的过程。 我们首先解释已经采取了条件分支的情况(案例1)。

条件分支预测

1 )获取受害码的条件分支并将相应的信息存储到BTB和BPU中。 这个分支发生在飞地内,除非我们在调试模式下运行飞地进程,否则LBR不会重新传输这些信息。
2)enclave执行被中断,操作系统取得控制权。恶意操作系统如何频繁地中断在第3.6节中讲解。
3)操作系统启用LBR,然后执行影子代码。
4)BPU正确预测将采取阴影条件分支(预测会不会take相关的分支地址)。此时,分支目标预测将失败,因为BTB在飞地内存储目标地址(目标地址不是攻击者跳转正确的地址)。然而,这个目标错误预测与分支预测的结果是正交的,尽管它会在CPU周期中引入惩罚。即根据经验BPU推测这个分支会执行,但由于BTB中记录的跳转地址碰撞的原因,实际上目标地址非正确地址,导致有时间损失。
5)最后,通过禁用和检索LBR,我们知道阴影条件分支已被正确预测 - 它已被预测。我们认为这个正确的预测是关于分支预测的,因为这两个分支指令的目标地址是不同的;也就是说,目标预测可能会失败。请注意,默认情况下,LBR报告发生在用户和内核空间中的所有分支(包括函数调用)。由于我们的影子代码没有函数调用并且在内核中执行,所以我们使用LBR的过滤机制忽略用户空间中的每个函数调用和所有分支。(LBR会记录预测是否正确,此时确实是正确的预测执行跳转了,所以直接查表LBR就可以了)这里写图片描述
攻击时有两种情况:1) 受害者刚执行过,更新了BTB,此时攻击者执行,由于BTB有记录,会正确跳转到正确的地址,因此查看LBR可查看预测准确与否推测受害者执行状态。2)受害者还未执行分支,此时BTB时空的,攻击者此时执行跳转由于没有历史,处理器由于默认静态跳转原则会推测不执行,会继续执行下一条语句,因此LBR记录错误预测。

初始化分支

当预测一个条件分支时,现代BPUs利用分支的前几次执行来提高预测的准确性。 例如,如果一个分支已被多次采用,然后又不被采用一次,则BPU会预测其将执行下一次执行。 这会使得阴影分支被多次执行后(例如,在循环内)错误地推断目标分支的执行。 为了解决这个问题,在每次攻击迭代的最后一步之后,我们在改变条件的同时多次运行阴影代码(即交织采取和不采取分支)来初始化分支状态。

以下都是会take 即 预测跳转,所以不会存在不被采用的情况。

无条件分支预测

与条件分支不同,无条件分支总是被采用; 即不需要分支预测。 因此,为了认识其行为,我们需要转移其目标地址来观察分支目标错误预测,而不是分支错误预测。 有趣的是,我们发现LBR并未报告无条件分支的分支目标错误预测; 它总是说每个无条件分支都被正确预测。 因此,我们使用LBR报告的分支的经过周期来识别分支目标误预测罚分,这比RDTSC更精准。
这里写图片描述
这与前文原理类似,特别需要指出的是 此时无论预测成功与否LBR都会显示预测成功。
所以可通过执行的时间长短推测enclave中的运行状态。 如此图可发现 LBR中有记录后,运行时间更短,

间接跳转

此和无条件跳转类似,都是无论预测是否成功,都会执行。然而,不像无条件跳转,间接跳转没有固定的跳转地址,如果没有历史记录,那么处理器将推测在此指令之后的指令会被执行,这等同于没有执行间接跳转,LBR会记录预测成功和失败。
这里写图片描述

由于间接跳转位置不对,所以攻击者执行时预测失败。
这里写图片描述

通过LBR可获得以上信息。

频繁中断和跟踪

分支影子攻击需要考虑改变(或甚至移除)BTB条目的情况,因为它们使得攻击错过某些分支历史。首先,BTB的大小是有限的,使得BTB条目可以被另一个分支指令覆盖。我们经验地确定Skylake的BTB有4,096个条目,其中方式的数量是四个,集合的数量是1,024个(第5.1节)。由于其设计良好的索引散列算法,我们观察到位于不同地址的两条分支指令之间的冲突很少发生。但是,无论如何,在超过4096个不同的分支指令之后,BTB将会溢出,我们将丢失一些分支历史。其次,由于循环或重新执行相同功能,可以删除或更改条件或间接分支的BTB条目。例如,条件分支在其第一次运行时已经被采用,并且由于给定条件的改变而没有在第二次运行时被取走,从而删除相应的BTB条目。间接分支的目标也可以根据条件进行更改,这会改变相应的BTB条目。如果分支遮蔽攻击在更改之前无法检查BTB条目,则会丢失信息。
为了解决这个问题,我们尽可能频繁地中断enclave进程,并通过操纵本地APIC定时器和CPU高速缓存来检查分支历史记录。 这两种方法减缓了目标enclave程序的执行速度,因此攻击者需要谨慎使用它们(即选择性地)以避免检测。
APIC
我们在最近的Linux版本中操纵本地APIC定时器的频率(细节在附录A中)。我们根据两个定时器中断之间执行的ADD指令的数量来度量我们操纵的定时器中断的频率。 定时器中断之间执行了大约48.76条ADD指令(标准偏差:2.75)1。 ADD在Skylake CPU [25]中只需要一个周期,这样我们的频繁定时器就能每隔约50个周期中断受害者飞地。
禁用缓存。
如果我们不得不在短循环内攻击一个分支指令<50个周期,那么频繁的定时器中断是不够的。 为了更频繁地中断飞地进程,我们通过设置CR0控制寄存器的高速缓存禁止(CD)位,选择性地禁用运行受害者飞地进程的CPU内核的L1和L2高速缓存。 随着频繁的定时器中断和禁用的高速缓存,平均在两个定时器中断之间执行约4.71条ADD指令(标准偏差:1.96,迭代次数为10,000次)。 因此,我们可以达到的最高攻击频率大约是五个周期。

虚拟地址防护

为了执行分支影子攻击,攻击者必须操纵受害者飞地进程的虚拟地址。 由于攻击者已经损害了操作系统,操纵页面表来改变虚拟地址是一件容易的事。 为简单起见,我们假设攻击者禁用用户空间ASLR并修改用于Linux的Intel SGX驱动程序(vm_mmap)以更改飞地的基址(附录B)。 另外,攻击者在影子代码之前放置任意数量的NOP指令以满足对齐。

攻击同步

尽管分支阴影在每次迭代中探测多个分支,但当受害者飞地程序很大时,它是不够的。 克服这个限制的方法是在功能级应用分支影子攻击。 即,攻击者首先推断受害者飞地程序已执行或正在执行的功能,然后探测属于这些功能的分支。 如果这些函数包含可从外部调用(通过EENTER)或依赖于外部调用的入口点,则攻击者可以轻松识别它们,因为它们可由OS进行控制和观察。
但是,攻击者需要另一种策略来推断非导出函数的执行。 攻击者可以创建由目标函数总是可达的分支(例如,位于函数序言部分的分支)组成的特殊影子代码。 通过周期性地执行这个代码,攻击者可以看到哪些被监视的功能已经被执行。 此外,攻击者可以使用页面错误侧通道[60]来同步页面方面的攻击。

虚拟机隔离

为了实现攻击  减少误差  最好在同一个core上 只有后victim 与 攻击者两个进程。为了避免这个问题,我们使用isolcpus引导参数来指定一个隔离的内核,如果没有特定的请求,它将不会被调度。 然后,我们使用taskset命令来运行受隔离内核的受害者飞地。

仿真

RSA攻击
10次恢复全部密钥 一次恢复66%

防护

1 冲刷分支状态 enclave与非enclave 区分开
flush的频率会影响性能 做了很多对比图 针对不同应用
2.模糊分支
尽量每个分支都执行
本文提出zigzagger工具
这里写图片描述
转换所有的有条件的跳转转为无条件跳转到蹦床上,无条件跳转会更加难分析,而这些蹦床最后会跳转到r15 保存的目标地址。利用cmov将每次不同的目标地址存入到寄存器中。利用个寄存器只是为了提高性能,可以将信息保存在内存中。这些目标地址r15拥有很多值,所以很难猜测当前流的具体目标地址。而对于分支条件不满足时,一些语句相当于NOP。

优点 1 可实现 简单不需要复杂的代码分析 或者厚重的代码改变。2 性能影响小 3 安全。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值