Linux 内核 IPv4 TCP 代码中的释放后使用漏洞
(CVE-2026-98432,CVSS 9.8):
从传入 SYN 中保存的 IPv4 选项可能在另一个 CPU 仍在读取它们以构建 SYNACK 时被释放,
因为两条析构路径使用普通的 kfree() 释放它们,而不是等待 RCU 宽限期。
上游修复为
e3f33b0a1d89
("ipv4: free inet_opt and ireq_opt after an RCU grace period")。
截至 2026-10-29,任何 Ubuntu 系列均未发布修复内核。 Ubuntu 跟踪器上的每个受影响状态都显示为"work in progress"或 直接标记为易受攻击,且页面未列出任何缓解措施。本包即为该缓解措施。
两条竞争路径都会读取 ireq->ireq_opt,即内核从传入 SYN 中保存的 IPv4 选项
(tcp_v4_save_options()):SYNACK 构建过程读取它们,而子套接字销毁可能释放它们,
并且请求套接字迁移(net.ipv4.tcp_migrate_req=1,或
BPF_SK_REUSEPORT_SELECT_OR_MIGRATE 程序)会共享然后释放相同的
选项。当 SYN 不携带 IPv4 选项时,ireq_opt 为 NULL:没有可释放的内容,也没有可读取的内容。
我们在依赖这一点之前阅读了修复提交;两部分都从携带 IPv4 选项的 SYN 开始。
因此,本包安装一条 nftables 规则,丢弃携带 IP 选项的入站 IPv4 TCP SYN, 该规则位于独立的表中,因此绝不会与 Docker、底层系统或发行版的规则发生冲突:
table inet samp_cve_2026_98432 {
chain prerouting {
type filter hook prerouting priority -300; policy accept;
ip hdrlength > 5 tcp flags & (syn | ack) == syn counter drop \
comment "CVE-2026-98432: drop inbound IPv4 SYN carrying IP options"
}
}
发布前已在真实内核上验证:携带选项的 IPv4 SYN 会命中计数器并被丢弃;普通 SYN 则原样通过。TCP 流量几乎从不携带 IP 选项(根据 RFC 7126,多种选项类型通常会被许多网络直接丢弃),因此该规则的实际运行成本几乎为零。
pve 内核,Ubuntu 的页面未覆盖)会报告 unknown:请查阅它们的公告。规则本身可以保护任何 Linux 主机;仅判定表是 Ubuntu 专属的。该规则驻留在内核内存中,不会持久化到磁盘。缓解包不得写入持久化路径(unit、cron),而 nftables include 文件只会在发行版的 nftables 服务启用时加载,而这些环境中该服务并未统一启用。因此:重启后,检测会读取到规则不存在(每条结果行上 rule_live=0、persistent=0),下一次 apply 会将其恢复。重启后重新运行 apply 就是运行模式,结果行从不声称相反的情况。
只读,会在一个私有临时目录中暂存自身并在完成后删除,报告:
uname -r,映射到其软件包版本)与 Ubuntu 各发行版和变体的修复版本进行比对。该机器的发行版尚无修复发布:no_fix。已发布修复内核但未运行:vulnerable,当修复已安装并等待重启时 restart_needed=1(已安装的修复绝不会报告为 fixed)。fixed 并带 workaround: true;一旦运行的内核已修复,则为单纯的 fixed。not_affected,表中未覆盖的发行版和发行版为 unknown。0 表示干净(fixed、not_affected),2 表示暴露或未决(no_fix、vulnerable、unknown:绝不算干净),1 表示运行本身失败,130 表示被中断。syn_options_mitigation/files/samp_common.py 是
samp-common 1.0.4 的逐字节副本
(dpkg、rpm 和 apk 版本比较、结果行、配置加载)。其 sha256 位于
samp.yaml 中,若副本不一致,tests/test_samp_pack.py 会失败。切勿
在此处编辑它;请使用 samp-common 的 scripts/vendor.py 重新引入。samp/v<version>(本次为
samp/v1.0.1),使用硬件支持的密钥签名。基座导入的是签名标签,
而非分支。一个脚本步骤,一行结果。当运行中的内核未修复时,它会加载规则;一旦运行中的内核已修复,它会移除规则及其表。除其部署的脚本、库和配置(在 samp.yaml 的 touches 中声明)外,它不编辑任何文件,因此结果行的备份列表为空。手动移除缓解只需一条命令:
nft delete table inet samp_cve_2026_98432
ansible-playbook -i inventory play.yml # a play that runs the role
python3 syn_options_mitigator.py --config syn_options_config.yaml # detect
sudo python3 syn_options_mitigator.py --config syn_options_config.yaml --apply
当 Ubuntu 发布修复后的内核时,将跟踪器中的版本粘贴到角色默认值中的 syn_options_fixed_versions 里(进行中的版本已作为注释存在其中),并将该变更作为下一个已签名标签发布;随后检测会开始针对这些版本报告 vulnerable/restart_needed,而应用操作会从重启进入修复内核的机器上移除该规则。
python3 -m pytest tests/
单元测试伪造了所有外部命令;契约测试(tests/test_samp_pack.py,属于 samp-common)会依据角色校验清单,从临时目录运行一次真实检测,并确保 apply 入口遵守单结果行和 needrestart 规则。
MIT。参见 LICENSE。
欢迎提交 PR 和改进 -> 请 fork 并提交合并请求。