Dirty Pipe:Linux 内核管道 Page Cache 覆写提权漏洞(CVE-2022-0847)
文档版本:v1.0 · 更新日期:2026-05-18 适用对象:安全研究员、系统管理员、渗透测试工程师
漏洞速览
| 属性 | 详情 |
|---|---|
| CVE 编号 | CVE-2022-0847 |
| 漏洞别名 | Dirty Pipe(脏管道) |
| CVSS 评分 | 7.8(HIGH) |
| CVSS 向量 | AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H |
| 漏洞类型 | CWE-668:资源暴露于错误控制范围(Page Cache 覆写) |
| 攻击向量 | 本地(Local) |
| 权限要求 | 低权限(Low) |
| 用户交互 | 不需要(None) |
| 公开日期 | 2022-03-07 |
| PoC 状态 | 已公开,在野利用 |
| 补丁版本 | Linux Kernel >= 5.16.11 / 5.15.25 / 5.10.102 |
| 临时缓解 | 不可行(需补丁修复) |
关键时间线
2021-04-29 ── 匿名安全研究员通过漏洞赏金计划向内核安全团队报告(corrupted files ticket)
2022-02-19 ── Max Kellermann 独立发现并分析漏洞根因
2022-02-20 ── Max Kellermann 向内核安全团队提交漏洞详情与补丁
2022-02-23 ── 修复补丁合并至 Linux 主线(commit 9d2231c5d74e)
2022-02-24 ── 稳定版内核发布(5.16.11/5.15.25/5.10.102)
2022-03-07 ── Max Kellermann 公开披露漏洞详情
2022-03-08 ── 首个公开 PoC 出现,各发行版集中发布安全更新
2022-04-01 ── 在野利用广泛出现
漏洞简介
Linux 内核的管道(Pipe)机制用于进程间通信(IPC),数据通过内核维护的环形缓冲区(Pipe Buffer)在进程间传递。2016 年,内核引入了 PIPE_BUF_FLAG_CAN_MERGE 标志位,允许 splice() 系统调用将文件 Page Cache 中的数据直接合并到管道缓冲区,实现零拷贝数据传输,大幅提升 I/O 性能。
CVE-2022-0847(Dirty Pipe)正是这一优化中的逻辑缺陷。由于 PIPE_BUF_FLAG_CAN_MERGE 标志位在管道缓冲区初始化时未被正确清除,当 splice() 将 Page Cache 页面合并到管道后,调用 write() 向管道写入数据时,内核错误地允许写入操作直接修改属于已被释放的 Page Cache 页面——而不是管道自己的缓冲区。攻击者可通过此机制向只读文件写入任意内容。
Dirty Pipe 被认为是 Dirty Cow 的 “精神续作”——两者均通过 Page Cache 污染实现提权。但 Dirty Pipe 相比 Dirty Cow 具有显著优势:不需要竞态条件(确定性触发)、利用稳定可靠、攻击门槛更低。该漏洞一经披露即被广泛利用,被称为 “近几年 Linux 最危险的本地提权漏洞之一”。
技术原理
利用链概述
低权限进程
│
├── ① 创建 pipe() 管道
│
├── ② splice() 将只读文件的 Page Cache 页面接到管道
│ 此时 pipe_buffer->flags 包含 PIPE_BUF_FLAG_CAN_MERGE
│
├── ③ write() 向管道写入恶意数据
│ 内核检测到 CAN_MERGE 标志 → 跳过新页面分配 →
│ 直接覆写 splice 引用的 Page Cache 页面
│
└── ④ 只读文件被篡改(内存层面)→ SUID 二进制被注入恶意代码 → root
详细步骤
步骤一:管道创建与 splice 注入
攻击者首先创建一个管道(pipe()),然后使用 splice() 系统调用将目标只读文件(如 /etc/passwd)的内容通过 Page Cache 引入管道:
int p[2];
pipe(p); // 创建管道
int fd = open("/etc/passwd", O_RDONLY); // 打开只读目标文件
unsigned int offset = 0;
// splice 将文件内容注入管道(零拷贝,引用 Page Cache 页面)
splice(fd, &offset, p[1], NULL, 1, 0);此时,管道的 pipe_buffer 结构直接指向文件的 Page Cache 页面,而非复制数据。关键的是,此时 pipe_buffer->flags 保留了 PIPE_BUF_FLAG_CAN_MERGE 标志。
步骤二:标志位未正确清除
正常流程下,PIPE_BUF_FLAG_CAN_MERGE 允许新数据追加到现有缓冲区末尾。但在 splice() 操作后,新的 pipe_buffer 从对应的 struct page 创建时,其 flags 字段未显式初始化为 0,而是沿用了前一个缓冲区的标志位。
// 内核代码简化示意:pipe_write() 中的关键分支
if (chars && !was_empty) {
unsigned int mask = pipe->ring_size - 1;
struct pipe_buffer *buf = &pipe->bufs[(head - 1) & mask];
int offset = buf->offset + buf->len;
// BUG: 此处仅检查 CAN_MERGE 标志,未验证 buf->page 的所有权
if ((buf->flags & PIPE_BUF_FLAG_CAN_MERGE) &&
offset + chars <= PAGE_SIZE) {
// 直接向 buf->page 写入,而该 page 可能属于只读文件!
memcpy(page_address(buf->page) + offset, src, chars);
buf->len += chars;
goto out;
}
}步骤三:写入触发覆写
攻击者随后调用 write() 向管道写入恶意数据:
char payload[] = "恶意数据,如覆盖 /etc/passwd 中的 uid=1000 为 uid=0";
write(p[1], payload, sizeof(payload));内核在执行 pipe_write() 时检查到 CAN_MERGE 标志,错误地认为可以将数据直接写入 Page Cache 页面,从而实现对只读文件的内存层面篡改。
步骤四:达成提权
由于写入仅发生在内核的 Page Cache 层,攻击者可修改任意只读文件的内容。常见利用路径:
- 修改
/etc/passwd:移除 root 密码或添加特权账户 - 注入 SUID 二进制:在
/usr/bin/su等程序中写入 shellcode - 覆写 cron job 配置:植入定时后门
与 Dirty Cow 对比
| 维度 | Dirty Cow(CVE-2016-5195) | Dirty Pipe(CVE-2022-0847) |
|---|---|---|
| 漏洞类型 | Race Condition(竞态条件) | 逻辑缺陷(标志位残留) |
| 触发方式 | 多线程竞态 | 单线程确定性触发 |
| 利用稳定性 | 中等(依赖竞态窗口) | 极高(100% 稳定) |
| 攻击门槛 | 较高(需理解竞态条件) | 较低(简单系统调用序列) |
| 写入粒度 | 一次可写 1024 字节 | 一次可写一页(通常 4096 字节) |
| 受影响版本 | 2.6.22 ~ 4.8.2(2007-2016) | 5.8 ~ 5.16.10(2020-2022) |
| 核心原语 | /proc/self/mem + madvise() | pipe + splice() + write() |
受影响版本
| 组件 | 受影响版本 | 安全版本 | 备注 |
|---|---|---|---|
| Linux Kernel(主线) | 5.8 ~ 5.16.10 | >= 5.16.11 | 漏洞自 2020 年 8 月引入(commit f6dd975583bd) |
| Linux Kernel(5.15 LTS) | 5.15.0 ~ 5.15.24 | >= 5.15.25 | 影响大量现代发行版 |
| Linux Kernel(5.10 LTS) | 5.10.0 ~ 5.10.101 | >= 5.10.102 | — |
| Ubuntu 22.04(Jammy) | kernel < 5.15.0-25 | >= 5.15.0-25 | 初始发布受影响的 LTS 版本 |
| Ubuntu 20.04(Focal) | HWE kernel 5.13+ | 发行版已 backport 修复 | — |
| Fedora 35/36 | 受影响的 5.x 内核 | 已发布修复 | — |
| RHEL 9 | kernel < 5.14.0-70 | >= 5.14.0-70 | — |
| Debian 11(Bullseye) | 默认 5.10.x < 5.10.102 | >= 5.10.0-12 | — |
| Android | 基于 5.8+ 内核的设备 | 含 2022-03/04 安全补丁级别 | — |
| 内核 < 5.8 | N/A | N/A | 不受影响(CAN_MERGE 优化未引入) |
| 内核 >= 5.17-rc1 | N/A | N/A | 主线在 5.17 合并窗口前已修复 |
漏洞影响场景
场景 1:本地低权限用户提权
- 前提条件:攻击者拥有目标系统的普通 shell 账号(无需 sudo 权限)
- 攻击过程:编译执行 Dirty Pipe PoC,覆写
/etc/passwd或 SUID 二进制 - 最坏影响:获取 root shell,完全控制系统
场景 2:容器环境攻击与逃逸
- 前提条件:容器内进程以低权限运行,宿主机运行受影响内核
- 攻击过程:在容器内执行 Dirty Pipe,直接修改宿主机 Page Cache 中的文件
- 最坏影响:容器逃逸至宿主机 root,突破容器隔离
场景 3:CI/CD 与共享开发环境
- 前提条件:多用户共享的 Linux 工作站或 CI Runner,任意用户可使用编译器
- 攻击过程:上传并执行 Dirty Pipe EXP,污染 Runner 或宿主机
- 最坏影响:窃取其他租户代码、CI Secrets、横向渗透
场景 4:Android 设备 Root
- 前提条件:Android 设备运行基于 5.8+ 内核的 ROM
- 攻击过程:通过用户安装的恶意应用或 ADB 执行 Dirty Pipe
- 最坏影响:设备完全 Root,绕过 SELinux 和 Verified Boot
修复措施
推荐修复(根本解决)
升级内核至修复版本。
# Ubuntu / Debian
sudo apt update && sudo apt upgrade -y linux-image-generic
sudo reboot
# RHEL / CentOS / AlmaLinux 9
sudo dnf update kernel -y
sudo reboot
# Fedora
sudo dnf update kernel -y
sudo reboot
# 验证修复
uname -r
# 期望:>= 5.16.11 / 5.15.25 / 5.10.102 或发行版 backport补丁核心修改(commit 9d2231c5d74e):在 pipe_write() 中,当创建新的 pipe_buffer 时,显式初始化 buf->flags = 0,确保 PIPE_BUF_FLAG_CAN_MERGE 不会被错误继承。
临时缓解(无法立即升级时)
Dirty Pipe 缺陷位于内核核心管道子系统中,没有可行的临时缓解措施。
| 方案 | 说明 | 局限性 |
|---|---|---|
| 禁用非特权用户命名空间 | sysctl -w kernel.unprivileged_userns_clone=0 | 仅限制部分利用路径,有功能副作用 |
| SELinux/AppArmor 策略 | 限制 splice() 调用 | 配置复杂,可能影响正常应用 |
| 最小权限原则 | 确保无本地非可信用户 | 非根本解决方案 |
一键检查与执行临时修复脚本
检查脚本
#!/bin/bash
# Dirty Pipe (CVE-2022-0847) 漏洞检查脚本
# 用途:检查当前内核版本是否在受影响范围内
# 限制:仅通过版本号判断,不执行实际利用验证
echo "=== Dirty Pipe (CVE-2022-0847) 漏洞检查 ==="
echo ""
KERNEL_FULL=$(uname -r)
KERNEL_VER=$(echo "$KERNEL_FULL" | cut -d'-' -f1)
echo "当前内核版本:$KERNEL_FULL"
MAJOR=$(echo "$KERNEL_VER" | cut -d'.' -f1)
MINOR=$(echo "$KERNEL_VER" | cut -d'.' -f2)
PATCH=$(echo "$KERNEL_VER" | cut -d'.' -f3)
echo ""
# 漏洞引入:5.8(commit f6dd975583bd)
# 修复版本:5.16.11 / 5.15.25 / 5.10.102
check_affected() {
if [ "$MAJOR" -lt 5 ]; then
return 1 # < 5.0,不受影响
fi
if [ "$MAJOR" -eq 5 ] && [ "$MINOR" -lt 8 ]; then
return 1 # < 5.8,不受影响
fi
if [ "$MAJOR" -gt 5 ]; then
return 1 # >= 6.0,主线已修复(5.17-rc1 前合并)
fi
# 检查各分支修复版本
if [ "$MINOR" -ge 17 ]; then
return 1 # 5.17+,主线已修复
fi
if [ "$MINOR" -eq 16 ] && [ "$PATCH" -ge 11 ]; then
return 1 # >= 5.16.11,已修复
fi
if [ "$MINOR" -eq 15 ] && [ "$PATCH" -ge 25 ]; then
return 1 # >= 5.15.25,已修复
fi
if [ "$MINOR" -eq 10 ] && [ "$PATCH" -ge 102 ]; then
return 1 # >= 5.10.102,已修复
fi
return 0
}
if check_affected; then
echo "⚠️ 当前内核版本可能受 Dirty Pipe (CVE-2022-0847) 影响"
echo " 建议立即升级内核或确认发行版已 backport 补丁"
else
echo "✅ 当前内核版本不在已知受影响范围"
echo " (如使用发行版定制内核,请查阅发行版安全公告确认)"
fi
echo ""
echo "=== 检查完成 ==="重要提示:Dirty Pipe 没有有效的临时缓解措施。若检查发现受影响,应立即升级内核并重启。
参考资源
官方与 NVD
| 标题 | URL | 类型标签 |
|---|---|---|
| NVD - CVE-2022-0847 | https://nvd.nist.gov/vuln/detail/CVE-2022-0847 | NVD |
| Max Kellermann 公开披露文章 | https://dirtypipe.cm4all.com/ | 官方/技术分析 |
| Linux 内核主线修复 commit | https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=9d2231c5d74e | 修复指南 |
| oss-security 披露帖 | https://www.openwall.com/lists/oss-security/2022/03/07/1 | 官方 |
发行版安全公告
| 标题 | URL | 类型标签 |
|---|---|---|
| Ubuntu Security Notice | https://ubuntu.com/security/CVE-2022-0847 | 厂商公告 |
| Red Hat CVE 页面 | https://access.redhat.com/security/cve/cve-2022-0847 | 厂商公告 |
| Debian Security Tracker | https://security-tracker.debian.org/tracker/CVE-2022-0847 | 厂商公告 |
PoC 与工具
| 标题 | URL | 类型标签 |
|---|---|---|
| Max Kellermann 原始 PoC | https://haxx.in/files/dirtypipez.c | PoC |
| Arthepsy PoC(增强版) | https://github.com/Arthepsy/CVE-2022-0847-DirtyPipe-Exploit | PoC |
| liamg/traitor(自动化提权工具) | https://github.com/liamg/traitor | 工具 |
Dirty Pipe 代表了 Linux 内核安全中最危险的一种模式:看似无害的性能优化,在特殊条件下变成确定性提权原语。它的出现推动了内核社区对 splice() 与 Page Cache 交互安全性的全面审视。