ARMv8-A处理器通常利用多层缓存、无序执行和分支预测等优化技术来提高性能。
这些优化技术不可避免地受到缓存相关攻击的威胁,包括Flush-Reload、Flush-Flush、Meltdown、Spectre及其变体。这些攻击可以打破不同进程之间甚至用户和内核空间之间的隔离边界。研究人员提出了许多防御方案来抵御这些与缓存相关的攻击。然而,它们要么需要修改硬件体系结构,要么覆盖范围不完整,要么引入显著的性能开销。
在本文中,我们在ARMv8A上提出了FlushTime,这是一个更安全的缓存刷新指令和通用定时器的协作框架。
FlushTime基于ARMv8-A的指令/寄存器陷阱机制,将缓存刷新指令和通用定时器从用户空间陷阱到内核空间,并使它们在内核空间中相互协作。当调用flush指令时,通用计时器分辨率将在几个时间片内降低。这种协作机制可以极大地减轻所有基于刷新的缓存相关攻击的威胁。由于普通应用程序很少需要在调用flush指令后立即获得高分辨率时间戳,FlushTime不会影响系统的正常运行。安全性和性能评估表明,FlushTime可以抵御所有基于刷新的缓存相关攻击,同时引入极低的性能开销。
缓存相关攻击:Meltdown、Specture等
常用方案:利用缓存刷新指令来减少噪声并提高与缓存相关攻击的分辨率
问题:Meltdown、Specture和大多数已经发现的变体(基于Flush Reload)也将缓存刷新指令作为攻击步骤将这种与缓存相关的攻击命名为“基于刷新的缓存相关攻击”
目前最流行、噪音最小、最简单的缓存攻击形式:攻击者知道刷新指令和目标虚拟地址时,可以实施基于刷新的缓存相关攻击
尽管刷新指令大大降低了缓存攻击的阈值,但字啊用户空间中禁止刷新指令是不可行的。->这主要是因为用户空间中的刷新指令在某些特定应用程序中是有用和必要的。例如,在一些软硬件协同设计中,通常需要在软件和硬件之间传输小批量的不连续数据。在这种应用场景中,在内核空间中调用DMA传输模块将非常耗时且操作复杂,而在用户空间中可用的刷新指令非常高效。在硬件存储器具有虚拟地址映射的情况下,可以直接将数据从CPU存储器虚拟地址写入硬件存储器虚拟地址。然后,CPU可以非常有效地调用刷新指令,以确保CPU缓存和硬件存储器之间的数据一致性。因此,确保用户空间中缓存刷新指令的可用性,同时避免它们带来的安全漏洞,是一个很有吸引力的话题。
为了检测和防御基于刷新的缓存相关攻击,以前提出的许多防御方案各有缺陷:
这篇文章提出了FlushTime,这是一个框架,可以抵御所有基于刷新的缓存相关攻击,同时确保ARMv8-a上刷新指令和通用定时器的可用性
FlushTime利用ARMv8-a的指令/寄存器陷阱机制将缓存刷新指令和通用定时器访问陷阱到内核中断处理程序中。在内核空间中,这两个处理程序相互写作来处理中断。
当进程调用缓存刷新指令时,从通用计时器获得的时间分辨率将暂时降低。基于这种协作机制,FlushTime在不影响刷新指令和通用定时器的正常使用的情况下,有效地减轻了基于刷新的缓存相关攻击的威胁。
ARMv8-A上有一个寄存器SCTLR_EL1(EL1系统控制寄存器)它可以控制缓存刷新指令的执行权限级别
默认情况下,SCTLR_EL1.UCI的位设置为1。在此设置下,可以在EL0级别调用缓存刷新指令,这些指令在用户空间中执行。相反,如果位置SCTLR_EL1.UCI设置为0,则缓存刷新指令被捕获到EL1级别(内核空间)在此设置下,当在EL0级别(用户空间)调用缓存刷新指令时,将生成中断,系统将进入EL1级别(内核空间)来处理此中断。
在linux内核中,user_cache_maint_handler()是缓存刷新指令的现成中断处理程序。在FlushTime的设计中,为SCTLR_EL1.UCI被设置为0,因此EL0级别(用户空间)的所有刷新指令执行都被捕获到user_cache_maint_handler()中。我们对user_cache_maint_handle()做了一个小的修改,这样内核就可以获得当前进程的降低分辨率的触发器