本文是我在HPCA 2024上发表的一篇论文,题目为《Modeling, Derivation, and Automated Analysis of Branch Predictor Security Vulnerabilities》。本文的主要贡献是:
随着针对分支预测器的微架构侧信道攻击愈演愈烈,计算机系统的安全边界和用户的安全关键数据正受到严重威胁。由于这些攻击的根本原因是分支预测器的微架构设计忽略了安全问题,因此在设计阶段就能详尽自动地探讨这些问题的分析框架迫在眉睫。本文提出了一个全面的自动评估框架,用于在微架构设计阶段检查分支预测器的安全保证。本文涉及的技术采用三步建模法,抽象描述了19种分支预测器状态和53种可能影响这些状态的操作。随后,本文开发了一个基于符号执行的框架来研究所有三步组合,并推导出156种针对分支预测器的有效攻击模式,其中包括89种以前的工作从未考虑过的新攻击。最后,本文将提出的框架应用于8种安全分支预测器设计和4种典型的基于硬件的反投机执行攻击的措施,以评估它们的安全能力。结果表明,这些安全分支预测器提供了有效的安全保证,并优于那些基于硬件的针对投机执行攻击的缓解措施,这表明安全分支预测器在缓解分支预测器安全漏洞方面有很好的前景。
美食:豆腐脑、油条、胡辣汤
美食:奶茶、烤鱼、包子
美食:铁锅炖、鮰鱼、排骨
晚霞:登山、夕阳
]]>2023年7月13日晚上,历时一年之余,经历拒稿->拒稿->大修->大修->小修的洗礼,终于拿到第一篇学术论文的录用通知。在此,我想将自己的经历记录下来,以此勉励自己。同时,我也非常感谢对我的论文提供帮助的两位老师、六次审稿过程中所有的匿名审稿人、还有一直给予我精神支撑的我的女朋友。
2021年9月,踏上了从我的家乡山东到武汉的飞机,开始了研究生生涯的旅程。尽管自己对于科研生活充满了期待与梦想,但由于自己迟迟无法找到很合适的研究点,因此在研究生的第一年,自己一直处于迷茫的状态。
一个偶然的契机,在阅读了大量的与侧信道有关的论文之后,终于发现了一个可以在智能手机上利用侧信道攻击的点。然后,经过了几个星期的实验与分析,终于确定了自己的想法是可行的,并决定将其写成论文。
由于自己的想法是在智能手机上利用侧信道漏洞发起攻击,因此也很感谢自己的导师出资购买了两块用于实验的手机。正是因为有了如此多的设备,才能够帮助我完成跨设备的实验以及真实场景下的实验,使得这个工作的工作量更加充足、更具有合理性。
经过了接近两个月的实验方法设计、实验数据采集与实验结果分析后,我得到了非常不错的实验结果。然后在2022年的6月,自己终于开始撰写这篇期待已久的科研论文。
在论文撰写的过程中,由于自己的英文水平不是特别出色(彼时英语六级的分数只有450多分,不过随着自己阅读与写作水平的提升,现在已经能够考到550多分了,我已经非常满意),在写作的过程中是采用中文翻译英文的办法(主要借助的工具是DeepL)以及自己再调整措辞和语序的方式。最后,在7月份,我的论文也完成了,并准备投稿到一个CCF-A类的期刊上。
第一次投稿的时间是2022年的7月10日,在2022年9月14日收到了拒稿的邮件。三位审稿人一位给出了大修,一位给出了重投,还有一位是拒绝。尽管这篇文章被拒绝了,但是三位审稿人以及编辑都非常认可我的创新点,因此我仍然对这篇文章充满希望。
然后,我按照三位审稿人给出的意见,逐条逐点进行修改,包括阐述原来论文中表述不够清晰的地方、增加很多很多的实验(约50%)、去掉原来没有必要出现的代码段等等。最后,这篇文章的篇幅也从原来的12页扩展到了15页。我仍然充满期待,因此选择再冲一次CCF-A类期刊。
经过了接近一个月的补充实验和修改,我在2022年10月4日再次投稿到另一个期刊。然而,不遂人愿,2023年3月2日,再次收到拒稿邮件。这次只有两位审稿人,一位给出了大修,一位给出了拒绝,编辑的评论是这篇文章的质量达不到期刊的要求。此时,一是感觉有些难受,二是有些遗憾,总感觉这次的版本投稿到第一次的期刊上就更有机会。不过,我还是相信这篇文章总会有它的归宿,因此我仍然按照审稿人的意见,详细修改了文章。
修改完成后,3月7日,我选择投稿到一个SCI一区的期刊上,非常开心能够在4月21日收到大修的邮件。虽然邮件中看不出三位审稿人具体的推荐意见,不过三位审稿人都非常认可我的工作,提出的14条意见要么是文章结构、要么是对比分析、要么是一些开放性的问题,因此我当时非常的激动。接下来的工作就是逐条回复审稿人,撰写response。
在修改完成后,5月13日我提交了返修稿和回信,这次审稿人也是出奇地快,仅仅4天后的5月17日,就给了又一次大修。这次审稿人只有两个,其中一个同意接收,另一个给出了大修。审稿人的主要意见是觉得我的文章逻辑不够清晰、图片的表述不够清晰、摘要和引言的逻辑不太好、参考文献太旧等。这次我仍然非常细心谨慎回复审稿人的每个问题,尽管有一个问题并不好解答和修改,我也有理有据地回复审稿人我没有修改以及为什么没有修改。
这次的大修在6月11日结束,并提交了返修稿和回信。经过了15天的等待,6月26日,我收到了小修的邮件。这次审稿人仍然有两个,一个接收,一个小修。审稿人现在已经认可我这篇文章的质量能够发表在这个期刊上,然后提出了四点小意见,包括修改摘要和引言的措辞、突出我在文中给出的建议、图表的数据格式、将两个章节合并等。这次的修改非常迅速,我同样认真斟酌修改,并恳切地回复每条建议。
在修改完成后,我于7月12日提交了返修稿。第二天(即7月13日),我的文章被期刊接收了,这也是我学术生涯的第一个小小的里程碑。虽然发表一篇SCI一区的论文在计算机领域不是特别突出的成就,因为我的工作实在是没有办法发表在顶刊和顶会上,但这对于我来说只是一个起点,我也希望自己以后能够发表高水平和高质量的论文。
科研不易,冷暖自知。
在收到小修意见时,有一位审稿人提出了一个非常关键的问题,让我产生了深深的思考:
The current tone of this manuscript sounds like that the authors are educating attackers a new approach to stealth user privacy, which I believe is not the true purpose of this paper. The purpose of this paper is meant to demonstrate a possible attack on an overlooked security vulnerability, which could become very powerful if attackers use sophisticated techniques.
对啊,我们所有做安全的人,我们进行漏洞挖掘的目的是什么?难道我们是为了破坏计算机、破坏移动设备的隐私数据吗?难道我们是要帮助攻击者来入侵其他用户吗?仔细想来,我们的目的应该是让大家注意到这个问题,从而避免问题、加以防护、或者进行检测,这才应该是我们的出发点。
此外,偶然在知乎上读到如下回答,深有同感:
The academic is not an army race. It does not really matter how fancy the model is. It does not really matter whether the model can achieve the sota performance. The real innovation is to find something new and this work has found a fresh new perspective.
我们为什么一定要比别人好呢?似乎我的工作也并不是比别人好,也达不到Related Work中的performance,那又如何呢?如果我们能找到一个别人没有关注过的点,哪怕很微小,似乎只要有一点点novelty,足矣。相反,我也在深思,对于已知的威胁点,通过ML、DL、甚至是RL的方式提高攻击者攻击能力的意义在哪里呢,毕竟这些威胁已经被证明存在了,除非目前的防御手段无法防御…
]]>从计算机体系结构的角度来说,内存安全违规(memory safety violation)一般分为两大类:
而面向返回编程(Return-Oriented Programming,ROP)、面向跳转编程(Jump-Oriented Programming,JOP)和面向调用编程(Call-Oriented Programming,COP)都是基于空间违规的攻击手段,本文将从攻击基本原理、现有芯片级对策和思考三个方面来介绍ROP/JOP/COP。
而ROP攻击产生的一大原因是因为,现代操作系统为了防止攻击者在栈上发起代码注入漏洞,采用了W^X的内存保护机制,即栈上的内存空间只能执行,不能写入。因此,攻击者在栈上发起代码注入漏洞时,只能通过覆盖返回地址来控制程序的执行流程,而这种攻击手段就是ROP。
以下是一个较为详细的ppt:memory-safety.pdf
在x86中,ret指令指令的执行可以看做:
(1)pop:从栈中弹出一个返回地址;
(2)jmp:跳转到该返回地址处执行。
此外,函数调用的参数传递是通过寄存器(eax、ebx、ecx、edx等)来完成的,比如:
1 | execve("/bin/sh", NULL, NULL); |
其中,系统中断的值为0x80,而execve调用的值为0xb(存放在eax寄存器中),剩余三个参数分别为:/bin/sh(存放在ebx寄存器中)、NULL(存放在ecx寄存器中)、NULL(存放在edx寄存器中)。因此,如果攻击者能够将返回地址覆盖为0x80指令所在的地址,并且将四个寄存器的值分别设置为0xb、/bin/sh、NULL、NULL,那么就可以实现execve(“/bin/sh”, NULL, NULL)的调用。ROP代码段是一串以ret指令结尾的代码段,因此攻击者希望填充的恶意数据为:
(0)数据与返回地址的偏移量;
(1)pop eax; ret;
所在的地址;
(2)eax寄存器的目标值0xb;
(3)pop ebx; ret;
所在的地址;
(4)ebx寄存器的目标值/bin/sh;
(5)pop ecx; ret;
所在的地址;
(6)ecx寄存器的目标值NULL;
(7)pop edx; ret;
所在的地址;
(8)edx寄存器的目标值NULL;
(9)0x80指令所在的地址。
指令序列的寻找可以通过JonathanSalwan开发的ROPgadget工具[1]来完成,以下面这段代码为例:
1 | ... |
由于gets函数存在栈溢出漏洞,因此攻击者可以通过恶意输入var1覆盖返回地址,并完成恶意代码执行:
(1)计算var1与返回地址的偏移量;
(2)用ROPgadget工具生成ROP链;
(3)将ROP链写入var1,从而控制程序的执行流程。
在JOP攻击中,攻击者控制的恶意数据覆盖jmp指令的跳转地址实现控制流劫持,JOP代码段是一串以jmp指令结尾的代码段。而在COP攻击中,攻击者控制的恶意数据覆盖call指令的跳转地址实现控制流劫持,COP代码段是一串以call指令结尾的代码段。对于JOP/COP攻击而言,攻击者要找寻的代码段中,除了要修改目标寄存器外,还要包含一个用于修改后续jmp/call跳转地址的pop指令(在ROP攻击中,由ret指令的特点,不需要攻击者额外控制)。
值得一提的是,在实际应用中,攻击者为了达成劫持控制流的目的,会将三种代码段通过组合的方式发起混合攻击。
Intel CET(Control-Flow Enforcement Technology)是Intel新推出的一项新的硬件级对策,其主要目的是防止攻击者通过ROP/JOP/COP等攻击手段来劫持控制流。
对于ROP攻击的防护,其基本思想与影子栈(shadow stack)类似,即由操作系统在内存中复制一份程序的内存栈或者是仅仅保留控制流跳转地址。然后,这个影子栈无法由正常的store、load指令进行控制,只能通过专门的指令来进行控制。因此,即使攻击者覆盖了软件栈上的返回地址,但是由于影子栈中仍然保存着原始的跳转地址,因此检查失败后会通过抛出异常来终止程序的执行。
对于JOP/COP攻击的防护,Intel提出一种叫做IBT(Indirect Branch Tracking)的技术,其基本思想是通过编译器在合理的间接跳转中⽤新的指令做标记,然后程序执行时会检查下一条指令是否为新添加的指令(endbr),如果不是则会抛出#CP异常。
ARM PAC(Pointer Authentication)是ARMv8.3引入的一项新的硬件级对策,其主要通过对指针进行鉴权来防止攻击者通过ROP/JOP/COP等攻击手段来劫持控制流。
这种防护方法的基本原理是,利用64位地址空间中暂时空闲的高16位来存放指针的鉴权结果(MAC码),然后在每次指针使用前,都会对指针进行鉴权,如果鉴权失败,则会抛出异常来终止程序的执行。
利用预测执行机制,通过隐蔽信道泄漏PAC机制的鉴权结果。
ZeRØ提出了独特的内存指令和新颖的元数据编码方案来保护代码和数据指针,仅仅只需要微小的微架构变化。ZeRØ在SPEC CPU2017基准上的性能开销为零,VLSI测量显示了低功率和面积开销。
No-FAT将内存分配大小(例如malloc大小)作为一个架构特征,来克服传统内存安全方法的许多棘手问题,例如与不安全软件的兼容性和显著的性能下降。No-FAT在SPEC CPU2017基准测试中产生了8%的开销,VLSI测量显示了低功率和面积开销。
[1] https://github.com/JonathanSalwan/ROPgadget
[2] Ravichandran, J., Na, W. T., Lang, J., & Yan, M. (2022, June). PACMAN: attacking ARM pointer authentication with speculative execution. In Proceedings of the 49th Annual International Symposium on Computer Architecture (pp. 685-698).
[3] Ziad, M. T. I., Arroyo, M. A., Manzhosov, E., & Sethumadhavan, S. (2021, June). ZeRØ: Zero-overhead resilient operation under pointer integrity attacks. In 2021 ACM/IEEE 48th Annual International Symposium on Computer Architecture (ISCA) (pp. 999-1012). IEEE.
[4] Ziad, M. T. I., Arroyo, M. A., Manzhosov, E., Piersma, R., & Sethumadhavan, S. (2021, June). No-FAT: Architectural support for low overhead memory safety checks. In 2021 ACM/IEEE 48th Annual International Symposium on Computer Architecture (ISCA) (pp. 916-929). IEEE.
]]>参考learning gem5的part II部分进行gem5的学习。
主要工作:
首先创建一个python类,包含三个参数:
1 | class SimpleObject(SimObject): |
然后创建与python类对应的C++类,并创建简单的hello函数:
1 | class SimpleObject : public SimObject |
修改SConscript文件,将先前创建的python类和C++类添加进去:
1 | SimObject('SimpleObject.py', sim_objects=['SimpleObject']) |
执行scons重新编译gem5:
1 | $ scons build/X86/gem5.opt -j5 |
修改自定义的配置文件,设置root.hello为SimpleObject(),并执行:
根据执行结果的输出,可以看到成功的添加SimpleObject并运行。
创建python类和C++类,假设MemoryObject一端连接CPU一端连接内存总线,那么需要创建三个接口:
1 | class SimpleMemobj(SimObject): |
1 | SimpleMemobj::SimpleMemobj(const SimpleMemobjParams ¶ms) : |
根据learning gem5网站的描述以及提供的开源代码,大致分为以下15个函数:
序号 | 作用域 | 函数 |
---|---|---|
1 | SimpleMemobj | SimpleMemobj(const SimpleMemobjParams ¶ms) |
2 | SimpleMemobj | Port& getPort(const std::string &if_name, PortID idx) |
3 | SimpleMemobj::CPUSidePort | void sendPacket(PacketPtr pkt) |
4 | SimpleMemobj::CPUSidePort | AddrRangeList getAddrRanges() const |
5 | SimpleMemobj::CPUSidePort | void trySendRetry() |
6 | SimpleMemobj::CPUSidePort | void recvFunctional(PacketPtr pkt) |
7 | SimpleMemobj::CPUSidePort | bool recvTimingReq(PacketPtr pkt) |
8 | SimpleMemobj::CPUSidePort | void recvRespRetry() |
8 | SimpleMemobj::MemSidePort | void sendPacket(PacketPtr pkt) |
9 | SimpleMemobj::MemSidePort | bool recvTimingResp(PacketPtr pkt) |
9 | SimpleMemobj::MemSidePort | void recvReqRetry() |
10 | SimpleMemobj::MemSidePort | void recvRangeChange() |
11 | SimpleMemobj | bool handleRequest(PacketPtr pkt) |
12 | SimpleMemobj | bool handleResponse(PacketPtr pkt) |
13 | SimpleMemobj | void handleFunctional(PacketPtr pkt) |
14 | SimpleMemobj | AddrRangeList getAddrRanges() const |
15 | SimpleMemobj | void sendRangeChange() |
在learning gem5的网站中,给出了这样一个函数之间的关系图:
主要分为以下步骤:
1 | system.memobj = SimpleMemobj() |
在m5out中的config.dot.pdf的结果如下:
执行结果如下,可以看出程序仍然能够正常执行:
参考learning gem5的part I部分,对gem5的配置文件的编写进行学习。
在这次的配置中,主要涉及到内存、Cache的配置,与之前复现的那篇论文相比,没有实现TLB。
此外,我还发现learning gem5中的很多参数已经与最新版本的gem5有一定的区别,尽管bus.slave和bus.master等参数在新版本(v22)中仍然可用,但是我还是将他们替换成新版本(v22)推荐的cpu_side_ports和mem_side_ports。
第一步,导入所需的依赖包以及初始化系统:
1 | # 导入gem5的objects |
第二步,配置系统时钟频率和内存大小,我配置的时钟频率为1GHz,内存大小为2G:
1 | # 设置系统的时钟频率为1GHz |
第三步,创建CPU、内存控制器、中断控制器等,并进行端口连接:
1 | # 创建一个CPU |
第四步,创建进程并设置运行参数,我选择了gem5中自带的hello world程序进行测试:
1 | # 创建一个进程 |
第五步,初始化以及运行:
1 | # 初始化gem5 |
输出的配置结果如下,可以看到一个简单的CPU与内存等的连接图:
运行结果如下,可以看出输出了Hello World:
L1指令缓存类,实现了简单的参数以及与CPU连接的函数:
1 | class L1ICache(L1Cache): |
L1数据缓存类,实现了简单的参数以及与CPU连接的函数:
1 | class L1DCache(L1Cache): |
创建L1 Cache并连接L2总线:
1 | # 创建L1Cache |
L2缓存类,只实现了简单的latency等参数,以及两个总线连接的函数:
1 | class L2Cache(Cache): |
创建L2 Cache并连接总线:
1 | # 创建L2 Cache |
输出的配置结果如下,与前面的简单配置相比,更加复杂,不过逻辑还是很清晰:
运行结果如下:
序号 | 论文 | 出处 |
---|---|---|
1 | DAGguise: Mitigating memory timing side channels | ASPLOS 2022 |
2 | Pinned loads: Taming speculative loads in secure processors | ASPLOS 2022 |
3 | Abusing Cache Line Dirty States to Leak Information in Commercial Processors | HPCA 2022 |
4 | unXpec: Breaking Undo-based Safe Speculation | HPCA 2022 |
5 | PS-ORAM: Efficient crash consistency support for oblivious RAM on NVM | ISCA 2022 |
6 | MOESI-prime: Preventing coherence-induced hammering in commodity workloads | ISCA 2022 |
7 | ProTRR: Principled yet Optimal In-DRAM Target Row Refresh | S&P 2022 |
8 | SecSMT: Securing SMT processors against contention-based covert channels | USENIX Security 2022 |
9 | Composable Cachelets: Protecting Enclaves from Cache Side-Channel Attacks | USENIX Security 2022 |
本文研究了内存时序旁路的缓解问题,攻击者利用DRAM控制器内的争夺来推断受害者的秘密。这类通道已经很实用,对共享内存环境中的安全计算构成了重要的挑战。
现有的最先进的内存定时侧信道缓解措施有几个关键的性能和安全限制。先前的方案需要繁琐的静态带宽划分,广泛的剖析阶段,或者根本无法防止利用细粒度的定时和银行信息的攻击。
作者提出了DAGguise,这是一种防御机制,可以完全防止内存时间侧信道,同时允许动态流量争用,以实现良好的性能。DAGguise利用一种新的抽象内存访问表示法,即有向无环请求图(简称DAG),来模拟经历争夺的内存访问模式。DAGguise根据公开的𝑟DAG塑造受害者的内存访问模式,通过轻量级的剖析阶段获得,完全消除了信息泄漏。
作者形式化验证了DAGguise的安全性,证明它保持了强大的安全保证。此外,通过允许动态流量竞争,DAGguise实现了相对于Fixed Service的12%的整体系统速度提升,Fixed Service是最先进的缓解机制,对于不需要保护的同地应用,其相对速度提升了20%。作者进一步宣称,DAGguise的原则可以被推广到保护其他类型的基于调度器的时序侧信道,例如那些针对片上网络或SMT内核的功能单元的侧信道。
在投机执行的安全框架中,当一条指令不再容易受到流水线压制时,它就会达到其可见点(VP)。在一个潜在的泄漏指令达到其VP之前,它必须停滞,除非有一个防御方案,如隐形投机提供保护。不幸的是,无论是停顿还是保护前VP指令的执行,通常都有性能上的代价。
实现低开销安全执行的方法之一是开发技术,加速VP从旧指令向新指令的推进。在本文中,作者提出了一个这样的技术。作者发现,在没有可能违反内存一致性(MCVs)的情况下,加载VP的进展主要受到阻碍。因此,作者的技术被称为 “钉住负载”,试图使负载尽可能早地不受MCVs的影响,作者称之为在流水线上钉住负载的过程。其结果是加快了副总裁的进度,减少了防御方案的执行开销。
在本文中,作者描述了Pinned Loads所需要的硬件,以及两种可能的Pinned Loads设计,在硬件要求和性能之间有不同的权衡。作者的评估表明,Pinned Loads非常有效:用Pinned Loads扩展三种流行的防御方案,防止投机执行攻击,在SPEC17和SPLASH2/PARSEC应用中的平均执行开销减少了约50%。例如,在SPEC17上,三种防御方案的执行开销从112.6%下降到51.3%,从35.8%下降到15.3%,以及从24.8%下降到13.2%。
缓存已经被用来构建各种类型的隐蔽和侧面渠道来泄露信息。大多数隐蔽的高速缓存通道利用了高速缓存点击和高速缓存失误之间的时间差异。然而,作者引入了一个新的和更广泛的缓存隐蔽渠道攻击分类。Hit+Miss,Hit+Hit,以及Miss+Miss。作者强调,处于不同状态的缓存线的缓存缺失(或缓存命中)可能有更大的时间差异,这些可以被用作定时通道。基于这种分类,作者提出了一种新的稳定和隐蔽的Miss+Miss缓存通道。回写型高速缓存在现代处理器中被广泛部署。
本文详细介绍了一种方法,即替换延迟的差异可以用来构建基于时间的通道(称为WB通道)来泄露回写缓存中的信息。发送方对缓存行的任何修改都会将其设置为脏污状态,而接收方可以通过测量替换这个缓存集的延迟来观察到这一点。作者还演示了发送方如何利用缓存组中不同数量的脏缓存线来提高编码多比特的符号的传输带宽。在发送方和接收方之间没有共享内存的超线程设置中,商业系统中WB信道的峰值传输带宽可以在每个缓存集1300到4400kbps之间变化。
与大多数现有的总是针对特定内存地址的高速缓存通道相比,新的WB通道专注于高速缓存集和高速缓存行的状态,使得通道很难受到内核上其他进程的干扰,而且它们仍然可以在使用随机替换策略的高速缓存中工作。作者还从高速缓存负载的数量和高速缓存失误率的角度分析了WB通道的隐蔽性。作者讨论并评估了可能的防御措施。本文最后讨论了各种形式的侧面通道攻击。
利用投机执行来泄密的投机执行攻击在工业界和学术界都引起了极大的关注。它们主要是利用由错误猜测和压制指令(即瞬时指令)留下的微架构状态的隐蔽或侧面通道。大多数此类攻击的目标是缓存状态。现有的基于缓存的防御系统对投机执行的攻击分为两类:shadow和undo。
大多数shadow防御系统对投机性指令的执行元数据进行缓冲,只有在投机性执行的指令被确定后才将其放入缓存。由于错误猜测是罕见的情况,undo防御系统允许猜测性指令修改缓存状态。一旦出现错误的猜测,它们会将缓存状态回滚到瞬时指令执行之前的状态。然而,shadow防御系统最近被投机性干扰攻击发现是不安全的。这就要求对undo防御系统进行深入的安全检查,以应对投机执行攻击。
在本文中,作者提出了unXpec作为对基于Undo的安全推测的第一种攻击。它利用了undo防御的回滚操作所表现出的秘密依赖的时间通道。具体来说,回滚过程需要使瞬时指令带入缓存的缓存行失效,并通过瞬时加载的数据从缓存中恢复被驱逐的缓存行。这就开辟了一个渠道,通过回滚时是否涉及很多无效和恢复的时间差异来编码秘密。作者进一步利用驱逐集来执行更多的恢复操作。这就产生了更长的回滚时间,从而产生了更大的依赖于秘密的时间差异。
作者在开源的CleanupSpec上展示了时间通道,这是一个有代表性的undo解决方案。一个单一的瞬时负载可以触发22个周期(没有驱逐集)和32个周期(有驱逐集)的秘密依赖的时间差异,这对于构建投机执行攻击的隐蔽通道来说是足够利用的。作者在gem5模拟器上运行unXpec并启用CleanupSpec。结果显示,unXpec可以以140Kbps的高速度泄露秘密,准确率超过90%。简单地强制执行恒定时间回滚以减轻unXpec的影响可能会引起超过70%的性能开销。
Oblivious RAM(ORAM)是一种可证明的安全原件,用于防止内存总线上的访问模式泄漏。通过对数据块进行重新映射和访问冗余块,ORAM通过模糊化防止访问模式泄露。字节可寻址的非易失性存储器(NVM)被认为是主存储器的候选者,因为它具有更好的可扩展性,有竞争力的性能和持久的数据存储。虽然之前有很多工作集中在提高ORAM在传统的基于DRAM的内存系统上的性能,但当内存技术转向使用NVM时,为了安全、正确性和性能,需要确保一个高效的碰撞一致性的ORAM。对ORAM系统直接使用传统的基于软件的碰撞一致性支持不仅昂贵,而且不安全。
在这项工作中,作者研究了如何用一个基于NVM的内存系统来坚持ORAM的构建。为了在不破坏ORAM系统安全和影响性能的情况下支持碰撞一致性,作者提出了PS-ORAM。PS-ORAM包括一个新的ORAM控制器设计和一套支持崩溃一致性的ORAM访问协议。
作者对PS-ORAM与不支持崩溃一致性的系统进行了评估,非递归和递归的PS-ORAM只产生了4.29%和3.65%的额外性能开销。结果表明,PS-ORAM不仅以最小的性能和硬件开销支持有效的崩溃一致性,而且对NVM的寿命也是友好的。
之前的工作表明,RowHammer攻击–通过频繁激活同一行来翻转DRAM中的比特–是可行的。广告商通常通过精心设计的指令序列来实施这些攻击,以绕过CPU缓存。然而,作者发现了一种新的翻转形式,作者称之为相干性诱导的翻转,由英特尔实施的缓存相干性非统一内存访问(ccNUMA)协议引起。作者表明,这种翻转发生在一个主要云提供商的生产硬件的商品基准中,这是第一次发现由非恶意代码产生的翻转。鉴于DRAM对比特翻转的敏感性上升,防止相干性引起的翻转以确保云的可靠性和安全性是最重要的。
因此,作者介绍了MOESI-prime,这是一种ccNUMA相干协议,可以缓解相干性引起的翻转,同时重新保持英特尔最先进的可扩展性。MOESI-prime表明,大多数DRAM的读和写触发这种翻转是不必要的。因此,通过在一致性协议中编码额外的信息,MOESI-prime可以省略这些读和写,防止在非恶意和恶意的工作负载中出现一致性引起的敲击。此外,通过省略不必要的读写,MOESI-prime对平均性能(在MESI和MOESI的±0.61%范围内)和平均DRAM功率(0.03%-0.22%的改进)的影响在评估的ccNUMA配置中可忽略不计。
随着科技的发展,DRAM越来越容易受到Rowhammer攻击的影响。本文介绍了PROTRR,这是第一个原则性的DRAM内目标行刷新缓解措施,具有安全保证和低开销的界限。与需要改变内存控制器的现有建议不同,PROTRR的DRAM内性质使其能够无缝集成。然而,这意味着PROTRR必须尊重DRAM协议的同步性,这限制了在任何特定时间可以保护的DRAM行的数量。
为了克服这一挑战,PROTRR主动刷新未来最有可能观察到比特翻转的每一行。虽然这个策略可以捕捉到被攻击最多的行,但其他一些行可能仍然在雷达下飞。作者利用这一观察来构建FEINTING,这是一种新的行锤攻击,作者证明在这种情况下是最佳的。然后,作者对PROTRR进行配置,使其能够安全地应对FEINTING。为了实现这一点,PROTRR应该跟踪对每一行的访问,这在硬件上实现起来非常昂贵。相反,PROTRR使用一个新的频繁项目计数方案,利用FEINTING在可容忍的DRAM漏洞、计数器的数量和额外刷新的数量之间提供一个可证明的最佳而灵活的权衡。
作者使用PROTRR的ASIC实现和周期精确的模拟进行的广泛评估表明,PROTRR可以为当前和未来的DRAM技术提供原则性的保护,对性能、功耗和面积的影响可以忽略不计。PROTRR与DDR4和DDR5中新的刷新管理(RFM)扩展完全兼容。
本文首次全面分析了高性能同步多线程(SMT)处理器中基于争用的安全漏洞。它的特点是描述了整个共享管道的争用情况,以及每个资源的潜在泄漏渠道。此外,它提出了一套统一的缓解/隔离策略,在保留完整的、不安全的SMT实现的大部分性能的同时,极大地减少了这种泄漏。这些结果为考虑SMT执行及其性能优势奠定了基础,甚至对安全敏感的应用来说,它也是一个合理的选择。
诸如英特尔SGX这样的隔离执行架构的安全性受到了最近出现的侧信道攻击的极大威胁。缓存侧信道攻击允许对手在不直接访问飞地内存的情况下泄露存储在飞地内部的秘密。在某些情况下,即使不知道受害者的应用代码或没有操作系统级别的权限,秘密也会被泄露。
作者提出了Composable Cachelets(CC)的概念,这是一种新的可扩展策略,用于动态划分最后一级缓存(LLC),将飞地与其他应用程序和相互之间完全隔离。CC支持缓存中的飞地隔离,能够在飞地被创建和销毁时动态地重新调整缓存容量。作者提出了一个缓存感知和飞地感知的操作语义,以帮助严格建立CC的安全属性,并且作者通过实验证明,CC在对性能和复杂性影响不大的情况下挫败了对缓存的旁路攻击。
]]>江城明月夜,何以为家,珞珈即家。
]]>从去年开始,一直在学习Meltdown攻击和Spectre攻击,包括攻击原理的学习、攻击的复现(在x86和ARM两种架构下复现)、利用符号执行(基于LLVM的KLEE)进行检测等。
Meltdown攻击是通过绕过CPU的权限检查机制,将内核态的数据读取到用户态,从而实现数据泄露。Spectre攻击是通过利用CPU的分支预测机制,让CPU错误预测执行,从而实现数据泄露。
这两种攻击都是通过利用CPU的特性来实现的,而gem5是一个CPU模拟器,并且提供了这两种攻击所利用到的乱序执行、分支预测特性以及Cache,因此理论上可以利用gem5来模拟这两种攻击。
在查阅相关资料时,发现2021年的一篇文章[1],利用gem5模拟了Spectre攻击,因此决定在学习gem5的过程中对这篇论文进行复现。
主要工作:
PoC地址[6]:https://spectreattack.com/spectre.pdf
CPU类型为乱序执行的DerivO3CPU,使用LTAGE分支预测器。
1 | ./build/X86/gem5.opt --debug-flags=O3PipeView --debug-start=369832000 --debug-file=trace.out \ |
在gem5.opt添加参数–debug-flags=O3PipeView –debug-start=369832000 –debug-file=trace.out,可以在m5out文件夹下生成trace.out文件,该文件包含了CPU的执行轨迹,可以利用o3-pipeview.py脚本将其转换为可视化的o3 pipeline。
1 | ./util/o3-pipeview.py -c 1000 -o pipeview.out --color m5out/trace.out |
在1GHz下,每个周期的Tick是1000(-c 1000),转化为可视化的o3 pipeline如下:
本节的主要内容是复现论文”Reproducing Spectre Attack with gem5: How To Do It Right?”的环境配置。
编译ARM架构的gem5:
1 | $ scons build/ARM/gem5.opt -j5 |
编译m5term:
1 | $ cd util/term |
从[3]中克隆代码到本地:
1 | $ git clone https://github.com/pierreay/reproduce-spectre-gem5.git |
在gem5目录下有树莓派4和A72处理器核的配置文件:
下载系统和内核镜像文件:
1 | $ wget -O - http://dist.gem5.org/dist/current/arm/disks/linaro-minimal-aarch64.img.bz2 | bunzip2 > linaro-minimal-aarch64.img |
解压缩后的文件目录为:
接下来利用dd命令创建workload.img文件:
1 | $ dd if=/dev/zero of=workload.img count=200K |
创建一个回环设备以便将镜像文件作为块设备访问:
1 | $ dev=$(sudo losetup -f) |
创建分区表以及ext4文件系统:
1 | $ echo "," | sudo sfdisk $dev |
最后,从回环设备中卸载:
1 | $ sudo losetup -d $dev |
这里如果直接按照[2]中执行,会遇到以下问题:
(1)没有将gem5的config添加到python的搜索路径中,会报找不到common的错误:
1 | ModuleNotFoundError: No module named 'common' |
因此,需要修改RPIv4.py文件,添加:
1 | sys.path.append("/home/gem5/gem5/configs/") |
(2)在gem5的commit中(5195c801156d1f9ff08d7ef4aceff2ff532c852),参数ArmITB和ArmDTB被统一换成了ArmTLB:
1 | arch-arm, configs: Remove ArmITB/ArmDTB |
因此,修改ARMv8A_Cortex_A72.py文件,将ArmITB和ArmDTB替换成ArmTLB:
1 | class ARM_A72_TLB_L1D(ArmTLB): |
(3)在gem5的commit中(6ecf110b06d7333aae13bcc16216cc127fdda7f0),flags_addr被移除:
同时,参考configs/example/arm/devices.py文件,将RPIv4.py中的对应代码去掉:
1 | # system.flags_addr = system.realview.realview_io.pio_addr + 0x30 |
(4)在gem5的commit中(5f95d7a89a56513876a7bb5dd8055d6b1d080c8b),IntrControl被移除:
1 | cpu: IntrControl, clear all and check helpers |
因此,直接将RPIv4.py中的以下代码注释掉:
1 | # system.intrctrl = IntrControl() |
(5)slave和master的接口变化:
修改RPIv4.py文件:
1 | # Wire up the system port to the previously created memory bus (gem5 |
修改A72.py文件:
1 | def connectCacheL2(self, bus): |
首先,配置M5_PATH环境变量:
1 | $ export M5_PATH=$PWD/img/ |
接着,引导系统:
1 | $ build/ARM/gem5.opt -q -d 01boot \ |
引导过程如下:
然后,在另一个终端连接到m5term:
1 | $ util/term/m5term localhost 3456 |
但是这一步可能是因为版本的问题失败了。尽管终端的输出显示已经开始模拟,连接m5term也有输出和提示,但是没有拿到ARM模拟器的shell,也没有引导成功的说明。
下载Linux系统和内核镜像文件:
1 | $ wget -O - http://dist.gem5.org/dist/v22-0/arm/aarch-system-20220707.tar.bz2 | tar xjv |
引导系统:
1 | $ build/ARM/gem5.opt -q ./configs/example/fs.py --num-cpu=4 \ |
连接m5term:
1 | $ util/term/m5term localhost 3456 |
引导成功的截图如下:
挂载disk镜像并写入攻击程序:
1 | $ mkdir -p disk |
执行攻击:
1 | $ cd spectre |
但是没有得到预期的结果,攻击失败,猜测应该是环境与论文中的不一致导致的。
之前曾经接触过gem5,不过只是停留在利用gem5完成一些简单的工作,并没有对gem5的源代码以及具体的配置做深入的学习。
本次的目标是打算对gem5的配置文件(即具体的System配置)以及源代码(即gem5每个功能的实现)有深入的学习和理解。
我使用的是最新的Ubuntu 22.04:
环境 | 版本 |
---|---|
虚拟机 | VMware Workstation 16.2.4 |
系统 | Ubuntu Server 22.04.1 LTS |
CPU | Intel(R) Core(TM) i5-9400 CPU @ 2.90GHz |
内存 | 8GB |
首先,更换apt源为阿里云源,以加快下载速度:
1 | $ sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak |
插入以下内容:
1 | deb http://mirrors.aliyun.com/ubuntu/ jammy main restricted universe multiverse |
然后,更新apt源并安装所需的依赖:
1 | $ sudo apt update |
从gem5的官方仓库克隆源码:
1 | $ git clone https://gem5.googlesource.com/public/gem5 |
利用SCons命令编译gem5,以编译x86架构的处理器为例:
1 | $ cd gem5 |
编译完成后的输出如下图所示:
在build/X86
目录下生成的gem5.opt
文件,即为编译好的gem5可执行文件。
此外,除了支持x86
架构,gem5还支持ARM
、MIPS
、RISC-V
等架构,具体的参数为修改build/ISA
中的ISA
为对应的架构名即可。
gem5的后缀名代表的含义是编译时的优化参数,除了opt
外,还有debug
、fast
,具体的含义可以参考官方文档。
以gem5自带的测试程序为例,运行gem5的命令为:
1 | $ build/X86/gem5.opt \ |
其中,--cpu-type
参数指定了使用的CPU类型,--caches
参数指定了使用的缓存类型,--cmd
参数指定了运行的程序。
运行结果如下图所示: