LWN:终于能够防护 straight-line 预测执行漏洞了!

关注了就能看到更多这么棒的文章哦~

Blocking straight-line speculation — eventually

By Jonathan Corbet
December 9, 2021
DeepL assisted translation
https://lwn.net/Articles/877845/

Spectre 类型的漏洞,之所以被专门起了一个名字,是因为人们认为这类问题会困扰着我们很长时间。随着 Meltdown 和 Spectre 披露日期的四周年到来,我们不得不服气,确实需要这么一个名字。最近的一个 Spectre 变种被称为 "straight-line speculation",是在 2020 年 6 月首次披露的,但其 fix 仍在努力开发中,希望能想办法进入编译器和内核。

straight-line speculation 与其他 Spectre 漏洞有些不同。回顾一下,经典的 Spectre 问题通常是影响下面这类代码:

if (offset < obj->array_length)
   do_something_with(obj->array[offset]);

从表面上看,这段代码是很安全的:只会在给定的 offsett 符合范围要求的情况下才会去解析并使用 obj->array 中 offset 的位置。但是,运行这段代码的 CPU 当时如果无法从 cache 中获取到 obj->array_length,那么就需要等待从内存中获取到这个值。此时 CPU 并不会仅仅等待而什么都不做,它实际上会猜测一下比较的结果,然后根据推测的结果来继续执行。但是它可能会猜错,从而采用了一个越界的 offset 来访问 obj->array。但是这不应该是个问题,因为一旦 array_length 被 CPU 获取到了,那么 CPU 就必定会发现这里它猜错了,然后它会相应地把这部分基于错误猜测的工作丢弃掉。

这里的问题是这种猜测性地执行工作会在系统中其他地方(最常见的是 memory cache)留下痕迹,可以被利用来把攻击者本来无法访问到的数据暴露出来。在最坏的情况下,Spectre 漏洞可以被用来攻击内核或在同一个物理主机上运行的虚拟机之间进行攻击。这些是真正可行的攻击方式,因此人们采取了许多防护措施希望能挫败这些攻击,尽管需要付出很大的性能损失的代价。

straight-line speculation,最初是在 Arm 的这份白皮书(https://developer.arm.com/support/arm-security-updates/speculative-processor-vulnerability/downloads/straight-line-speculation )中披露的,它的与众不同之处在于它不依赖于错误的 branch 预测。事实上,它根本不需要牵涉到 conditional branch (条件分支)。相反,它利用了一些关于 unconditional control-flow 变化的奇怪行为。有很多指令会导致程序计数器(program counter,PC)的变化;在 Arm 上,这包括可以产生 exception (异常)的指令,也包括 unconditional direct branch 以及从函数调用中返回的 RET 指令。

人们总以为 CPU 的 speculative-execution (预测执行)模式在遇到这些指令时能够正确处理(当然应该停止预测),这不应该是什么难事。但是,事实证明,在某些 CPU 上,在某些情况下,CPU 可能会采用推测性地策略来执行紧跟在后面的指令,就像这些特殊指令并不存在一样。也就是继续直冲冲地向下继续执行,这就是 straight-line 的名字的来源。如果攻击者能够在这些指令之后紧接着放一些他希望 CPU 去访问某些内容的代码,那么这部分代码可能就会被预测性地执行,从而在系统的其他地方产生跟以前一样的一些影响。这是一个很难利用的漏洞(目前还不清楚是否有人在现实世界中真正利用了这个漏洞),但它仍然是一个需要 fix 的漏洞。

Arm CPU 中的这个漏洞得到了编号 CVE-2020-13844。GCC 和 LLVM 很快就添加了 patch 来解决这个问题。新的 -mharden-sls flag 可以打开相关的防护措施。令人高兴的是,这个问题相对容易解决,只要在这些 unconditional branch 之后放置一个 barrier 指令就可以解决这个问题。如前所述,由于这些跳转是 unconditional 的,因此这些 barrier 操作实际上不会被真正执行,但在 CPU 的 straight-line speculation 执行过程中会看到,这时预测执行机制就会停下来。因此,这个改动并不会真正影响性能,除了最终的可执行文件 size 略有增加之外。

碰巧,不仅仅是 Arm 有这个问题,其他一些 x86 处理器也可能会预测性地执行 RET 指令之下的指令。在这种情况下,解决方案就是在 RET 之后放置一条 INT3 指令来阻止预测执行。INT3 是一条单字节指令,通常被调试器用来设置断点。同样,以这种方式使用时,它实际上不会得到执行。

编译器的改动已经准备好了,可以处理好这个漏洞(尽管它们还没有出现在正式 release 版本中),但是内核还没有更新来使用这些新的编译器。此外,由于很难利用这个漏洞,因此这个问题的解决就显得不那么特别迫切了。

Jian Cai 在 2 月份发布了一组 patch 针对 Arm 增加了保护,但这项工作还没有被合入 mainline。Arm 开发者 Will Deacon 反对这组 patch:

我仍然不理解为什么 Spectre-v1 没能能够得到编译器修改来进行防护,而 SLS 却能得到这种防护?修改编译器将会影响所有运行内核二进制文件的 CPU。换句话说,我认为这里最主要缺少的是一个解释,来说明为什么 SLS 就值得需要让所有的 C 代码都需要受到影响。

这组 patch 此后没有再出现。

在 x86 方面,Peter Zijlstra 最近提供了一组相关 patch。这里也是使用了新的编译器选项(当编译器可以支持时)来插入所需的指令,但是(正如 Deacon 在回应 Arm 补丁时指出的)这只是问题的一部分。内核里有相当多的汇编代码,这些代码都不会被编译器的修改简单解决。因此,Zijlstra 费了很大力气,用一个宏来替代了所有的 RET 指令,当选择正确的配置选项时,这个宏就可以被展开来包括一个额外的 INT3 指令。为了慎重起见,objtool 工具也增加了功能,用来检查 INT3 指令是否被插入到了相应的位置,以此来防止未来有人新写一些代码来引入类似的漏洞。

鉴于自这个漏洞被披露以来已经过去了将近一年半的时间,很明显,没有人觉得必须要尽快解决这个问题。在 straight-line speculation 这方面的防护进展十分缓慢,跟最初 Meltdown 和 Spectre 披露前的争分夺秒状态比起来相差甚远。但有一点我们现在应该已经知道了,那就是攻击者最终会想出一个办法来利用任何漏洞,不管它有多难利用。因此,straight-line speculation 漏洞的保护机制还是很受欢迎的,尽管它来得很晚。

全文完
LWN 文章遵循 CC BY-SA 4.0 许可协议。

欢迎分享、转载及基于现有协议再创作~

长按下面二维码关注,关注 LWN 深度文章以及开源社区的各种新近言论~

efb982baa3fe7c1435e973e00dc12d3b.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值