CVE-2026-99999:Debian 内核里那个能逃出虚拟机的 IPv4 校验和 bug
Debian 安全跟踪页把 CVE-2026-99999 标成 Linux 内核 IPv4 校验和校验缺失,攻击者可从 Guest 逃到 KVM 宿主。bookworm 修在 6.1.190-1,trixie 修在 6.12.113-1。
![]()
图:Debian 安全跟踪页的 CVE-2026-99999 条目,列出 bookworm / trixie 的修复版本(来源:security-tracker.debian.org,截图于 2026-10-19)
Debian 安全跟踪页上,CVE-2026-99999 的条目短得有点反常:一句话描述、一个上游提交、两张版本表。但它背后的东西不小——这是 PwnEscape 那条 Guest 到 Host 的 KVM 逃逸链的入口,而 Debian 的 bookworm 和 trixie 都受影响。
漏洞本体:一个偏移量算错了坐标系

图:PWNAI 的 PwnEscape 研究页面,标题直接写明 Guest-to-Host KVM Escape(来源:pwn.ai/blog/pwnescape,截图于 2026-10-19)
跟踪页引用的上游提交标题是 ipv4: validate checksum_start before completing checksum。翻译成人话:内核在完成 IPv4 校验和之前,没有认真检查“校验和的起点”到底落在哪里。
问题的触发点在 virtio-net 的头转换函数 __virtio_net_hdr_to_skb()。这个函数要把虚拟网卡描述符里的校验和元数据翻译成内核 skb 的字段,其中 csum_start 是一个相对于当前 skb 数据视图的偏移。历史代码只检查了这个偏移“别太靠前”,却没有把它换算成相对于网络头的位置。
当报文里带有额外的链路层结构时,这两个坐标系就不是一回事了。上游的补丁把不等式写成:
transport_offset >= minimum_network_header_length
transport_offset - network_offset >= minimum_network_header_length
这两行看起来差不多,实际上不等价。前者只保证“在当前视图里够靠后”,后者才保证“离网络头足够远”。少了后一个约束,一个精心构造的报文就能让 skb_checksum_help 在计算校验和时写坏网络头——跟踪页的原话是 “corrupt the network header and cause a bunch of mischief”。
“mischief” 这个词用得很轻,但在虚拟化场景里,它能变成从 Guest 写到 Host 的任意内存破坏。
为什么和 Debian 有关

图:AWS 安全公告 2026-137,说明该问题影响 KVM 型 hypervisor(来源:aws.amazon.com,截图于 2026-10-19)
Debian 的内核包是这条链上最常见的落点。跟踪页给的状态很清楚:
| 发行版 | 漏洞版本 | 修复版本 | 公告 |
|---|---|---|---|
| bookworm | 6.1.176-1 | 6.1.190-1 | DLA-4841-1 |
| trixie | 6.12.107-1 | 6.12.113-1 | DSA-6568-1 |
| forky / sid | — | 7.2.11-1 | 随内核更新 |
这里有两个容易踩的坑。
第一,bookworm 走的是 LTS 通道(DLA),不是常规 DSA。很多只盯 debian-security-announce 的人会漏掉 LTS 公告,以为 bookworm 没修。实际上 6.1.190-1 已经进了 bookworm-security。
第二,容器和虚拟机修的不是同一层。容器共享宿主内核,容器里 apt upgrade 升的是用户态,救不了内核;要修的是宿主机。虚拟机里的 Guest 内核也得单独升,因为攻击者是从 Guest 里发报文触发这个 bug 的。
修复动作

图:上游内核提交 6785011f8b16(ipv4: validate checksum_start before completing checksum)(来源:git.kernel.org,截图于 2026-10-19)
Debian 上的标准动作:
sudo apt update
sudo apt full-upgrade
# 确认内核版本已到修复版
uname -r
如果不想全量升级,至少把内核和 linux-libc-dev 一起升:
sudo apt install --only-upgrade linux-image-amd64 linux-headers-amd64
升级后必须重启才生效。用 needrestart 或 uname -r 对比一下当前运行的内核,别只看 dpkg -l 里的版本号——包已经装了、内核还是旧的,是最常见的“以为修了”。
云主机用户还要注意:如果宿主机是云厂商管的,Guest 内核自己升;如果跑的是嵌套虚拟化或者自建 KVM,宿主和 Guest 都要升。AWS 的安全公告 2026-137 提到这个 bug 影响 KVM 型 hypervisor,但普通 EC2 实例不在影响范围内——具体要看公告原文,别只看标题。
顺带澄清一个编号混淆
搜索 “CVE-99999 Debian” 会同时冒出两个东西:
- CVE-2025-99999:HSM 认证绕过,GitHub 上有 PoC 仓库。Debian 跟踪页查不到这个编号,说明它不是 Debian 软件包的问题。
- CVE-2026-99999:本文这个 Linux 内核 IPv4 校验和问题,Debian 有明确条目和修复版本。
CVE 编号相近不代表同一个漏洞,年份差一位就是两件事。判断一个 CVE 是否影响 Debian,最靠谱的入口是 security-tracker.debian.org/tracker/CVE-XXXX-XXXXX,看 “Vulnerable and fixed packages” 那张表,而不是搜索引擎摘要。
为什么两个坐标会错位
把 virtio-net 收包的过程拆开看就清楚了。
Guest 发出的报文在描述符里是“线性缓冲区 + 元数据”。元数据里有 csum_start 和 csum_offset,表示“从哪个字节开始算校验和、结果写到哪”。宿主内核拿到之后,要把它翻译成 skb 的 csum_start,单位是“相对于 skb->data”。
但 skb->data 指向的是当前协议层的数据,不是链路层帧的起点。一个带 VLAN 标签、或者带额外封装头的报文,链路层头和网络层头之间会多出几个字节。这时候“相对于 data”和“相对于网络头”就差了这一段。
旧代码的检查是:
if (skb_transport_offset(skb) < min_header_len)
return -EINVAL;
它只保证“传输层偏移在当前视图里别太靠前”。攻击者构造一个元数据,让这个偏移刚好过检查,但换算到网络头之后实际落到了头部里面。等 skb_checksum_help 去写校验和,写的位置就覆盖了网络头字段。
补丁加的那一行,本质是把检查从“当前视图”改成“网络头视图”:
if (skb_transport_offset(skb) - skb_network_offset(skb) < min_header_len)
return -EINVAL;
一行之差,攻击面从“可以写坏头部”变成“直接拒绝”。
披露与修补的时间线
从公开信息看,这条链的节奏大致是:
- 研究者发现并报告,上游先做防御性加固;
- 补丁进入 7.3-rc 系列,同时回移到稳定分支;
- Debian 跟进,bookworm 走 LTS(DLA-4841-1),trixie 走安全更新(DSA-6568-1);
- 云厂商发安全公告,说明哪些产品受影响。
这个节奏里,最危险的是第 2 到第 3 步之间的窗口:上游补丁公开了,发行版还没发更新。攻击者可以对照补丁反推利用方法,而用户还在等包。这个窗口通常几天到几周,跑关键基础设施的人应该盯上游 commit,而不是只等发行版公告。
自查:你的 Debian 到底修了没
光看 apt list --upgradable 不够,因为内核包可能已经装了但没重启。我一般跑这一组:
# 1. 当前运行的内核
uname -r
# 2. 已安装的内核包
dpkg -l 'linux-image-*' | awk '/^ii/ {print $2, $3}'
# 3. 是否有待重启标记
[ -f /var/run/reboot-required ] && cat /var/run/reboot-required
# 4. 对比修复版本
# bookworm 需要 >= 6.1.190-1
# trixie 需要 >= 6.12.113-1
如果 uname -r 还是旧版本,说明包可能装了但没重启。内核漏洞的修复必须重启才生效,这一步没有捷径。
Agent 沙箱场景的额外动作
如果你用 microVM 跑不可信代码(Firecracker、KVM、Cloud Hypervisor),除了升级宿主内核,还要做三件事:
- 确认 Guest 内核也升级:有些逃逸链需要 Guest 侧配合触发;
- 限制 Guest 的出网能力:PwnEscape 的入口是网络包,能不出网就不出网;
- 在宿主侧加 seccomp/Landlock:即使逃逸成功,也限制后续动作。
这三条不能阻止漏洞,但能把“一次逃逸”从“接管宿主”降级成“被限制的进程”。
容器、云主机、物理机的分工
同一个 CVE,不同部署形态要修的地方不一样:
- 物理机 / 自建 KVM:升宿主内核,重启,检查所有 Guest 是否也需要升;
- 公有云 VM:升 Guest 内核,宿主由云厂商负责,但要看公告确认自己的实例类型是否在影响范围;
- 容器:容器共享宿主内核,容器里升级用户态没用,必须升宿主;
- Serverless / 托管运行时:升级由平台负责,你要做的是确认平台公告和 SLA。
很多人以为“我在容器里,隔离够了”。容器隔离的是进程和文件系统,不是内核。内核漏洞面前,容器和宿主是同一台机器。
我的判断
这个 bug 的技术含量在于“两个坐标系”的细节:补丁作者一开始提的修复也不完整,评审过程中才把嵌套头、IP options、IPv6、不同入口调用者都考虑进去。这类边界条件正是虚拟化攻击面最肥的地方。
对普通 Debian 用户,动作很简单:升级、重启、确认 uname -r。对跑多租户或 Agent 沙箱的人,这件事的提醒更重——microVM 不是绝对边界。你把不可信代码关进 Firecracker,前提是宿主内核没有能被 Guest 打穿的路径。CVE-2026-99999 就是那条路径之一。
补丁已经在 7.3-rc7 合入,Debian 也给了修复版本。剩下的问题是:有多少台机器装完包之后没重启。
最后提醒一句:内核漏洞的修复窗口往往比想象中长,因为重启需要停机窗口、需要排期。如果你的环境跑着多租户或 Agent 沙箱,这个窗口应该按小时算,而不是按周算。攻击者不会等你的维护窗口。把内核更新纳入例行巡检,比出事之后临时排期靠谱得多。毕竟漏洞利用不会给你发会议邀请。把补丁和重启都做成流水线,才配得上“例行”两个字。

评论
…