AMD处理器RDRAND16指令永不生成0:Zen 2等架构硬件随机数缺陷波及多代CPU

AMD处理器RDRAND16指令永不生成0:Zen 2等架构硬件随机数缺陷波及多代CPU

2026年5月11日,巴西开发者Jessé在flat assembler汇编论坛发帖报告了一桩怪事:他在用汇编语言写数据可视化程序、调用处理器的RDRAND与RDSEED指令给图表喂数据时,偶然发现AMD处理器在给定数据宽度下根本无法生成数字0,而同一程序在Intel处理器上跑出的0一切正常。这份原本沉寂的帖子在9月22日被多位开发者重新挖出并密集复现,演变成一场跨架构的硬件随机数缺陷排查,相关讨论当天登上Hacker News首页并收获182分。

受影响的是16位形式的RDRAND指令。理论上16位均匀随机数出现0的概率是六万五千五百三十六分之一,长时间采样本应与其他数值大致相当。但Jessé附带的测试程序显示,AMD主机上代表0的那根柱状图始终为零。网友jstanley起初以为自己的Ryzen 5 3600没有问题,因为他用32位结果取余数时0如期出现;改用真正的16位指令形式后,他的处理器同样无法生成0。

失败标志位误置成为最可能的解释

网友0x000xca0ffe给出了目前最有说服力的机制解释:16位RDRAND其实能产生0,但处理器在输出0时错误地把进位标志CF置为0,而按手册规定CF等于0恰恰代表本次生成失败、调用方应当重试。他给出的统计数字相当扎实:十亿次采样中出现15312次CF为0,且这些失败情形返回值全部是0;其余有效结果的分布则完全正常,数值桶的最小值14670、最大值15835,与其他数值的桶值处于同一量级。

论坛用户revolution翻出处理器文档中的等价算法伪代码佐证了这一点:随机数生成器就绪时数据写入目标寄存器并置CF为1,未就绪时目标寄存器被写0并置CF为0。也就是说,返回值为0是失败时的规定动作,但0同时也是合法的随机输出,两者靠CF区分——而AMD这批处理器在输出合法的0时把CF弄错了。

受影响范围横跨Zen 1到Zen 3

最初帖子猜测这只是Zen 2架构的问题,但9月22日的复现结果显示影响面更广。网友Sellyme在Ryzen 5 1600(Zen 1)上跑出了与Jessé的4800HS完全相同的缺陷,说明问题并非Zen 2独有;网友matja在Zen 3架构的EPYC 74F3服务器处理器上同样观察到16位与32位的0缺失。不过新一代处理器似乎已经修复:Sellyme的Ryzen 9 9950X3D(Zen 5)16位RDRAND表现正常,但同一颗处理器暴露了另一个已登记为CVE-2025-62626的缺陷,即16位与32位RDSEED在熵源耗尽时会返回0而不是进入失败状态。网友peri-cl的Zen 4锐龙7840U也无法复现16位RDRAND的问题。

这一缺陷的实际安全影响存在争议。网友CodesInChaos认为事情令人尴尬但实际影响有限,因为硬件随机数通常不会直接使用,而是作为种子喂给密码学安全的伪随机数生成器。也有运维背景的网友表示,他们早在AMD处理器随机数bug频发时期,就在所有Linux服务器的引导参数里加入了关闭CPU作为内核随机源的选项。围绕内核熵池混合的讨论中,多数人认同单个坏源不会污染整体随机性,但知情后予以剔除仍是合理选择。

这并非AMD随机数指令第一次出洋相。jstanley回忆Zen 2刚上市时,曾有过RDRAND始终返回全1导致应用程序启动即退出的bug,最终靠微码更新修复,他戏称当年修好了「永远生成全1」,如今却换成「永不生成全0」。讨论中还被反复提及的还有2008年Debian OpenSSL可预测伪随机数漏洞,以及fail0verflow破解PS3时利用的随机数失误。

截至9月22日,AMD尚未就这一缺陷发表官方声明,也未放出对应微码更新。在官方回应之前,依赖16位硬件随机数的开发者可以改用32位形式再取低16位,社区已验证该变体能以正常概率产生0;而调用RDRAND时正确检查CF标志、失败即重试,本来就是手册要求的标准用法,也是这次缺陷只坑到部分程序的原因。