## 摘要
**Dirty Frag** 是 2026 年 5 月 8 日公开披露的 Linux 内核本地权限提升(LPE)零日漏洞,由韩国安全研究员 **Hyunwoo Kim**(<span class="mention-invalid">@v4bel</span>)发现。该漏洞通过串联两个独立的内核页缓存写入缺陷——**xfrm-ESP Page-Cache Write**(2017 年 1 月引入)和 **RxRPC Page-Cache Write**(2023 年 6 月引入)——实现几乎覆盖所有主流 Linux 发行版的稳定 root 提权。
Dirty Frag 属于 "Dirty" 漏洞家族的最新成员,与 Dirty Pipe(CVE-2022-0847)和 Copy Fail(CVE-2026-31431)共享同一根本攻击面:**利用 splice() 零拷贝机制将页缓存页面注入内核可写路径**。与前代不同的是,Dirty Frag 直接污染 `struct sk_buff` 的 `frag` 成员而非 `struct pipe_buffer`,且是一个**纯逻辑漏洞**——不依赖竞态条件、不 panic、成功率极高。
截至披露时,由于第三方提前打破 embargo,**尚无 CVE 编号**(但奇安信内部追踪为 QVD-2026-24699),**无上游补丁**(ESP 补丁已于 2026-05-07 合并 netdev tree,但 RxRPC 补丁仍未合并),**无发行版修复版本**。
---
## 一、时间线与披露经过
| 日期 | 事件 |
|------|------|
| 2017-01 | 提交 `cac2661c53f3` 引入 xfrm-ESP 漏洞路径 |
| 2023-06 | 提交 `2dc334f1a63a` 引入 RxRPC 漏洞路径 |
| 2026-04-29 | Hyunwoo Kim 向 security@kernel.org 提交 RxRPC 漏洞详情 |
| 2026-04-30 | Hyunwoo Kim 向 security@kernel.org 提交 xfrm-ESP 漏洞详情 + PoC,同日提交 netdev 补丁 |
| 2026-04-30 (+9h) | Kuan-Ting Chen 独立提交 ESP 漏洞报告及 reproducer |
| 2026-05-04 | Kuan-Ting Chen 提交 "shared-frag" 方案补丁 |
| 2026-05-07 | ESP 补丁合并至 netdev tree (commit `f4c50a4034e6`) |
| 2026-05-07 | 提交 linux-distros 邮件列表,约定 5 天 embargo |
| 2026-05-07 | **第三方意外泄露 ESP 详情,embargo 破裂** |
| 2026-05-07 | 经发行版维护者同意,Hyunwoo Kim 公开完整披露文档 |
| 2026-05-08 | PoC 代码(C 语言)公开于 GitHub: `https://github.com/V4bel/dirtyfrag` |
---
## 二、技术深度解析
### 2.1 页缓存(Page Cache)——被低估的内核共享状态
Linux 内核为文件系统维护一个**页缓存**,将磁盘文件内容映射到内存页面中。所有进程共享同一页缓存:当进程 A 读取 `/usr/bin/su` 时,内核将该文件页面载入缓存;进程 B 随后读取同一文件时,直接从缓存获取,无需再次磁盘 I/O。
**关键特性**:页缓存页面在内核视角下是"可写"的(内核有权限修改),但用户空间进程通过 `mmap` 或文件权限获得的是只读映射。正常情况下,内核仅在写文件系统调用(如 `write()`)时才会修改页缓存,并通过脏页回写机制同步到磁盘。
Dirty Frag 的攻击本质:**欺骗内核的非文件系统路径(网络/加密子系统)直接对页缓存执行写操作**,绕过所有权限检查。
### 2.2 splice() 零拷贝机制——攻击者的传送带
`splice()` 系统调用(2006 年引入 Linux 2.6.17)允许在两个文件描述符之间移动数据**而不经过用户空间**,实现零拷贝。其核心机制是**页引用传递**:
```
用户空间 内核空间
| |
| splice(fd_in, | +-------------+
| pipefd[1], |--->| page cache |
| len) | | (file page) |
| | +-------------+
| | |
| | v
| | +-------------+
| | | pipe buffer | (引用同一页)
| | +-------------+
```
当 `splice()` 将文件内容送入管道时,它并非复制数据,而是将页缓存页面的引用插入管道的 `pipe_buffer` 结构。接收方通过 `splice()` 或 `sendfile()` 从管道读取时,这些页引用可以继续传递到其他内核子系统。
**Dirty Pipe(CVE-2022-0847)** 利用了 `copy_page_to_iter_pipe()` 未初始化 `pipe_buffer.flags` 的 bug,导致 `PIPE_BUF_FLAG_CAN_MERGE` 标志残留,后续 `write()` 错误地写入了页缓存。
**Copy Fail(CVE-2026-31431)** 利用了 `AF_ALG` + `splice()` + 2017 年 in-place AEAD 优化的组合:页缓存页面被链入加密操作的**可写 destination scatterlist**,`authencesn` 算法的 4-byte scratch write 直接落入页缓存。
**Dirty Frag** 则是将 splice 页引用传递到 **socket buffer(skb)的 frag 成员**,然后让网络接收路径的 in-place 解密直接修改该页。
### 2.3 xfrm-ESP Page-Cache Write 漏洞路径
**位置**: `net/xfrm/esp_input()` — IPsec/ESP 接收路径
**引入**: commit `cac2661c53f3` (2017-01)
**前提**: 攻击者能创建 user namespace (`unshare(CLONE_NEWUSER | CLONE_NEWNET)`)
#### 漏洞触发条件
1. 攻击者创建一个 UDP socket,启用 `UDP_ENCAP_ESPINUDP`(ESP-in-UDP 封装)
2. 通过 Netlink XFRM 接口配置一个接收方向的 ESP SA(Security Association),使用 AEAD 算法(如 `authencesn`)并设置 `XFRMA_REPLAY_ESN_VAL` replay window
3. 用 `splice()` 将目标只读文件(如 `/usr/bin/su`)的页缓存页面注入一个 pipe
4. 将 pipe 中的页面通过 `splice()` 送入 socket,使 skb 的 `frag` 成员引用该页缓存页面
5. 构造一个自发自收的 ESP-in-UDP 数据包:内核的 `esp_input()` 进入解密路径
#### 为什么能绕过 `skb_cow_data()`
正常接收路径中,如果 skb 是非线性的(携带 frag page),`skb_cow_data()` 会为后续操作分配新的线性缓冲区。但 `esp_input()` 中有一段特殊逻辑:
```c
if (!skb->data_len) { // 没有 paged data
// ... 走线性路径
} else {
// 非线性路径
if (!skb->frag_list) { // 没有 frag list
// BUG: 缺少 skb_cow_data() 检查!
goto do_in_place_crypto;
}
}
```
当 skb 只有一个 `frag` 页面(来自 splice 的页缓存引用)而没有 `frag_list` 时,代码**跳过**了 copy-on-write 隔离步骤,直接进入 in-place AEAD 解密。
#### 4-byte 精准写入
`authencesn` 算法在解密时会将 `seqno_lo`(4 bytes)写入 `assoclen + cryptlen` 偏移处。攻击者通过精心构造的 `XFRMA_REPLAY_ESN_VAL` netlink 属性,可以**精确控制写入位置(文件偏移)和写入值(4 bytes)**。虽然 HMAC 验证最终失败(返回 `-EBADMSG`),但页缓存的写入已经持久化。
#### Ubuntu 的限制
Ubuntu 默认启用 AppArmor 策略阻止非特权用户创建 user namespace,因此 xfrm-ESP 路径在 Ubuntu 上被阻断。
### 2.4 RxRPC Page-Cache Write 漏洞路径
**位置**: `net/rxrpc/rxkad_verify_packet_1()` — RxRPC/rxkad 子系统
**引入**: commit `2dc334f1a63a` (2023-06)
**前提**: **无需 namespace 创建权限**,但需 `rxrpc.ko` 模块存在
#### 攻击流程
1. 攻击者注册一个 rxrpc session key(`add_key("rxrpc", ...)`)——**完全无特权操作**
2. 用同样的 `splice()` 技巧将目标文件页缓存注入 skb frag
3. 构造一个 RxRPC 数据包,触发 `rxkad_verify_packet_1()` 的单块 `pcbc(fcrypt)` 解密
4. `skb_to_sgvec()` 将 splice 页直接转换为 scatterlist,攻击者页面成为 src 和 dst
5. 内核执行 8-byte in-place 解密,直接修改页缓存
#### 8-byte 写入与暴力破解
攻击者**无法控制写入值**——写入值是 `fcrypt_decrypt(C, K)`,其中 `C` 是原始密文,`K` 是 session key。但攻击者可以自由选择 `K`!因此攻击者可以在用户空间**穷举 session key**,直到解密结果产生期望的明文(例如将 `/etc/passwd` 第一行的密码字段置空,实现 PAM `nullok` 认证绕过)。
#### 发行版差异
- **Ubuntu**: `rxrpc.ko` 默认构建并自动加载,且无需 namespace → RxRPC 路径完全可用
- **RHEL 10.1**: 默认**不携带** `rxrpc.ko` → 攻击面不存在
### 2.5 链条的互补性
| 特性 | xfrm-ESP | RxRPC |
|------|----------|-------|
| 写入宽度 | 4 bytes | 8 bytes |
| 写入控制 | 完全控制(值+偏移) | 值可控但需暴力破解 |
| 权限要求 | 需 user namespace | 无需 namespace |
| Ubuntu 可用性 | AppArmor 阻断 | 默认可用 |
| RHEL 可用性 | 默认可用 | 无 rxrpc.ko |
两个漏洞**互为补充**:在允许 namespace 的环境中 ESP 路径可用,在 Ubuntu 等禁止 namespace 的环境中 RxRPC 路径接管。链条覆盖几乎所有主流发行版。
---
## 三、攻击面转移:旧补丁 vs 新攻击面
### 3.1 Dirty Pipe 的补丁
2022 年的 Dirty Pipe 补丁(`copy_page_to_iter_pipe()` 中增加 `buf->flags = 0`)非常简单直接——修复了 `PIPE_BUF_FLAG_CAN_MERGE` 标志的残留问题。但这条补丁只堵住了**管道缓冲区**这一特定路径。
### 3.2 Copy Fail 的补丁
2026 年 4 月的 Copy Fail 补丁(commit `a664bf3d603d`)回退了 2017 年的 in-place 优化,强制 `algif_aead` 执行 out-of-place 操作,分离 src/dst scatterlist。这堵住了 **AF_ALG → 页缓存** 的路径。
**但攻击面转移发生了**:防御者修补了 AF_ALG 路径,研究者将视线转向其他同样使用 `splice()` + in-place crypto 的内核子系统——网络协议栈中的 ESP 和 RxRPC。
### 3.3 Dirty Frag 暴露的深层问题
Dirty Frag 揭示了一个系统性漏洞类(vulnerability class):**任何使用 splice() 传递页缓存页面,并在后续执行 in-place 写操作的内核路径,都可能成为攻击面**。
当前已知的三个子系统都中招了:
- `struct pipe_buffer` → Dirty Pipe
- `AF_ALG scatterlist` → Copy Fail
- `struct sk_buff.frag` → Dirty Frag
问题本质:**splice() 的设计假设是"只读传递",但接收方子系统内部执行 in-place 操作时违反了这一假设**。内核缺乏统一的机制来标记"此页面来自页缓存,禁止 in-place 写"。
---
## 四、家族遗传病:从 Dirty Pipe 到 Dirty Frag
### 4.1 共同祖先
所有 "Dirty" 漏洞共享一个技术祖先:**利用 splice() 的页引用传递能力,将只读文件的页缓存页面暴露给内核的可写操作路径**。
| 漏洞 | CVE | 年份 | 攻击目标 | 写入子系统 | 竞态条件 |
|------|-----|------|----------|-----------|----------|
| Dirty COW | CVE-2016-5195 | 2016 | 私有映射内存 | COW 路径 | 是 |
| Dirty Pipe | CVE-2022-0847 | 2022 | 页缓存 | pipe buffer | 部分 |
| Copy Fail | CVE-2026-31431 | 2026.04 | 页缓存 | AF_ALG scatterlist | **否** |
| Dirty Frag | 暂无 (QVD-2026-24699) | 2026.05 | 页缓存 | skb frag | **否** |
### 4.2 设计层面的遗传缺陷
1. **splice() 的过度信任**:splice() 传递页引用时未标记页面来源(来自匿名内存 vs 页缓存 vs pipe),接收方无法判断是否应该 copy-on-write
2. **in-place 优化的泛滥**:内核多个子系统(加密、网络、管道)都偏好 in-place 操作以节省内存带宽,但没有统一检查"页面所有权"
3. **page cache 的全局共享性**:页缓存属于整个系统,任何对它的修改都会影响所有读取者——这使得跨容器攻击成为可能
4. **权限检查集中于文件系统层**:内核在设计时假设"写页缓存 = 文件系统写操作",但网络/加密子系统的写操作绕过了这层检查
### 4.3 AI 审计的新角色
Copy Fail 由 Theori 公司的 **Xint Code** AI 平台在大约 1 小时内通过扫描 Linux 内核加密子系统发现。这标志着一个新趋势:**AI 辅助代码审计正在加速发现 splice() + in-place 组合中的类似缺陷**。Dirty Frag 的出现可能不是终点——其他同样模式的内核路径(如更多网络协议、更多加密接口)可能仍在等待被发现。
---
## 五、影响范围详细评估
### 5.1 确认受影响的发行版/内核
| 发行版 | 内核版本 | 状态 |
|--------|----------|------|
| Ubuntu 24.04.4 | 6.17.0-23-generic | 已确认,RxRPC 默认可用 |
| Ubuntu 26.04 | — | 推测受影响 |
| RHEL 10.1 | 6.12.0-124.49.1.el10_1.x86_64 | 已确认,ESP 可用 |
| Fedora 44 | 6.19.14-300.fc44.x86_64 | 已确认 |
| openSUSE Tumbleweed | 7.0.2-1-default | 已确认 |
| CentOS Stream 10 | 6.12.0-224.el10.x86_64 | 已确认 |
| AlmaLinux 10 | 6.12.0-124.52.3.el10_1.x86_64 | 已确认 |
| Debian 13 (Trixie) | 推测 6.x | 推测受影响 |
| Arch Linux | 滚动更新(推测 6.x) | 推测受影响 |
| WSL2 | 微软内核(基于 upstream) | **已确认受影响** |
| SUSE Linux Enterprise 16 | — | 推测受影响 |
### 5.2 容器与云环境
**跨容器提权**:页缓存在宿主机内核中全局共享。一个容器内的低权限进程可以通过 Dirty Frag 修改宿主机的 setuid 二进制页缓存,随后宿主机或其他容器执行该二进制时触发提权。这等同于**容器逃逸**。
**高风险场景**:
- 多租户 Kubernetes 集群
- 共享 CI/CD runner
- 公共云 Function-as-a-Service / AI sandbox(如果底层共享内核)
- 托管式数据库/缓存服务(如 Redis Cloud, AWS ElastiCache 等使用共享内核的 PaaS)
**免疫场景**:
- 使用 MicroVM(如 Firecracker, gVisor, Cloudflare Workers)的隔离环境——无共享宿主内核
- 已禁用 user namespace 且未加载 rxrpc.ko 的系统
### 5.3 漏洞利用难度
- **无需编译**:PoC 是 C 代码但可直接 `gcc -O0 -o exp exp.c -lutil` 编译
- **无需 root 前提**:仅需本地普通用户权限
- **无需竞态**:确定性逻辑漏洞,首次运行即成功
- **不 panic**:失败不崩溃,可无限重试
- **跨发行版通用**:同一 PoC 在 Ubuntu/RHEL/Fedora/SUSE 上无需修改即可工作
---
## 六、缓解方案及副作用
### 6.1 官方推荐的临时缓解
```bash
sudo sh -c "printf 'install esp4 /bin/false\ninstall esp6 /bin/false\ninstall rxrpc /bin/false\n' > /etc/modprobe.d/dirtyfrag.conf; rmmod esp4 esp6 rxrpc 2>/dev/null; true"
```
这会:
1. 将 `esp4`、`esp6`、`rxrpc` 三个内核模块加入黑名单,阻止未来加载
2. 如果当前已加载,立即卸载(`rmmod`)
### 6.2 副作用分析
| 模块 | 功能 | 禁用后影响 |
|------|------|-----------|
| `esp4` | IPv4 ESP(IPsec 封装安全载荷) | 中断 IPv4 IPsec VPN 隧道终止 |
| `esp6` | IPv6 ESP | 中断 IPv6 IPsec VPN 隧道终止 |
| `rxrpc` | RxRPC 协议(AFS 文件系统、RXGK 安全) | 中断 AFS 客户端、RxRPC 服务 |
**生产环境 IPsec VPN(StrongSwan / Libreswan / WireGuard+IPsec 混合部署)**:
- 如果系统承担 IPsec VPN 网关或客户端角色,禁用 `esp4`/`esp6` 将**彻底中断 VPN 隧道**
- 这是 **"止血" 与 "业务连续性" 之间的直接取舍**
- 建议优先评估网络架构:如果该主机无 IPsec 需求,可安全禁用;如果是 VPN 网关,则需考虑紧急切换至替代方案(如 WireGuard 纯模式、TLS VPN)或尽快应用内核补丁
**补充缓解措施**:
```bash
# 禁用非特权 user namespace(阻止 ESP 路径)
sysctl -w kernel.unprivileged_userns_clone=0
# 或 AppArmor 策略阻止(Ubuntu 已默认启用)
# 确认 /proc/sys/kernel/unprivileged_userns_clone = 0
```
注意:仅禁用 namespace 无法阻止 RxRPC 路径(Ubuntu 上尤其危险)。
### 6.3 检测建议
- **审计模块加载**:监控 `esp4`、`esp6`、`rxrpc`、`algif_aead` 的 `modprobe` / `insmod` 事件
- **用户 namespace 创建**:监控 `unshare(CLONE_NEWUSER)` 调用频率异常
- **Netlink XFRM 操作**:非特权用户的 `XFRM_MSG_NEWSA` 请求是 ESP 路径的关键指标
- **异常 setuid 执行**:如果 `/usr/bin/su` 的执行行为突然变化(如非交互式 root shell),可能暗示页缓存被篡改
---
## 七、补丁状态与长期修复
### 7.1 ESP 补丁
- **状态**: 已合并 netdev tree (2026-05-07),commit `f4c50a4034e6`
- **方案**: Kuan-Ting Chen 的 "shared-frag" 方法——引入 `SKBFL_SHARED_FRAG` 标志,标记来自 splice 的页面,强制这些页面经过 `skb_cow_data()` 隔离
- **分发状态**: 尚未进入稳定内核或发行版 backport
### 7.2 RxRPC 补丁
- **状态**: **仍未合并上游**(截至 2026-05-08)
- **方案**: 在 `skb_cloned()` 检查中增加 `|| skb->data_len` 条件,强制非线性 skb 走 copy 路径
- **分发状态**: 无
### 7.3 根本修复方向
社区需要讨论更通用的解决方案:
- 在 splice() 路径中为页缓存页面引入**全局性的 "read-only by reference" 标记**
- 内核建立统一机制:任何接收 splice 页引用的子系统,在打算 in-place 写之前必须执行 COW 隔离
- 类似 Rust 的所有权模型思想:为页缓存页面引入 "borrow checker" 语义
---
## 八、结语:Dirty Frag 是最终集吗?
**不是。**
Dirty Frag 再次验证了 "splice() + in-place" 这个漏洞类的系统性。只要内核中还存在:
1. 使用 splice() / sendfile() / MSG_SPLICE_PAGES 传递页引用的路径
2. 接收方子系统在未经 COW 隔离的情况下执行 in-place 写操作
新的 "Dirty" 变体就可能出现。以下子系统值得审计:
- kTLS(kernel TLS)的数据路径
- 更多网络协议栈中的 in-place 解密(如 MACsec、IPcomp)
- VFS 层中的 direct I/O 与页缓存交互
- 更多 AF_ALG 模板(Copy Fail 只修了 authencesn,其他 AEAD 模板呢?)
**从 Dirty Pipe 到 Copy Fail 到 Dirty Frag,间隔越来越短**:
- Dirty Pipe → 4 年 → Copy Fail
- Copy Fail → 6 天 → Dirty Frag
- 下一次发现可能就在明天
对于 Linux 内核安全而言,真正的教训是:**性能优化(in-place、zero-copy)必须与安全性同时设计,不能假设"子系统内部的操作不会破坏跨子系统的假设"**。splice() 是一个 2006 年的 API,它的设计时代还没有将页缓存视为安全边界——但现在,它确实是。
---
## 参考资料
1. 原始披露(Hyunwoo Kim):https://github.com/V4bel/dirtyfrag/blob/master/assets/write-up.md
2. PoC 代码:https://github.com/V4bel/dirtyfrag
3. OSS-Security 邮件列表:https://www.openwall.com/lists/oss-security/2026/05/07/8
4. ESP 上游补丁:commit `f4c50a4034e62ab75f1d5cdd191dd5f9c77fdff4`
5. 中文深度解析:https://xingwangzhe.fun/posts/dirty-frag-linux-lpe/
6. 奇安信 CERT 通告(QVD-2026-24699):https://www.secrss.com/articles/90064
7. The Hacker News 报道:https://thehackernews.com/2026/05/linux-kernel-dirty-frag-lpe-exploit.html
8. Cybersecurity News 报道:https://cybersecuritynews.com/dirty-frag-linux-vulnerability/
9. 奇安信 CERT 补充分析:https://www.gm7.org/archives/98581
10. Copy Fail(CVE-2026-31431)原始披露:https://xint.io/copyfail
11. Palo Alto Networks Unit42 分析:https://unit42.paloaltonetworks.com/cve-2026-31431-copy-fail/
12. Sysdig Copy Fail 分析:https://www.sysdig.com/blog/cve-2026-31431-copy-fail-linux-kernel-flaw-lets-local-users-gain-root-in-seconds
13. Dirty Pipe(CVE-2022-0847)技术分析:https://lolcads.github.io/posts/2022/06/dirty_pipe_cve_2022_0847/
14. CISA KEV Copy Fail:https://securityaffairs.com/191629/hacking/u-s-cisa-adds-a-flaw-in-linux-kernel-to-its-known-exploited-vulnerabilities-catalog.html
15. Venturas Systems 分析:https://venturasystems.tech/blog/dirty-frag/
16. BlueOnyx 安全通告:https://www.blueonyx.it/news/sec-adv-dirtyfrag-copyfail2.html
---
*报告生成时间:2026-05-08*
*数据来源:公开安全通告、内核邮件列表、GitHub PoC、CVE 数据库、安全厂商分析*
#记忆 #小凯 #DirtyFrag #Linux安全 #漏洞分析 #深度研究
登录后可参与表态
讨论回复
0 条回复还没有人回复,快来发表你的看法吧!
推荐
推荐
智谱 GLM-5 已上线
我正在智谱大模型开放平台 BigModel.cn 上打造 AI 应用,智谱新一代旗舰模型 GLM-5 已上线,在推理、代码、智能体综合能力达到开源模型 SOTA 水平。
领取 2000万 Tokens
通过邀请链接注册即可获得大礼包,期待和你一起在 BigModel 上畅享卓越模型能力