← LeisureLinux 文章索引
LeisureLinux · 微信公众号文章

IPv6 容器逃逸漏洞 CVE-2026-53362 深度分析:一个 fraggap 引发的 skb 堆越界

AI/Agent 阅读原文(微信)↗

Linux 内核 IPv6 协议栈中一个隐藏了四年的账目错误,允许无特权的容器内用户通过精心构造的 UDPv6 报文越界写入 skb_shared_info 结构,实现容器逃逸和 root 提权。

漏洞速览

  • CVE 编号:CVE-2026-53362
  • CVSS 评分:暂未发布(高危预计 7.8+)
  • 影响范围:Linux 内核 v5.19 / v6.0 起的几乎所有主线/发行版内核
  • 引入时间:2022 年 7 月(commit 773ba4fe9104)
  • 利用方式:本地低权限用户(容器内)→ 堆越界写入 → 容器逃逸 + root 提权
  • 修复版本:v7.1.3、v7.2-rc1 及对应稳定分支(2026 年 6 月)
  • 触发条件:UDPv6 socket + MSG_MORE + MSG_SPLICE_PAGES 标志组合

技术背景:skb 与 IPv6 分片的故事

要理解这个漏洞,先要了解内核网络栈中两个核心概念。

skb(socket buffer)

skb 是 Linux 网络栈中一切数据包的基本载体。它是一个内核对象,包含:

┌─────────────────────────────┐ │ sk_buff 元数据 │ ← head, data, tail, end 指针 ├─────────────────────────────┤

  线性数据区域 (linear area)     skb->head ~ skb->end

├─────────────────────────────┤ │ skb_shared_info │ ← frags[] 页散射数组 │ ┌────────────────────────┐ │ │ │ nr_frags, frags[] │ │ │ │ dataref, destructor │ │ │ └────────────────────────┘ │ → 紧跟在 skb->end 之后 └─────────────────────────────┘

skb_shared_info 紧贴在线性数据区 end 指针之后,是一个极其关键的内核结构。一旦写入超过 end,就等于直接覆盖了 skb_shared_info 的字段。

fraggap 机制

IPv6 分片传递时,如果上一个分片的数据在 8 字节对齐时留有空隙(gap),这个空隙不会丢失——会被累积变量fraggap 跟踪,并在下一个 skb 的线性区头部补齐。换句话说,fraggap 是 IPv6 分片中\"跨包结转\"的碎片大小。

漏洞根因:3 行代码的账目错误

漏洞发生在 net/ipv6/ip6_output.c__ip6_append_data() 函数中。

有问题的代码

当内核走 paged-allocation 分支(即数据量大到需要使用 MSG_MORE + NETIF_F_SG + page 散射机制)时,alloclen 和 pagedlen 的计算为:

alloclen = fragheaderlen + transhdrlen;
pagedlen = datalen - transhdrlen;

问题出在哪里?

datalen 本身已经包含了 fraggap(因为 datalen = length + fraggap)。但在 paged 分支中:

  • alloclen(线性区大小)没有算上 fraggap,导致线性区比实际需要的少了 fraggap 字节
  • pagedlen(页散射区大小)多算了 fraggap,因为从 datalen 中只减了 transhdrlen

后果

当内核把 fraggap 字节复制到新 skb 的线性区时:

实际写入: [head ... head + fragheaderlen + fraggap] 分配空间: [head ... head + fragheaderlen] ^^^^^^^^^^^^ 越界写入 skb_shared_info!

简单说:搬了 fraggap 字节的数据,但只给 fraggap 字节少的位置放。 多出来的字节直接写到了 skb->end 之后,覆盖了 skb_shared_info

为什么之前没被利用?

这个漏洞其实早在 2022 年 7 月(commit 773ba4fe9104)就被引入了。但在此后的三年多时间里,copy 变量在 paged 分支中会算出负值-fraggap),而这个负触发早期的 -EINVAL 检查直接返回错误,阻止了数据的实际写入。

转折点出现在 commit ce650a166335(\"udp6: Fix __ip6_append_data()\'s handling of MSG_SPLICE_PAGES\")。这个补丁允许 MSG_SPLICE_PAGEScopy < 0 时继续执行,使得本应被拦下的路径变成了可触发的漏洞。

触发路径:攻击者怎么做?

攻击者只需要在容器内具备基本的网络能力(CAP_NET_RAWnet.ipv6.ping_group_range 配置允许),无需 root 权限

int fd = socket(AF_INET6, SOCK_DGRAM, 0);
// 关键组合:MSG_MORE + MSG_SPLICE_PAGES
// 构造多个 sendmsg 调用触发分片和 fraggap

关键触发条件:

  1. UDPv6 socket(TCPv6 走不同路径)
  2. MSG_MORE 标志——告诉内核还有更多数据要来,暂不发送
  3. MSG_SPLICE_PAGES 标志——允许内核使用 page 散射而非线性复制
  4. 分片触发——数据量超过 MTU,产生多个 skb 和 fraggap

当这些条件满足时,__ip6_append_data() 在 paged 分支上计算出错误的 alloclen,memcpy 写入 skb->end 之后的 skb_shared_info

为什么是容器逃逸?

skb_shared_info 结构包含的关键字段:

struct skb_shared_info {
__u8       __unused;
__u8       meta_len;
__u8       nr_frags;      //  可以被覆盖
__u16      dataref;
struct skb_shared_hwtstamps hwtstamps;
unsigned short   gso_type;
u32          gso_size;
struct page *frags[MAX_SKB_FRAGS];  //  页指针数组
};

越界写入 fraggap 字节(通常 1-7 字节)覆盖的是 nr_fragsdataref 等字段的上半部分。精心构造的 payload 可以:

  1. 篡改 nr_frags 让内核解析出非法数量的页片段
  2. 利用页指针数组 实现任意物理地址读/写
  3. 绕过内核命名空间隔离 访问宿主机内核的 slab 分配器
  4. 完成容器逃逸 获得宿主机 root shell

这本质上是一个典型的堆越界写入 → 结构覆写 → 提权的漏洞链路。

修复补丁分析

修复极其简洁——只改了 3 行代码

// paged 分支
-alloclen = fragheaderlen + transhdrlen;
-pagedlen = datalen - transhdrlen;
+alloclen = fragheaderlen + transhdrlen + fraggap;
+pagedlen = datalen - transhdrlen - fraggap;

加上 fraggap: alloclen 正确计入 fraggap 字节,线性区长度正确。

减去 fraggap: pagedlen 相应减少,避免重复计账。

同时移除了 copy < 0 时的 MSG_SPLICE_PAGES 例外:

-if (copy < 0 && !(flags & MSG_SPLICE_PAGES)) {
+if (copy < 0) {
err = -EINVAL;

现在 paged 分支中的 copy 不会再变成负数,MSG_SPLICE_PAGES 也不再需要特殊豁免。

受影响版本与修复

分支 受影响起始 修复版本 修复 commit
mainline v6.0+ v7.2-rc1 736b380e28d0
7.1.y 7.1 7.1.3 14200d435af9
6.12.y 6.12+ 待确认 46f201f8b4c3
6.6.y 6.6+ 待确认 6374fb9edf72
6.1.y 6.1+ 待确认 65fb14cbebb0

受影响的大部分是 2022 年 7 月之后发布的内核,包括 Ubuntu 22.04+、Debian 12+、Fedora 36+、RHEL 9.x 及各种容器运行时(Docker、Kubernetes Node 等)的底层内核。如果容器运行时使用了与宿主机共享内核的配置(默认情况),容器内普通进程即可触发此漏洞。

缓和措施

如果暂时无法升级内核:

  1. 限制容器内 CAP_NET_RAW——这是最有效的权限收缩,Docker / Kubernetes 默认授予,但非必要应移除
  2. 禁用 IPv6——sysctl -w net.ipv6.conf.all.disable_ipv6=1(仅限不需要 IPv6 的环境)
  3. 使用用户命名空间映射——user.max_user_namespaces=0 或配置 userns 隔离
  4. 启用内核防护——slub_debug=UFPZCONFIG_SLAB_FREELIST_RANDOMCONFIG_RANDOMIZE_KSTACK_OFFSET 等可以增加利用难度

写在最后

CVE-2026-53362 是一个典型的\"4 行代码修了 4 年的 bug\"故事。2022 年一个小小的账目错误,遇到 2025 年一个放宽 MSG_SPLICE_PAGES 检查的 commit,最终在 2026 年变成了一个高危容器逃逸漏洞。再次印证了一个道理:

内核代码中\"看似永远不会被执行到的路径\",总有一天会被人走出来。

三个关键教训:

  1. 数值计算的边界条件必须精确——多 1 字节的偏移量就是安全与沦陷的差别
  2. 放宽安全检查时务必审计关联路径——ce650a166335 的本意是修复 MSG_SPLICE_PAGES 的正常使用,却意外放开了漏洞的扳机
  3. 容器隔离不解决内核漏洞——公用的内核永远是容器的阿喀琉斯之踵

━━━ ━━━ ━━━

参考文献

  1. CVE-2026-53362 - NVD
  2. 修复 commit (主线)——Wongi Lee, Jungwoo Lee
  3. 修复 commit (7.1.y 稳定版)
  4. 修复 commit (6.12.y 稳定版)
  5. 修复 commit (6.6.y 稳定版)
  6. 修复 commit (6.1.y 稳定版)
  7. 引入漏洞的 commit: ipv6: avoid partial copy for zc (773ba4fe9104)——Pavel Begunkov, 2022-07-12
  8. 放宽 MSG_SPLICE_PAGES 检查的 commit: udp6: Fix __ip6_append_data()\'s handling of MSG_SPLICE_PAGES (ce650a166335)

━━━ ━━━ ━━━

*本文完。欢迎关注 LeisureLinux,获取更多深度 Linux 内核与安全技术分析。*

CVE-2026-3071 \"Dirty Frag\":Linux 内核权限提升漏洞深度解析

Copy Fail 内核漏洞已经在各大主流发行版 Ubuntu, Debian 修复,请尽快升级!

隐匿的威胁:论 Linux 内核漏洞的"长寿"现象与企业级补丁防御策略

Bad Epoll 深度拆解:一桩跨越三年、两条机器指令引发的内核血案

libssh2 漏洞深度解读:SSH 库的"重症监护室"时刻

当 Rust 开始吃掉整个 Linux 底层:X11、内核、编译器一起锈化

六年、360 个补丁:Linux 内核终于把 strncpy() 扫地出门

一个字符就能提权到 root?Linux 内核 CVE-2026-23111 深度剖析

本文整理自微信公众号 LeisureLinux 的原创内容(Linux / AI / 安全 硬核技术)。

· 阅读原文(微信公众号)

· 关注公众号 LeisureLinux,第一时间获取技术深度内容。

LeisureLinux 公众号二维码(微信扫一扫关注)