修复本身只改了一处内存释放方式,麻烦在两件事上:发行版补丁进度不一,以及很多 Go 程序可能从没人决定过要开 MPTCP。
SYN 包可以带 IPv4 选项,比如 Record Route 或 Timestamp。内核先把这些选项存进 request socket,握手完成后,再把同一个指针直接交给新建的子 socket。如果此时另一颗 CPU 正在处理重传的 SYN,它会在 RCU 读临界区里读取这块内存来构造 SYN-ACK,而析构函数用的是普通 kfree(),内存可能当场被释放。
上游修复(提交 e3f33b0a1d89,Eric Dumazet)把 af_inet.c 和 tcp_ipv4.c 两处的 kfree() 换成了 kfree_rcu(),让内存等读者离开后再释放。引入问题的提交可追溯到 2015 年 10 月,CVE 记录的受影响起点是 4.4 内核。一个存在了十一年的问题,最后只改了释放方式。
IPv6 的子 socket 创建路径会复制选项,所以这条重传竞争主要是 IPv4 的问题;请求迁移场景下的 IPv6 问题另行处理。
这个 CVE 是 Anthropic 那篇研究文章里五条攻击链的最后一条,前四条分别涉及 Chrome、Safari、Android 和 Windows 的 QUIC 实现。按 Anthropic 的说法,研究人员只做了初始提示,后面的利用由 Claude 完成:先靠竞争让内核多回传数据、拿到内核地址绕过 KASLR,再借同一漏洞劫持控制流,以 root 执行命令。
有两个数字常被引用:约 48 分钟泄露内核指针,再用约 5 分钟到达命令执行。它们来自受控实验室的单次实验,不是成功率。真正让人不舒服的是另一个细节:竞争失败通常只是握手没完成,机器不一定崩溃,攻击者可以反复试。
网上流传的「已公布利用示例」说法也要打个折扣。据安全厂商 Penligent 的分析,公开内容只是摘要,不是可复用的利用方法,也不能据此认为所有 Linux TCP 监听端口在默认配置下都同样可被利用。内核构建、架构、加固和网络路径都会影响结果。评分的分歧也反映了这一点:内核 CNA 打 9.8,Red Hat 的草稿评分是 8.1。
演示的前提是目标有 MPTCP 监听端口。放在几年前,这个前提会排除绝大多数服务器,但 Go 1.24 的发布说明写明,net.ListenConfig 在支持的系统上默认使用 MPTCP,目前仅限 Linux。也就是说,部署者可能从没选择过 MPTCP,服务却已经在用它监听。
实际是否生效,还要看工具链版本、go.mod 的版本声明和显式指令,不能一概而论。Go 安全团队的态度也很明确:逐个程序关 MPTCP 属于脆弱的缓解措施,升级内核才是正解。Go 默认值是否调整,据 lilting.ch 报道仍在 issue #82717 中讨论。
语言运行时的一个默认值,就这样改变了一批服务的攻击面。这也是这个漏洞比普通内核补丁更难排查的地方:服务器清单上看不出来,得逐个看程序怎么编译的。
上游首个修复版本是 5.10.272、5.15.223、6.1.190、6.6.159、6.12.113、6.18.56、7.2.10。发行版会回移补丁,所以别拿 uname -r 直接比这串数字,要对照各家安全公告的包版本。以下状态截至 10 月底至 11 月初的公开报道,动手前请再查一次:
等补丁期间可以先降低暴露:用 sysctl net.mptcp.enabled 查看开关,用 ss -Mltn 看有没有 MPTCP 监听,不需要就关掉;Go 程序可设 GODEBUG=multipathtcp=0,或在 go.mod 里写 godebug multipathtcp=0;限制入站 TCP、过滤带 IPv4 选项的包也有帮助。这些都只减少暴露,没有修好内存问题。
修复包装完不算完,内核要重启后才生效。CVE 公开已有半个多月,最容易出事的恰恰是那些包已更新、但一直没重启的机器。