具体而言,所有的现代处理器都会进行推测执行,例如,它们会假设某个值从内存中读取,或者某个if条件是真是假,使之可以根据这些假设提前执行任务。如果假设正确,推测结果就会保留;如果假设错误,推测结果就会放弃,处理器则会重新计算。推测执行并不是处理器的架构特征,而是执行特征,因此应该在完全不可见的情况下执行程序。当处理器放弃错误的推测时,看起来就像这个推测从未发生过一样。
但“崩溃”和“幽灵”漏洞的研究人员发现,推测执行并非完全不可见。当处理器放弃推测结果时,错误推测会留下一些痕迹。例如,推测可能会改变处理器缓存中的数据。程序可以通过测量从内存中读取数值的时间来探测这些变化。
通过仔细构建,攻击者便可让处理器根据一些兴趣值进行推测,并使用缓存变化来揭露出推测值的实际情况。这就会对网络浏览器等应用构成威胁:可以利用恶意JavaScript来了解正在运行的进程的内存布局,然后使用这些信息来利用其他安全漏洞执行任意代码。
网络开发者认为他们可以在浏览器处理过程中构建安全沙盒,这样一来,脚本就无法了解其包含进程的内存布局。从架构角度来讲,这种假设似乎完全合理。但由于存在“幽灵”攻击,导致这些假设无法成立。
英特尔、苹果和其他采用ARM架构的芯片所面临的“崩溃”漏洞则是这种方式的一个可怕变体。它能让恶意程序从操作系统内核中提取数据。在发现这种漏洞后,操作系统已经进行了一些调整,将多数数据隐藏,使之无法被这种恶意程序发现。英特尔也对其处理器进行了专门的调整来解决“崩溃”问题,所以该公司最近的处理器已经不再需要激活这些变化。
“幽灵”更加难以应对。已经出现了很多软件技术阻止处理器通过推测方式执行敏感代码,或者限制信息通过推测执行方式泄露出去。
谷歌研究人员发现,这些软件措施有很多不完善的地方,例如在从内存加载许多值之后便会屏蔽所有的推测,虽然可以屏蔽很多攻击,但实际使用中却效果不佳。研究人员还尝试修改Chrome V8 JavaScript引擎,但却会导致性能下降三分之一或五分之一。其他措施也会遭遇类似的问题。
但所有措施都存在一个问题:没有一种方式能够屏蔽所有的“幽灵”变种,因此需要将许多技术结合起来。而由于这些技术不能任意结合,所以单纯是找到合适的技术组合也是一个巨大的挑战。另外,谷歌还设计了一个通用目的“幽灵”家族攻击,无法用目前的任何技术实现防御。
“幽灵”攻击的一项重要因素是衡量缓存变化的时间系统。有一种想法认为,可以让应用使用的时钟不那么精确。这种理论认为,如果需要以几纳秒的长度来衡量缓存差异,那么以毫秒为精度单位可能就会太过粗糙,无法发动攻击。但研究人员却设计了一种技术来放大这种时间差异,而这种放大效果可以战胜这种让时间系统变得粗糙的防御方式。
正因如此,该公司认为不可能完全依靠软件技术来防御“幽灵”攻击。硬件调整或许可以实现这种效果,但这目前仍未得到证实。