1
Zenbleed是一个在AMD Zen2架构上的指令集漏洞,这个漏洞也是由预测执行产生的。但相对于Spectre漏洞,Zenbleed并不需要时间侧信道,攻击方法也远比Spectre简单。这个漏洞更类似于常规程序中由malloc/free导致的UAF问题。
2
随着对CPU计算性能需求的增长,x86处理器引入了 MMX,SSE,AVX 等SIMD指令,也加入了用于这些指令的专用寄存器 MM,XMM,YMM,ZMM。在Zen2架构中,对这类指令最高支持到AVX2,寄存器最大是256bit的YMM系列寄存器。
(gdb) x/20i __strlen_avx2
...
<__strlen_avx2+9>: vpxor xmm0,xmm0,xmm0
...
<__strlen_avx2+29>: vpcmpeqb ymm1,ymm0,YMMWORD PTR [rdi]
<__strlen_avx2+33>: vpmovmskb eax,ymm1
...
<__strlen_avx2+41>: tzcnt eax,eax
<__strlen_avx2+45>: vzeroupper
<__strlen_avx2+48>: ret
vpxor xmm0,xmm0,xmm0
将清空整个ymm0寄存器(写入XMM寄存器将自动清空YMM的高位)图片来源:https://lock.cmpxchg8b.com/zenbleed.html
第二段vpcmpeqb ymm1, ymm0, [rdi]
将rdi指向的内存32字节与YMM0比较,比较的结果存入YMM1中。相同的字节会被设置成0xFF,不同的字节会被设置成0x00。
图片来源:https://lock.cmpxchg8b.com/zenbleed.html
随后vpmovmskb eax, ymm1
将ymm1中保存的结果转存到eax中,ymm1中每一个不为0x0的字节将设置eax对应的比特位为1
图片来源:https://lock.cmpxchg8b.com/zenbleed.html
最后判断字符串的长度,我们就只需要数出来eax中有多少个前导为0的bit。tzcnt eax, eax
就正好是做这个的。
图片来源:https://lock.cmpxchg8b.com/zenbleed.html
这段代码还执行了vzeroupper
,用于清空所有YMM寄存器的高128bit,同时也可以避免在从VEX模式切换到non-VEX模式带来的性能损失。因此,他出现在了这段代码的末尾。
3
我们看到上面有多个清空YMM高128位的操作,但CPU是怎么完成这个操作的呢?
在CPU中,每个寄存器并非一个独立的存储空间,而是利用 寄存器分配表(Register Allocation Table) 和 寄存器文件(Register File)。寄存器文件类似于一个数组,每一个元素存储着一个寄存器的值,而寄存器分配表会存储寄存器名称和寄存器文件数组下标的关系。
当我们清空某个寄存器时,CPU并不会去清空寄存器文件中实际存储的值,而是设置寄存器分配表中的z-bit, 或者说将寄存器分配表标记为未分配。这个flag可以独立地被设置于YMM的高128位和低128位(也就是XMM)。所以在vzeroupper
执行时,CPU会释放寄存器文件中对应的表项,并将寄存器分配表对应项设置为0。
vzeroupper
,但是后续发现预测错误,这时候该怎么办呢?最简单的办法就是直接将设置的z-bit去掉,让寄存器分配表表项重新映射到原来的寄存器文件表项上。图片来源:https://lock.cmpxchg8b.com/zenbleed.html
UAF triggered!
4
部分AMD Zen2 CPU在从错误投机的vzeroupper
指令回滚状态时,可能会出现上述的错误。受影响的至少包括以下产品:
-
AMD Ryzen 3000 Series Processors
-
AMD Ryzen PRO 3000 Series Processors
-
AMD Ryzen Threadripper 3000 Series Processors
-
AMD Ryzen 4000 Series Processors with Radeon Graphics
-
AMD Ryzen PRO 4000 Series Processors
-
AMD Ryzen 5000 Series Processors with Radeon Graphics
-
AMD Ryzen 7020 Series Processors with Radeon Graphics
-
AMD EPYC “Rome” Processors
首先我们需要触发 XMM寄存器合并优化(XMM Register Merge Optimization) 然后再来个寄存器重命名,最后再整个错误预测的vzeroupper
。只要精细的控制时间窗就能触发这个漏洞。
由于一些基础的操作,比如strlen,memcpy,strcpy都使用了这类simd寄存器进行性能优化,所以我们可以利用这个漏洞有效的监控系统中发生的这些行为,而且无论是发生在虚拟机、沙箱、容器、进程中。
因为同一个寄存器文件是被同一个物理核中的所有寄存器共享的,甚至两个超线程核都是共享的同一个寄存器文件。
5
复现这个问题的方式有很多,我们可以看一个很简单的例子:
vcvtsi2s{s,d} xmm, xmm, r64
vmovdqa ymm, ymm
jcc overzero
vzeroupper
overzero:
nop
cvtsi2sd 是用来触发寄存器合并优化的,它实际做了啥并不重要,任何可以触发寄存器合并优化指令都可以。然后我们用vmovdq触发寄存器重命名,然后用一个条件跳转让cpu预测错误,投机执行vzeroupper
但随后回滚操作,就可以触发这个问题了。
触发后,我们就能直接从ymm寄存器中,读出别的程序可能正在处理的数据。
实际的复现比这个复杂一些,可以后台索要附件查看。最终,原作者实现了可以泄露30kb每核每秒的能力,这个速度足以监控一些密钥和密码信息。
6
AMD已经提交了最新的微码,linux用户更新linux-firmware即可。你的主板厂家也应该会放出含有最新微码的BIOS/UEFI,请及时更新。
如果暂时无法更新,可以修改DE_CFG[9]
来规避,在linux上,使用以下命令即可。
# wrmsr -a 0xc0011029 $(($(rdmsr -c 0xc0011029) | (1<<9)))
但这个会带来性能损失。
7
没有什么好的办法检测和识别此类攻击的存在,因为它不需要任何的权限或特殊系统调用。当然我们也绝对不能通过检查vzeroupper
的调用来判断,它的使用实在是太广泛了。
8
内存管理在哪儿都很难,即使是在芯片中。
9
寄存器文件:https://zh.wikipedia.org/wiki/寄存器堆
寄存器重命名:https://zh.wikipedia.org/wiki/寄存器重命名
XMM寄存器合并优化:https://www.amd.com/en/server-docs/software-optimization-guide-for-amd-epyc-7003-processors-zip-format , section 2.11.5
https://lock.cmpxchg8b.com/zenbleed.html
华为终端安全奖励计划|漏洞奖金翻倍活动强势回归--更高奖金,更多守护
原文始发于微信公众号(华为安全应急响应中心):难以想象的芯片UAF漏洞,Zenbleed漏洞分析
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论