用电压故障注入解锁矿卡中的 A100:GA100 熔丝漏洞研究
Using voltage glitching to unleash the A100 in my mining card
研究者 lae 称在 GA100 芯片上发现电压故障注入漏洞,可烧写任意熔丝,把 8GB 的 CMP 170HX 矿卡解锁成等效 A100-80G。解锁后可用 SM 约 120-126 个,FP16 FMA 达 85.858 TFLOP/s,高于零售 A100 的 72.488 TFLOP/s,NVLink、PCIe Gen4、MIG 等功能也可解锁。
摘要
我在 GA100 芯片上发现了一个电压故障注入漏洞,允许操作者烧录任意熔丝。利用这个漏洞,我把我的 CMP 170HX 8GB 显卡变成了实际上相当于 A100-80G 的显卡!此外,我解锁的显卡实际上比零售版 A100 快约 1.2 倍,因为所有功能正常的 SM 都被启用了(约 120-126 个,取决于芯片抽奖),而不是 NVIDIA 为所有量产 A100 显卡选择的良率安全的 108 个 SM。最后,CMP 被禁用的功能如 NVLink、PCIe Gen4、NVJPG、NVDEC、MIG 都可以通过这种方法解锁,不过我没有专门测试 NVJPG/NVDEC/MIG。
这是我的“A100-80G”的外观和功能。
GPU 081920 MiBNVIDIA Graphics Device00000000:81:00.00x20C210DE
GPU 181920 MiBNVIDIA Graphics Device00000000:C1:00.00x20C210DE
GPU 0NV12GPU 1CPU 亲和性 0–127 · NUMA 0
Full nvidia-smi output$ nvidia-smi --query-gpu=index,pci.bus_id,pci.device_id,name,memory.total; nvidia-smi topo -m
index, pci.bus_id, pci.device_id, name, memory.total [MiB]
0, 00000000:81:00.0, 0x20C210DE, NVIDIA Graphics Device, 81920 MiB
1, 00000000:C1:00.0, 0x20C210DE, NVIDIA Graphics Device, 81920 MiB
GPU0 GPU1 CPU Affinity NUMA Affinity GPU NUMA ID
GPU0 X NV12 0-127 0 N/A
GPU1 NV12 X 0-127 0 N/AFP16 FMA 吞吐量TFLOP/s
零售版 A100
1.00×
硬件解锁的 CMP 170HX
1.18× 零售版 A100
Retail A100 72.488 TFLOP/s; hardware-unlocked CMP 170HX 85.858 TFLOP/s from the raw OpenCL output below.Full OpenCL output.-----------------------------------------------------------------------------.
|----------------.------------------------------------------------------------|
| Device ID 0 | NVIDIA Graphics Device |
| Device ID 1 | NVIDIA Graphics Device |
|----------------'------------------------------------------------------------|
|----------------.------------------------------------------------------------|
| Device ID | 0 |
| Device Name | NVIDIA Graphics Device |
| Device Vendor | NVIDIA Corporation |
| Device Driver | 610.43.03 (Linux) |
| OpenCL Version | OpenCL C 3.0 |
| Compute Units | 124 at 1410 MHz (7936 cores, 22.380 TFLOPs/s) |
| Memory, Cache | 81338 MB VRAM, 3472 KB global / 48 KB local |
| Buffer Limits | 20334 MB global, 64 KB constant |
| Max Workgroup | 1024 threads |
|----------------'------------------------------------------------------------|
| Info: OpenCL C code successfully compiled. |
| FP64 Compute (double, fma ) 11.287 TFLOPs/s (1/2 ) |
| FP32 Compute (float , fma ) 22.781 TFLOPs/s ( 1x ) |
| FP16 Compute (half2 , fma ) 85.858 TFLOPs/s ( 4x ) |
| INT64 Compute (long , a*b+c) 2.759 TIOPs/s (1/8 ) |
| INT32 Compute (int , a*b+c) 22.769 TIOPs/s ( 1x ) |
| INT16 Compute (short2, a*b+c) 20.273 TIOPs/s ( 1x ) |
| INT8 Compute (char4 , dp4a ) 81.169 TIOPs/s ( 4x ) |
| Memory Bandwidth ( coalesced read ) 1883.17 GB/s |
| Memory Bandwidth ( coalesced write) 2137.93 GB/s |
| Memory Bandwidth (misaligned read ) 1460.81 GB/s |
| Memory Bandwidth (misaligned write) 250.13 GB/s |
| PCIe Bandwidth (send ) 13.10 GB/s |
| PCIe Bandwidth ( receive ) 11.69 GB/s |
| PCIe Bandwidth ( bidirectional) (Gen3 x16) 11.58 GB/s |
|-----------------------------------------------------------------------------|
'-----------------------------------------------------------------------------'NVIDIA 使用熔丝进行产品细分、安全功能和其他有趣的访问控制功能——关键在于,在 NVIDIA 芯片上烧录熔丝在某些情况下可以授予你更多访问权限,而不是更少。在正确安全的设计中,烧录熔丝应始终导致更严格的状态,因为烧录的熔丝无法以经济可行的方式恢复。NVIDIA 的设计允许通过烧录更多熔丝来放宽限制!
在这篇文章中,我将介绍 GA100 芯片、其熔丝控制器、VFI 的使用以及未来的研究方向。我决定在这里发布一些促成我研究的工作。
致谢
我的工作建立在Jon Pry 先前的研究以及许多其他投入大量时间更好地理解 GA100 芯片的人的工作之上。我是在另一位安全研究员独立发现同一漏洞之后披露我的发现的;我认为将这一信息公开符合公众的最佳利益。这些发现在本文发表之前已披露给 NVIDIA 的产品安全团队。
GA100 版本
GA100 是 NVIDIA 的一款芯片,已用于驱动近 20 种不同的 SKU——A100 是最知名的变体。我不会深入介绍每个 SKU,但我会介绍与我的工作相关的 GA100 表现形式,涵盖 CMP 170HX 和 A100 的不同版本。
制造出的 GA100 芯片有 128 个 SM、12 个 FBP、5 个 NVDEC 单元、一个 PCIe Gen4 x16 控制器,并且根据帧缓冲区大小,附带 4-6 层与芯片共封装的 HBM。NVIDIA 使用 eFuse 进行良率控制和产品细分——未分化的 GA100 根据缺陷测试和制造商需求转变为限制更多的变体。
在产品细分最极端的表现形式之一中,CMP 170HX 是一款以太坊挖矿卡,名义上具有 8 或 10 GB 的应用程序可见帧缓冲区容量,实际上分别附带约 80 和约 40 GB 的板载 HBM!这项工作主要围绕如何完全解锁并使用该容量。先前的工作在通过软件方法解锁 GA100 方面取得了巨大进展;VFI 带我们走完了最后一英里。
| SKU | 开箱状态 | 软件(cmpunlocker) | GA100VFI |
|---|---|---|---|
| CMP 170HX 8GB | |||
| 帧缓冲区 | 8 GB | 64 GB | 64-80 GB1 |
| CMP 170HX 10GB | |||
| 帧缓冲 | 10 GB | 40 GB2 | 40-48 GB |
| 两款 CMP | |||
| SM | 70 | 70 | 120-128 |
| PCIe 代数 | 1 | 2 | 4 |
| NVLink | 否 | 否 | 是3 |
| ECC | 否 | 否 | 是4 |
| 多实例 GPU | 否 | 否 | 是4 |
| NVDEC | 0 | 0 | 54 |
硬件限制
那么,NVIDIA 是如何利用熔丝从同一颗芯片上同时生产出数据中心 A100 和挖矿 CMP 卡的呢?要理解这一点,我们需要仔细看看位于 GA100 上的熔丝控制器。
熔丝控制器是一个包含 16,384 个 eFuse(512 行,每行 32 个)的模块,以及围绕该原始熔丝宏的一堆逻辑。它的职责是执行熔丝读取和编程、保护底层熔丝,并向芯片其余部分提供可用的“选项字”。这些选项字随后决定芯片如何工作以及启用哪些功能。
每个 eFuse 可以处于两种状态之一(熔断=1,未熔断=0),512 行被划分为 4 个区域:
- 常规熔丝(第 0-221 行)。这些很直接;通常单个(成对的)熔丝会映射到一个选项字,例如 OPT_ENABLE_FUSE_PROGRAM(一个决定是否允许进一步熔丝编程的选项字)。常规熔丝具有内置冗余:例如,OPT_ENABLE_FUSE_PROGRAM 由一个 PRI 和一个 RED(主和冗余)熔丝组成,在此例中主实例是第 0 行的熔丝 0,冗余实例是第 1 行的熔丝 0。有些选项字是标量,例如 OPT_X_COORDINATE,它宽 9 位,表面上保存芯片在制造晶圆上的 x 坐标。重要的是,如果常规熔丝被熔断,基本上没有办法持久地将其恢复为未熔断状态(除了后面的 RIR)。
- 无熔丝熔丝(第 222-487 行)。这个有点奇怪。显然 NVIDIA 对意外熔断常规熔丝并毁掉其工程样品感到沮丧,于是想出了一套以类似 JTAG 链的格式来编码有效选项字的系统(见这项专利)。可以把 FF 本质上视为一个脚本,它描述了哪些选项字应该具有什么值。FF 熔丝(请原谅RAS 综合征)涉及我们可以使用 VFI 解锁的大部分功能。这是因为只需写入新的 FF 行就可以轻易清除 FF 选项字!我们稍后会更深入地讨论这一点。目前,你应该知道 NVIDIA 也知道这一点,因为在正常情况下,你被严格禁止执行任何 FF 熔丝熔断。
- IFF 熔丝(第 487-512 行)。这些包含与 FF 格式不同的指令。它们超出了本文的范围,它们主要用于对熔丝控制器选项字进行即时重新编程。它们通常在生产卡中不可访问。
- RIR 熔丝(8 行,每行 32 个熔丝,严格来说不属于 512 行)。这些由熔丝宏的设计方提供(TSMC 数据手册见此处),本质上是第一方设计者预设的“熔丝修复”机制。GA100 上的 RIR 区域可容纳 16 条修复指令,每条指令可覆盖主 512 行中某个已识别熔丝的值。对我们来说不幸的是,具体到 8 GB 的 170HX SKU,16 个 RIR 字中有 15 个全为 1,而第 16 个字编码的是一条无用的修复指令,几乎无法用于任何有价值的解锁。10 GB SKU 的情况则不同,但那是另一天的话题了……
对于基于 VFI 的解锁,有两组非常有趣的熔丝:
- “控制熔丝”。这一术语源自 NVIDIA 的 Tegra 硬件头文件,专门指第 0 行和第 1 行,它们规定了高度安全敏感的选项字的值。
- 无熔丝熔丝(Fuseless fuses),编码了所有决定一块 GA100 是生来就做一张微不足道的矿卡,还是成为 AI 数据中心主力干将的有趣选项字。
在列举一些由 FF 编码的选项字之前,我们需要先更详细地理解 FF 记录格式,然后再讨论控制我们感兴趣特性的晶粒模块。
无熔丝熔丝
每条 FF 行是一个 32 位记录。位 0–4 选择链,位 5 区分 FF 与 IFF(FF 为 0),位 6–15 选择一个 16 位块,位 16–31 提供该块的新值。专利中的 JTAG 链图在这里相当字面化:控制器通过将这些记录重放到链中来构建选项数据。每条链中的固定位置对应各个选项字。
如果两条记录寻址同一条链和同一个块,则后一条记录生效。例如,0x0fe805c1 表示链 1、块 23、数据 0x0fe8。追加该记录可以清除由较早 FF 记录设置的有效位。没有物理熔丝被烧断;新行替换旧的 16 位块。这适用于 FF 支持的选项,不适用于第 0 行和第 1 行中的常规控制熔丝。
现在我们知道了 FF 字是如何编码的,下面列出有趣的选项字及其位置。这些是由一位特别有帮助的研究人员发现的,他交叉比较了不同 GA100 SKU 的 FF 值和有效选项字,以差分方式理解 FF 链/块到选项字的映射,因为目前没有已知的官方映射。
| 命名选项 | 推断的 FF 位置 | 用途 |
|---|---|---|
NV_FUSE_OPT_FBIO_DISABLE |
链 1 位 83–106;块 5–6 | 内存 I/O 地板清扫 |
NV_FUSE_OPT_FBPA_DISABLE |
链 1 位 107–130;块 6–8 | 内存子分区地板清扫 |
NV_FUSE_OPT_GPC_DISABLE |
链 1 位 131–138;块 8 | GPC 地板清扫 |
NV_FUSE_OPT_TPC_GPC0_DISABLE 至 NV_FUSE_OPT_TPC_GPC7_DISABLE |
GPC i 的链 1 位 187+8i 至 194+8i;块 11–15 |
八个 TPC 掩码 |
NV_FUSE_OPT_PES_DISABLE |
链 1 位 251–274;块 15–17 | PES 地板清扫 |
NV_FUSE_OPT_FBP_DISABLE |
链 1 位 307–318;块 19 | 帧缓冲分区地板清扫 |
NV_FUSE_OPT_ROP_L2_DISABLE |
链 1 位 319–342;块 19–21 | ROP/L2 地板清扫 |
NV_FUSE_OPT_NVLINK_DISABLE |
链 1 位 368–370;块 23 | NVLink 禁用掩码 |
NV_FUSE_OPT_DISABLE_GEN3_SPEED |
链 2 块 39;位 1 和位 9 中哪一个尚未确定 | PCIe Gen3 速度限制 |
NV_FUSE_OPT_PCIE_MAGIC_BITS_D[25] |
链 2 块 47 位 3 | Gen4 速度禁用标志 |
NV_FUSE_OPT_PCIE_BOOT_GEN23_DISABLE |
链 2 块 49 位 6 | PCIe 启动策略 |
NV_FUSE_OPT_PCIE_BOOT_GEN3_DISABLE |
链 2 块 49 位 7 | PCIe 启动策略 |
NV_FUSE_OPT_PCIE_DEVIDA |
链 2,位 593–608;块 37–38 | 设备身份 |
NV_FUSE_OPT_PCIE_DEVIDB |
链 2,位 609–624;块 38–39 | 设备身份 |
NV_FUSE_OPT_SYS_PIPE_DISABLE |
链 1,位 372–379;块 23 | 多实例 GPU 启用管道 |
缩写 FBIO/FBPA/FBP/TPC/GPC/PES/ROP 均指微架构元素,请参阅 GA100 白皮书中的这张图,以进一步了解它们之间的相互关系:

FBP 是 NVIDIA 内部对“帧缓冲分区”的称呼,一个 HBM 堆栈对应 2 个 FBP。FBPA 是子分区,一个 FBP 对应 2 个 FBPA。PES/ROP 是 SM 正常工作所必需的模块(看似与图形相关)。
掌握这些知识后,如果我们能写入新的 FF 行,将 _DISABLE 字全部置零,或至少在考虑芯片缺陷的前提下尽可能放宽,会怎样?如果我们观察 _DISABLE 选项如何与其他元素配合使用,很快就会发现这些 _DISABLE 字是我们防止芯片部分区域被“floorSweep”的主要杠杆。在阐明“如果”之后,我将讨论“如何”:电压故障注入的具体应用,以及我们可以用 VFI 攻破的熔丝控制器防护措施。
Floorsweeping
NVIDIA 让这些选项负责设置 floorsweep 信号,这会使某个芯片元素无法访问(并且很可能断电)。根据实验,我认为 floorsweep 线路是在 RTL 中指定的,从熔丝控制器发出,终止于各个功能模块,并控制模块内的某个主电源/时钟域开关。我观察到 floorsweeping 行为与熔丝控制器针对每个功能模块的有效状态字值之间的延迟非常小。
以 FBP floorsweeping 为例。在我的一张 8 GB 卡上,OPT_FBP_DISABLE 为 0x852:FBP 1、4、6 和 11 被屏蔽。单独的 OPT_FBP_DEFECTIVE 掩码为 0x840,覆盖 6 和 11。在我用替换 FF 行将 FF 支持的禁用掩码缩减为 0x840 后,1 和 4 上的额外掩码消失了,但有缺陷的 6 和 11 仍保持禁用。这样,芯片 12 个 FBP 中有 10 个处于有效掩码中。从功能上看,当 OPT_FBP_DISABLE 为 0x852 时拒绝寄存器读写的 FBP 1 和 4,在这次熔丝写入后变得可响应。
尽管可以通过 FF 写入将功能模块“解除 floorsweep”,但这并不足以使该模块完全可供最终应用程序使用——例如,默认帧缓冲几何配置仅使用每个可用 HBM 堆栈的一部分。
为了绕过这一点,我们可以利用本质上是对 cmpunlocker 方法的小修改。通常用于 8 -> 64 GB 解锁的驱动补丁会写入一组特定的功能配置字(FBPA_CFG、SM_SPEED_SELECT 等)。默认值的选择是为了在常见的 170HX 变体上成功,该变体具有 _DISABLE FF 派生选项字,阻止某些功能模块被使用(任何使用它们的尝试都会返回 floorswept 错误)。在解锁 FF 烧录到位后,我们可以将更宽松的字写入配置寄存器,从而在功能上相当于 A100-80G。
实现 FF 烧录
根据我们掌握的信息,似乎很直接:如果可以烧录任意 FF 熔丝,任何 GA100 都可以根据芯片良率和已填充的内存堆栈,完全解锁到其最大能力。但我们如何烧录 FF 熔丝?让我们看看熔丝控制器的熔丝编程功能,以了解更多。
要请求熔断保险丝,必须向熔丝控制器所属的 FUSEADDR、FUSEWDATA 和 FUSECTRL 寄存器写入数据。虽然名义上主机或无特权请求者无法访问这些寄存器,但借助 Canary in the Crypto Mine ROP,打开相应的特权级别掩码轻而易举。因此,许多研究人员曾尝试胁迫熔丝控制器在 FF 区域熔断保险丝。以下是我们的一些共同观察:
- 熔丝控制器内部有一个 FSM,并通过 FUSECTRL_STATE 位指示其当前状态。
- 对于请求的 FUSEWDATA 值中的每一个“热”位,熔丝控制器都会进入一次 WRITE_PROGRAM 状态。这与预期的熔丝编程行为相符。
- 然而,除非清除某个特定的选项字,否则对 FPF 范围(第 96-221 行)之外的熔丝地址的写入实际上不会发生。该区域内的熔丝(据信为“现场可编程熔丝”,用于标记哪些 ucode 版本已运行,以及其他现场相关信息)确实会生效,并且熔丝控制器状态机在 FPF 和非 FPF 区域的行为完全相同。
我所指的那个特定选项字是 OPT_SECURED_BURN_FEATURE_ENABLE(“SBFE”),在所有量产卡上它都被置为 1。当该选项字被清除时,允许在任意地址进行熔丝编程。当它被置位时,只能熔断 FPF 熔丝。迄今为止,还没有人找到任何方法在 SBFE=1 的情况下熔断 FF 熔丝,即使从 HS 上下文操作熔丝控制器也不行。目前尚不清楚“安全熔断”的真正含义,我推测必定存在一种仅靠软件的方式,即使在 SBFE=1 时也能执行非 FPF 熔断,只是我们不知道这里的“安全”这个形容词到底指什么。
注意 PLM、HS、ucode……;随着解释的深入,本节中我使用了一堆 NVIDIA 特有的术语。关于这些术语含义的深入解释,我推荐你参考其他资料,例如 Je Ne Sais Quoi - Falcons over the Horizon。
重要的是,正如人们在限制更宽松的卡上已经发现的那样,在 SBFE=0 的情况下执行 FF 熔断是可能的!而事实证明,达到这一状态正是我们实现 GA100 解锁的方式。经过大量试错,我最终诉诸电压故障注入来诱发这一状态,并且成功做到了。让我们再谈谈电压毛刺。
电压故障注入
关于 VFI 已有诸多论述,深入解释我留给其他资料。简而言之,施加短暂的供电电压低脉冲通常会导致集成电路出现意外行为。我让 GPT-6 Astra 设计了一块基于 STM32G4 的板子,接入 CMP PCB 上的 PWMVID 信号。PWMVID 是 NVIDIA 的电压调节器标准,我的毛刺器拦截 GA100 裸片发出的 PWM 信号,并用其自身的波形替换后馈入 MP2888B VRM 驱动 IC。借助我的装置,我可以诱使显卡自身的 VRM 为我产生定时毛刺,这比基于 MOSFET 的方案更简单,并且比试图直接驱动 PMBus 能实现更快的毛刺注入。
故障注入器需要与 PCB 建立两处连接,最好使用漆包线/磁线完成。一根线接入 NVVDD 用于电压检测,另一根线接入 PWMVID 信号。故障注入器要正常工作,唯一另外需要的步骤是移除一个 0402 0 欧姆电阻,这会断开 GA100 输出 PWM 引脚与 VRM IC 之间的连接。通过追踪 MP2888B 的引脚定义,特别是其 PWMVID 和 VOSEN 引脚,找到接入点的位置并不困难(MP2888B 与其公开的兄弟芯片 MP2888A 共享封装)。紧邻 MP2888B 的测试点使得 PWMVID 接入点的安装相对容易。
完成该接入后,一次故障注入尝试包含以下序列:
- 移除显卡电源
- 施加显卡电源
- 一旦 NVVDD 越过阈值,立即启动定时器(“故障定时器”)
- 按照故障定时器对齐,发出 PWMVID 信号以执行预设的电压波形
- 观察显卡行为,根据需要从步骤 1 重复
我的装置通过简单的 ACPI S0 -> S3 -> S0 转换实现步骤 1/2,在现代桌面平台上只需几秒钟即可完成。更具侵入性的修改或昂贵的设备可能获得更好的实验速率,但根据我的经验,使用后文描述的方法,这套装置足以在 1 小时到 48 小时的故障注入时间内解锁显卡。
对于 NVVDD 阈值,Astra 编写的固件使用 STM32 比较器检测 NVVDD 何时越过 225mV,随后一个紧凑的 DMA 循环在 PWMVID 引脚上驱动所需的占空比。S0 之后,主机检查显卡状态并决定下一步操作;如果涉及另一次故障注入,将通过 USB 向故障注入板发送故障模式命令。然后主机通过 RTC 定时器触发 S3,在约 3 秒后唤醒(根据经验得出的周期,可获得不错的稳定性)。
有时主机无法返回 S0,我通过将记录和故障注入活动准备工作下放到一块 SBC(Radxa Cubie A5E)来解决这个问题,该 SBC 还可以在故障目标主机无响应时通过 GPIO 驱动主板电源/复位按钮引脚。
更多细节分享在 GA100VFI 仓库 中,如果你感兴趣的话。现在,让我们看看可以通过 VFI 触发的各种有趣状态,以及我们烧录 FF 行所需的特定故障状态。为了帮助阐明每种故障状态之间的差异,我构建了一个关于保险丝控制器在施加电压时如何启动的经验模型。请注意,在没有实现保险丝控制器的 RTL 的情况下,我们只有猜测。以下是假设的启动阶段:
- 按保险丝宏的要求感测 RIR
- 感测(从保险丝宏到读出寄存器)控制行
- 将控制行锁存为控制行派生的选项字
- 感测剩余行
- 将常规保险丝值锁存到其选项字中
- 解析 FF 链
- 将 FF 链值锁存到其选项字中
这些假设阶段基于我实际能从芯片上读到的内容:控制器状态、CMD_READ 工作时的原始行、已发布的选项字,以及 PRI 环是否仍能到达 GPU 的其余部分。通过查看几个关键值,我们可以区分故障注入的结果。重要的是,故障模式和结果非常依赖于具体芯片,因此请将这些示例波形和响应仅视为示例。让我们看看 3 种有趣的故障状态。
1. 所有保险丝感测为零
命令 PWMVID 占空比 · 59.58% / 0.8333%预期 NVVDD · 模拟
t=0 之后的毫秒数;左侧空白省略了 0–200 毫秒
某些故障会使几乎所有已发布的选项字读取为零。在一个捕获到的状态中,672 个命名选项读取中有 669 个为零;其余三个是错误响应。控制器的 CRC 状态为 0x00(尚未解析),PCIe ID 读取为 2080(基础 GA100 PCIe 产品 ID,不对应任何真实零售产品),并且 GPU 的 PRI 环被保持在复位状态。
此状态与熔丝控制器的灾难性故障相符。该卡启动后基本不可用,因为几乎所有启动功能都被全零状态破坏。然而有趣的是,该卡原生以 PCIe Gen4 速率训练!一些略有变化的变体可能展示部分熔丝成功锁存,或包含乱码值而非全零。我未能将其中任何状态推进到 FF 烧录;在几乎所有状态中,熔丝控制器都不可达或功能失常。
2. RIR 读取被破坏
指令 PWMVID 占空比 · 59.58% / 0.8333%预期 NVVDD · 模拟
t=0 之后的毫秒数;左侧空白省略了 0–977 毫秒
读取 CMP 170HX 8GB 上的 RIR 数据揭示了其确切效果:15 条 noop 修复指令,以及一条写入,该写入改变了第 18 行中某个熔丝的值,我们可以监控其选项字。此外,由于 RIR 感测由熔丝宏内部消耗,而非直接由熔丝控制器消耗,我们可以通过尝试读取原始行来观察被破坏的 RIR 锁存——观察到的位翻转在翻转的选项字以及原始熔丝行中保持一致。这为研究芯片启动设定了一个有趣的时间检查点(RIR 感测必须先于其他熔丝感测发生),但本身并不是有用的故障。
3. 金发姑娘的故障
指令 PWMVID 占空比 · 59.58% / 0.8333%预期 NVVDD · 模拟
t=0 之后的毫秒数;左侧空白省略了 0–978 毫秒
我第一张卡上成功的三脉冲状态似乎恰好破坏了基于 row0/1 的选项字,同时保持其他熔丝和选项字完好。在此状态下,所有源自 row0/1 的选项字均为零。初始回读如下所示:
| 信号 | 初始回读 |
|---|---|
| PCI ID 与访问 | 20c2;BAR0 和 PRI 环响应 |
FUSECTRL |
0xe0040000(IDLE) |
CRC_STATUS |
0x55(两半均无错误解析) |
DISABLE_SW_OVERRIDE |
0 |
OPT_SECURED_BURN_FEATURE_ENABLE |
0 |
ENABLE_FUSE_PROGRAM |
0 |
| FUSECTRL/FUSEOPT 权限掩码 | 两者均为 0xffffffff |
| 原始行 0 和 1 | 两者仍为 0x53557c3d,与故障前相比未改变 |
在此阶段,我们仍无法发出 FF 写入,因为 ENABLE_FUSE_PROGRAM=0。老实说,我不确定 ENABLE_FUSE_PROGRAM 为什么会为零,鉴于它在零售板上为 1,所以这在我看来几乎像是一种实现故障检测金丝雀的方式(或者至少这样做会很优雅)。
熔丝感测一次一行进行,所有 32 个熔丝用一条线供电进行感测,这意味着攻击者要让单个熔丝看起来被清除或置位要困难得多。因此,包含一个“金丝雀”熔丝是合理的,当它被清除时禁用安全关键功能(如熔丝烧录),因为通常攻击者最多只能在行粒度上操纵熔丝感测。所以,当 row0/1 选项字全部显示为已清除时,ENABLE_FUSE_PROGRAM=0 阻止我们烧录任何熔丝。
不过,看看我们在这种状态下有什么:DISABLE_SW_OVERRIDE=0。这个字通常是 1,它会阻止我们将 EN_SW_OVERRIDE 寄存器设为 1,而设为 1 后我们就能“影子化”熔丝控制器所暴露的大多数选项字。这样做涉及写入寄存器 CTRL_OPT_*,对应选项字 OPT_*,进而决定有效值 STATUS_OPT_*。正是这一点让我们能把 SBFE 影子化为 0。但是,尽管我们有 DSOV=0,ENABLE_FUSE_PROGRAM 却是无法影子化的选项字之一,即使 DSOV=0 也不行。所以看起来我们卡住了。
至少我是这么想的,并且在这个状态下撞了一阵子墙。然后我注意到还有一个我尚未尝试发出的熔丝控制器命令:SENSE_CTRL。我一直没有发出它,因为表面上看,所有由 row0/1(控制熔丝)派生的选项字似乎都会匹配它们的熔丝值,这会重置 SBFE、关闭软件选项字影子化,并让我们无法熔丝。令我惊讶的是,当我发出这个命令时,所有由控制熔丝派生的选项都变成了它们的熔丝值,除了 DISABLE_SW_OVERRIDE,它保持为 0!
在 DSOV=0 的情况下,我们可以轻松地将 SBFE 设为 0,ENABLE_FUSE_PROGRAM 为 1 是因为它匹配其熔丝值,然后我们就可以大干一场了!还有一个问题,FUSEWDATA 可能有一个锁定的 PLM,但在 DSOV=0 的情况下,我们只需向 OPT_SECURE_FUSE_WDATA_WR_SECURE 写入 0,将 PLM 设为全 1,从而开放主机访问以进行熔丝。
此时,剩下要做的就是为我们感兴趣的特性计算与 _DEFECTIVE 值匹配的 _DISABLE 字,并发出 FF 烧录。注意,占用的 FF 空间和缺陷位因芯片而异,因此每次烧录都必须针对芯片定制。
最终结果
帧缓冲解锁
在 80 GB 完好的 8 GB 卡上(根据我有限的样本,似乎约占 8 GB 卡的 ~90%),解锁可产生完整的 80 GB 作为可用帧缓冲。多项合成测试(在整个帧缓冲中写入伪随机字并在 L2 失效后读回)以及真实工作负载(如 vLLM 和 SGLand)均完全正常。 如前所述,我的一张卡只有 64 GB 完好。在这种情况下,硬件解锁不会带来帧缓冲优势。
计算解锁
170HX 开箱即用限制为 70 个 SM。实际上,芯片上几乎总是有 >120 个 SM 无缺陷,解锁允许全部使用。这带来了显著的性能提升,与仅软件解锁的 170HX 相比约 1.7 倍,甚至比零售 A100 还高出令人印象深刻的约 1.2 倍!
FP16 FMA 吞吐量 TFLOP/s
软件解锁的 CMP 170HX
0.69× 零售 A100
零售 A100
1.00×
硬件解锁的 CMP 170HX
1.18× 零售 A100
ProjectPhysX OpenCL-Benchmark FP16 half2 FMA: software-unlocked CMP 170HX, 50.129 TFLOP/s; retail A100, 72.488 TFLOP/s; hardware-unlocked CMP 170HX, 85.861 TFLOP/s. Retail A100 is the 1.00 times reference.PCIe 代数
唯一阻止 cmpunlocker 超越 PCIe Gen2 的是 FF 选项字。清除相关位后,Gen3/4 可训练并确认完全正常。结合 PCIe 去耦电容改装,最高可达 PCIe Gen4 x16,与零售 A100 PCIe 版本相当。
NVLink
将 OPT_NVLINK_DISABLE 字清零只是让 NVLink 真正工作所需的修改之一。由于 CMP 170HX PCB 缺少 U11 IC(它将 PCIe 3.3v 连接到 NVLink 桥接引脚),原装板卡无法在连接的 NVLink 桥上启动参考时钟发生器。只需将 U11 封装上的两个引脚短接即可解决此问题,尽管这会移除 U11 提供的任何调节或保护。如果你要桥接由不同电源供电的 GPU,请务必小心,因为除非你在部分 GPU 上不安装 U11,否则这会将 +3.3V 电源轨连接在一起!如果你只在一对板卡中的一块上修补 U11,NVLink 桥接工作正常。
在 NVLink 启用的固件方面,有一个 ROM 检查需要通过额外的主机端命令绕过。我相信你的 clanker 能搞定 ;)
在调查 NVLink 解锁时,我还发现了 NVIDIA 在 GA100 上 NVLink 实现的一些有趣怪癖。我将在后续博客文章中发布更多内容,敬请关注!
未来方向
通过任意熔断,我们主要获得功能解锁。一些安全敏感选项默认未熔断,熔断它们可能带来有趣的立足点。但对我来说更有趣的是更深的故障状态,其中许多默认熔断的安全敏感熔丝被感知为未熔断,从而启用调试 HS 执行等路径,授予对芯片内部前所未有的访问权限。
参考文献
- Jon Pry,A Canary in the Crypto Mine: Defeating Stack Protection in a GPU Secure Coprocessor(2026)。
- Amogh Munikote,cmpunlocker(2026)。
- Otto Bittner 等,The Forgotten Threat of Voltage Glitching: A Case Study on Nvidia Tegra X2 SoCs(2021)。
- NVIDIA,US9230678B2: Integrated circuit having an enhanced fuseless fuse structure(2016)。
- TSMC,TEF07F32X32HD18_PHRM_C180518 electrical fuse datasheet, rev. 120A(2018)。
- hexkyz 和 SciresM,Je Ne Sais Quoi - Falcons over the Horizon(2021)。
- TechPowerUp,NVIDIA GA100 GPU specifications。
- GA100VFI source repository。
脚注
-
据轶事,在我检查的 10 个 CMP 170HX 8 GB 样本中,只有一个出厂时仅有 64 GB 可用,其余的功能性帧缓冲大小均为 80 GB。↩
-
尽管《Canary in the Crypto Mine》论文声称 10 GB SKU 可稳定达到 80 GB,但现实中很少有(如果有的话)卡能够实现这一点,且确凿证据稀缺。仍有可能某些 10 GB SKU 确实出厂时板载 80 GB,但根据社区反馈,这一比例似乎非常低。大多数“不稳定”的 80 GB 解锁可通过 L2 缓存和在真实 40 GB 帧缓冲上的内存别名组合来解释。↩
-
启用 NVLink 进一步需要非常小的硬件修改,因为 170HX PCB 上缺少一个组件,我稍后会详细讨论。↩
来源:Hacker News · blog.kate.land