从 Linux 网络栈打到 KVM 虚拟机逃逸
来源:pwn.ai — 2026-10-18
📋 概述
Vercel 在 2026 年 8 月 18 日挂出百万美元悬赏,邀请研究者击穿其 Sandbox 的隔离边界——既是网络隔离,也是虚拟机到宿主机的边界。PWN.AI 团队用人类主导、模型辅助的研究框架 Omega-Pwn,三天内找到一个位于 Linux 网络栈的原语:来自客户机的校验和元数据,可以在内核已经校验过 IPv4 头之后再改写它。路径是 Linux 的校验和卸载机制——skb 处于 CHECKSUM_PARTIAL 状态时只记录 csum_start 与 csum_offset,真正的写入被推迟;而这段元数据本质上是在「授权一次对包内存的写入」。历史代码里 ip_do_fragment() 先完成校验和、再取 IPv4 头指针并读取 ihl,于是延迟写入可以覆盖已经解析过的头字节:第一字节从 0x45(IHL=5,头长 20 字节)变成 0x4f(IHL=15,头长 60 字节),版本号仍是 4,但头长解释被改。后续分片按这个「晚到的 IHL」拷贝头,读到超出线性数据的部分,于是把宿主机内存当作 IPv4 选项发出——一次 32 字节的宿主内存泄露,最终扩展为完整的客户机到宿主机逃逸。修复是上游提交 6785011f8b16,在完成校验和之前先校验 csum_start。
🔑 核心要点
- 入口是一个「被推迟的写入」:CHECKSUM_PARTIAL 状态下的 skb 只记 csum_start 与 csum_offset,真正的校验和写入发生在之后
- 问题不在 KVM 而在宿主 Linux 网络栈:客户机能影响这段元数据,就等于获得了对包内存某处写入的授权
- 经典 TOCTOU,但不是多线程竞争:ip_do_fragment() 先 skb_checksum_help() 完成校验和,之后才取 ip_hdr 并读取 ihl
- 改写极小却致命:首字节从 0x45 变 0x4f,版本号仍是 4,头长解释从 20 字节变 60 字节
- 泄露的形状来自分片:按「晚到的 IHL」拷贝头会越过线性数据,把宿主机内存当成 IPv4 选项发出去,起点是 32 字节泄露,终点是完整逃逸
- 修复在上游提交 6785011f8b16:在完成校验和之前就校验 csum_start,要求它不落在 IPv4 头内
💡 金句
客户机能够影响的校验和元数据,不只是描述性信息——它授权了一次对包内存的写入;如果这段元数据来自较低信任的来源,那么它的有效性必须撑过准入与完成之间的每一次操作。
👍 0
👎 0
← 返回 Lobsters 首页