一个针对 AMD navi31 显卡(RX 7900 系列)的 PSP(Platform Security Processor,平台安全处理器)漏洞利用。 很可能也适用于其他相邻的产品系列。
它会关闭 PSP 的固件签名检查,因此显卡将加载它原本会拒绝的 未签名 IP 固件(SMU、SDMA、MEC、IMU、RLC)。想象一下自定义电源管理、频率限制,或者任何其他存在于厂商签名而你未签名的固件中的东西。
不会刷写任何内容。补丁存在于 PSP 内存中,并在热启动期间应用;冷断电重启会将其清除,显卡恢复原厂状态。那次热启动就是“Wake and Break”:显卡醒来,我们说服它立刻变得非常兴奋,并胁迫它废除签名检查。:-)
已在 RX 7900 XTX 上实测。参见状态。
python3 wakebreak.py 25=/path/to/firmware.bin
它会植入补丁、对显卡进行热启动,并将你的镜像作为固件类型 25 提交。如果打印出 accepted,说明 PSP 接受了一个它通常会拒绝的镜像。
需要一些东西来试用吗?ipfw_images.py 会列出你的驱动实际加载的固件,并写出一对测试镜像——一个真实镜像,以及一个在其签名中翻转了一位、因此固件本身逐字节完全相同的副本:
python3 ipfw_images.py # what does this card load?
python3 ipfw_images.py 25 # -> /tmp/fw_25_{ok,bad}.bin
python3 wakebreak.py 25=/tmp/fw_25_bad.bin
Stock 固件会拒绝 fw_25_bad.bin。应用补丁后,它会被接受。
这就是整个演示。
python3 -m venv venv
venv/bin/pip install -r requirements.txt
make verify # are the shipped artifacts intact?
make selftest # offline sanity checks, no card touched
你需要一台 Linux 主机,并且能够通过 tinygrad 的 AMD 驱动(PCIe 或其 USB 桥接)访问该显卡。请参阅 requirements.txt,了解你的主机所需的一个 tinygrad 补丁。
已知有四种 navi31 固件版本,补丁必须与之匹配。配置文件 a 是默认配置,覆盖最常见的一种。如果你有显卡 SPI flash 的转储文件,identify.py 会告诉你:
python3 identify.py FLASH.bin
# -> sos-build c: wakebreak.py --sos-build c
否则直接尝试即可。猜错也无妨: 补丁会检查它即将修改的内容,发现无法识别的内容时便不写入任何内容,显卡正常启动。
python3 wakebreak.py --sos-build c 25=/tmp/fw_25_bad.bin
已在测试过的显卡上确认(RX 7900 XTX,配置文件 a):
| 被篡改的固件,原厂显卡 | 被拒绝 |
| 被篡改的固件,已打补丁 | 被接受 |
| 冷断电重启后 | 再次被拒绝——显卡恢复原厂状态 |
注意:配置文件 b、c 和 d 已构建并离线检查过,但从未在硬件上运行过。如果你有一张匹配配置文件 b、c 或 d 的显卡,请反馈它是否有效!
补丁本身是几百字节的 ARM 汇编,位于 hook/*.S。构建好的二进制块随仓库一起发布,因此你无需交叉编译器即可使用。如果你仍想重新构建它们:
make rebuild # needs arm-none-eabi binutils
make rebuild CROSS=/path/to/arm-none-eabi-
构建过程会拒绝安装任何哈希与在卡上测试过的字节不匹配的内容,因此不同的工具链无法悄悄改变写入你 PSP 的内容。
wakebreak.py the exploit
identify.py which --sos-build does this card need?
ipfw_images.py build a signed/tampered firmware pair to test with
selftest.py offline checks
hook/ the patch: ARM sources and built blobs
firmware/ two stock AMD firmware images the exploit needs to get in
firmware/ 存放的是未经修改、公开发布的 AMD 镜像。它们是旧版本,之所以保留,是因为进入的途径要经过它们。
这里有意不展开说明:请阅读代码。wakebreak.py 约有 600 行带注释的代码,注释解释了其机制、安全检查,以及每一步为何按此顺序排列。TL;DR: 加载两个原厂 AMD 受信任应用程序,诱使其中一个运行一条能够写入 PSP 内存的调用链,将补丁放入引导加载程序的常驻副本中,然后对显卡进行热启动以进入该副本。
MIT,参见 LICENSE。随你怎么用。
本作品在制作过程中大量使用了 LLM 辅助。这并不意味着作者对这里实际发生的事情一无所知。为了走到这一步,经历了 大量 的反驳和手动工作。你可能不喜欢那些粗制滥造的 Python 产物之类的,但你无法反驳这样一个事实:你的 Navi31 显卡现在突然能够加载未签名的固件组件 blob 了。感谢你的关注。