CVE-2026-43284 — Dirty Frag 深度拆解:当零拷贝遇上原地解密,页缓存成了攻击者的画板

TL;DR :这是 2026 年 5 月 7 日公开披露的 Dirty Frag ​ 漏洞链的主角之一(另一条是 CVE-2026-43500)。一句话定性------**内核网络栈的"高效零拷贝"把自己绊倒了:一个只读的页缓存页,被 splice 偷偷塞进网络包的碎片里,然后 ESP 接收路径以为那是它私有的缓冲区,直接在上面做原地解密写入。结果是:非特权用户可确定性地污染任意文件的页缓存,稳稳拿到 root。**​ 无竞态、无 crash、不碰磁盘。


0 · 先定位:Dirty Frag 到底是什么

Dirty Frag 不是单一 CVE,而是一个漏洞家族名称,覆盖两个独立但同构的 bug:

CVE 子系统 做什么 CVSS
CVE-2026-43284 xfrm/ESP(esp4 + esp6 模块) ESP-in-UDP 的原地解密路径把外部共享页当私有页写入 8.8 Highkernel.org CNA)
CVE-2026-43500 rxrpc(AFS 的 RxRPC 协议) RxRPC 接收路径的 fcrypt原地解密对共享页做 8 字节 STORE 7.8 High(NVD / CISA)

两者的共同祖先缺陷一句话就能说透:

splice()/ MSG_SPLICE_PAGES可以把一个你只有读权限的文件的 page cache page,以"引用"的方式挂到内核网络包(sk_buff.frags[])里;下游的消费代码(ESP 解密 / RxRPC 解密)没有检查"这个页是不是别人也在用",直接原地写入 → 你改了只读文件的 RAM 副本。

这个 bug class 和 Dirty Pipe(CVE-2022-0847)Copy Fail(CVE-2026-31431) ​ 是一脉相承的------都是**"零拷贝的引用语义 + 下游的 in-place 写假设"**撞在一起的结果。


1 · 漏洞核心:SKBFL_SHARED_FRAG 的缺席

1.1 正常情况下的保护机制:SKBFL_SHARED_FRAG + skb_cow_data()

Linux 网络栈里,sk_buff(简称 skb)的非线性数据可以存在 skb_shinfo(skb)->frags[]数组里,每一项是一个 skb_frag_t,指向一个 struct page *(就是页缓存页或别的什么页)。

当一个 skb 的 frag 引用的 page 不是内核独家拥有的(比如来自 pipe 的页、来自文件页缓存的页),正确做法是:

  1. 标记 SKBFL_SHARED_FRAG标志位​ → 告诉后续路径"这个 skb 的数据不是私有的"

  2. 任何需要修改数据的路径看到这个 flag → skb_cow_data()做一个 COW(Copy-On-Write)私有拷贝​ → 再写私有副本

TCP 路径(skb_splice_from_iter()之后)正确地做了第一步 :设置了 SKBFL_SHARED_FRAG

1.2 问题出在哪:IPv4/IPv6 的 UDP 拼接路径漏设了 flag

关键句子就在官方修复描述里,也是最精辟的一句:

TCP marks such skbs with SKBFL_SHARED_FRAGafter skb_splice_from_iter(), so later paths that may modify packet data can first make a private copy. The IPv4/IPv6 datagram append paths did not set this flag when splicing pages into UDP skbs.

翻译成人话:

步骤 正常期望 实际情况
你用 splice()把一个文件(比如 /usr/bin/su的某个页)喂到 socket 内核把该页的引用挂进 frags[],**同时标 SKBFL_SHARED_FRAG**​ IPv4/IPv6 datagram 路径忘了标
后续 ESP 接收处理看到这个 skb 看到 shared flag → skb_cow_data()→ 私有拷贝 → 安全 没看到 flag → 以为 skb 是 uncloned 私有非线性 skb → 走 no-COW fast path
ESP 原地解密 写在私有拷贝上,不影响原始页 直接写在原始 page cache page 上​ 💀

结果:/usr/bin/su的页缓存在内存里被覆写,但磁盘上的 /usr/bin/su完好无损------传统文件完整性监控完全看不见。


2 · 攻击链全景:从零到 root 的逻辑链条

2.1 攻击者需要什么 precondition?

条件 说明
本地低权限用户 shell 不是远程直接打,但 foothold 易得(Web RCE、SSH、CI runner、容器内执行等)
内核版本 ≥ 4.11(~2017)且未打补丁 几乎所有 2017--2026.5 之间的内核
esp4/esp6 模块可用(CVE-2026-43284 路径) 多数发行版默认编译进内核或可作模块加载;利用时需要 CAP_NET_ADMIN→ 通常通过 `unshare(CLONE_NEWUSER
或者 rxrpc 模块可用(CVE-2026-43500 路径) RxRPC 路径不需要用户命名空间创建,纯普通用户权限即可 → 这是它在 Ubuntu 等加固系统上也通的key

2.2 两条利用路线(你通常选更容易的那条)

复制代码
路线 A:CVE-2026-43284(ESP 路径)
  1. 普通用户 → unshare(CLONE_NEWUSER|CLONE_NEWNET) 拿到伪 CAP_NET_ADMIN
  2. 创建 XFRM SA(IPsec 转换状态),注册 ESP 处理
  3. 用 splice()/vmsplice() 把 /usr/bin/su 的页缓存页引用喂入 UDP socket
  4. 触发 ESP-in-UDP 接收 → 原地解密写入 su 的页缓存
  5. 覆写 su 的前 N 字节为 shellcode stub(setuid(0)+execve)
  6. 执行 /usr/bin/su → 以 root 身份跑你的代码 → 🎉

路线 B:CVE-2026-43500(RxRPC 路径,更优雅)
  1. 不需要用户命名空间
  2. 用 RxRPC socket + splice 把 /etc/passwd 的页缓存页挂进去
  3. 原地解密路径对其做 8-byte STORE × 3
  4. 把 root 行的 password 字段清空
  5. su -  → 空密码直接拿 root[2,12](@ref)

PoC 已在 GitHub 公开(V4bel/dirtyfrag),且有多个安全厂商复现确认稳定性。


3 · 为什么这个漏洞格外危险------跟 Dirty Pipe / Copy Fail 放一起看

Bug 年份 污染载体 写入粒度 竞态? 可见性(磁盘)
Dirty COW​ (CVE-2016-5195) 2016 mmap + write fault 页级 ✅ 竞态 需要 sync 才落盘
Dirty Pipe​ (CVE-2022-0847) 2022 pipe+ splice()+ 页标志 任意偏移 4KB 内 ❌ 确定 仅 RAM
Copy Fail​ (CVE-2026-31431) 2026.04 AF_ALG + splice()→ crypto SGL 4 字节 / 轮 ❌ 确定 仅 RAM
Dirty Frag​ (CVE-2026-43284/500) 2026.05 sk_buff.frags[]+ ESP/RxRPC 原地解密 4B(ESP) / 8B(RxRPC) ❌ 确定 仅 RAM,不改变磁盘哈希

核心规律很清楚:Linux 的页缓存共享语义 + 零拷贝引用传递 + "我拥有这个 buffer"的假设这三者的交集,是过去 10 年里最高产的 LPE 温床之一。

Dirty Frag 的特别之处:

  • 确定性:不靠 timing,不靠 CPU pinning,不靠 brute force

  • 安静 :不改磁盘 → sha256sum /usr/bin/su看起来完全正常

  • 双入口:ESP 路径 + RxRPC 路径互为备份------一个被堵还有另一个

  • 跨容器 :页缓存是宿主全局共享的,容器内一样能污染宿主机 su的缓存


4 · 受影响范围速判

内核版本维度

范围 状态
< 4.11 不受影响(esp4/esp6 的 splice 路径那时还不存在)
4.11 ≤ kernel < 修复版本 ⚠️ 受影响
修复阈值举例 5.10.206+、5.15.206+、6.1.172+、6.6.138+、6.12.87+、6.18.28+、≥ 7.0.5、≥ 7.1-rc3

一键快查

bash 复制代码
# 1. 内核版本
uname -r
uname -a

# 2. esp4/esp6 是否编译进来了
grep -E "^CONFIG_(INET_ESP|INET6_ESP)=" /boot/config-$(uname -r) 2>/dev/null
# =y 或 =m → 受影响的编译路径存在

# 3. 模块是否已加载
lsmod | grep -E "esp4|esp6|rxrpc"

# 4. 你能否创建用户命名空间(ESP 路径的常用前置)
unshare -Ur -- cat /proc/self/status 2>&1 | head -5
# 能看到 Effective: 0 0 ... 就说明 unprivileged userns 开着

5 · 修复 & 缓解(按优先级)

✅ 第一选择:升级内核(必须重启)

bash 复制代码
# Ubuntu / Debian
sudo apt update && sudo apt full-upgrade
sudo reboot

# RHEL / Alma / Rocky
sudo dnf update kernel
sudo reboot

# 验证新内核起来后
uname -r

Canonical 的公告给出了各版本的 fixed kernel 版本号(18.04/20.04/22.04/24.04 各有对应包版本),阿里云 Linux 也有对应的 ALINUXx-SA 条目。

🛡️ 临时缓解(不能立即重启时用)

核心思路:让 esp4/esp6/rxrpc 不可加载 / 不活动,斩断攻击面:

bash 复制代码
# 方案 A:modprobe 黑名单 + 尝试卸载
sudo sh -c 'printf "install esp4 /bin/false\ninstall esp6 /bin/false\ninstall rxrpc /bin/false\n" \
  > /etc/modprobe.d/dirtyfrag.conf'
sudo rmmod esp4 esp6 rxrpc 2>/dev/null || true

# 顺手清一下可能被污染的页缓存(不能"修复"已污染但能降风险)
sync && echo 3 | sudo tee /proc/sys/vm/drop_caches > /dev/null

⚠️ 业务代价 :如果你这台机器真的跑 IPsec VPN(strongSwan / libreswan 的 kernel-mode ESP),禁用 esp4/esp6 会断 VPN------需要按业务情况评估。

🐳 容器场景额外防线

默认 Docker seccomp 不拦 ​ AF_KEY / XFRM netlink,但部分配置会拦 AF_RXRPC。最稳的做法是在容器 runtime 层加约束,并尽快把宿主机内核升级------因为页缓存是宿主机全局的,容器内的缓解只是缩面,不是根治。


6 · 蓝队检测线索

因为 Dirty Frag 不改磁盘,检测必须靠行为:

信号 采集方式
普通用户频繁调用 socket(AF_NETLINK, ...)+ XFRM msg(XFRM_MSG_NEWSA等) AuditD / eBPF LSM
splice()/ vmsplice()紧跟 sendmsg()/ recvmsg()到奇怪 socket 类型 syscall tracing
非特权用户成功 unshare(CLONE_NEWUSER)+ 随后加载 netdev 相关模块 audit + kaudit
/usr/bin/su执行后产生异常子进程(shell 从 su 出来但 parent 不是正常 login 链) 进程血缘监控
页缓存异常:文件 inode 的 RAM 内容与磁盘不一致(高级检测:用 vmtouch/ eBPF 做抽查) 内存取证

Microsoft Defender 这边已经发了签名覆盖(Exploit:Linux/DirtyFrag.A/BTrojan:Linux/DirtyFrag.*),Defender for Cloud 也有 posture 检测。


7 · 官方修复到底改了什么(代码层面一句话版)

修复做了两件互补的事:

  1. IPv4/IPv6 datagram 的 splice-to-UDP 路径 :补上缺失的 SKBFL_SHARED_FRAG标记(对齐 TCP 的正确行为)

  2. ESP input 路径 :即使 flag 出现,也 fallback 到 skb_cow_data()做 COW 私有拷贝,绝不对外引用的页原地解密

本质上就是把"这不是我的页"这个事实,从 flag 的缺席态 → 强制显式态,让后续所有写路径正确走 COW。


⚠️ 结语

CVE-2026-43284 是那种教科书级别的"效率换安全"陷阱------splice 零拷贝很快,但不该快的代价是让页缓存的 ownership 变得模糊。从 Dirty Pipe 到 Copy Fail 到 Dirty Frag,同一个主题反复出现:

只要内核把一个"仅可读页缓存页的引用"交给了某个可以做 in-place write 的下游路径,且下游没有 ownership 检查,攻击者就拥有一个 page-cache 级的 write-what-where。

这不是某个开发者马虎,而是整个"零拷贝引用传递"范式的系统性张力------快,就要共享引用;共享引用,就必须付出精确的追踪成本。

仅供合法授权环境研究/防御加固使用。 ​ 在自己没授权的机器上验证这个 exploit = 违法入侵。如果这是你接到的安全工单,最合理的下一步是:拉内核升级窗口 + 先上 modprobe 黑名单兜底

相关推荐
lx188548698961 小时前
Redis大Key阻塞:单线程CPU100%的致命陷阱
数据库·redis·缓存
c_lb72881 小时前
期货量化策略从 Windows 迁到 Linux 服务器:环境注意点
linux·服务器·windows·python
熙芯XiChip1 小时前
Linux SPI从机驱动开发要点
linux
IT策士1 小时前
Redis 从入门到精通:位图、HyperLogLog、GEO
数据库·redis·缓存
hweiyu001 小时前
Linux命令:newgrp
linux·运维·服务器
凡人叶枫1 小时前
Effective C++ 条款15:在资源管理类中提供对原始资源的访问
linux·开发语言·c++·stm32·单片机
c238561 小时前
Vim 高阶实操技巧篇
linux·编辑器·vim
布局呆星1 小时前
Spring Boot + Redis 缓存实战:@Cacheable、序列化踩坑、缓存一致性,一次讲透
spring boot·redis·缓存
Plastic garden2 小时前
Linux下rsync + inotify 实时文件同步方案
linux·运维·服务器