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 黑名单兜底

相关推荐
HLC++11 小时前
Linux的进程间通信
android·linux·服务器
华清远见IT开放实验室13 小时前
实验室建设案例 | 石家庄科技信息职业学院嵌入式实验室——从底层硬件到系统应用,一所应用型高校的嵌入式人才培养这样落地
linux·arm开发·stm32·嵌入式硬件·高校·实验室建设
groundhappy15 小时前
idalib安装和codex ida-mcp配置
linux·开发语言·python
通信小小昕16 小时前
Ubuntu 26.04 中文输入法安装
linux·运维·ubuntu
时空无限17 小时前
vllm 缓存对模型启动时间的影响
缓存·vllm
张小姐的猫17 小时前
【Linux】网络编程 —— HTTP协议(上)
linux·运维·服务器·网络·http·单例模式·策略模式
栩栩云生17 小时前
AI 写代码犯的错,早被写进了错题集
linux·安全·ai编程
imc.1119 小时前
linux基础IO
linux·运维·服务器
BelongPanda20 小时前
Linux Nginx 纯手动 Let‘s Encrypt 泛域名证书配置教程
linux·nginx
酷可达拉斯21 小时前
Linux操作系统-shell编程(0)
linux·运维·服务器·python·云计算