Copy Fail (CVE-2026-31431) 核心分析

这是一个极其危险且优雅的 Linux 内核本地提权漏洞,732 字节 Python 脚本直取 root。

───

为什么它不一样

| 漏洞         | 条件           | Copy Fail    |
| ---------- | ------------ | ------------ |
| Dirty Cow  | 需要竞态条件,可能崩溃  | ❌ 不需要        |
| Dirty Pipe | 版本特定,需精确管道操作 | ❌ 全版本通吃      |
| Copy Fail  | 直线路径,无竞态,无重试 | ✅ 一个脚本跑所有发行版 |

恐怖之处:

跨发行版:Ubuntu、Amazon Linux、RHEL、SUSE 全中,无需改脚本
隐蔽:只污染 page cache,磁盘文件不变,文件完整性校验(checksum)检不出
跨容器:page cache 全系统共享,容器逃逸 + Kubernetes 节点沦陷(Part 2 会讲)

───

技术根因(三层叠加)

2011: authencesn 加入内核(IPsec ESN 支持)
       ↓ 用调用者的 dst buffer 当 scratch pad,写超出边界
2015: AF_ALG 支持 AEAD + splice() 路径
       ↓ splice 能把 page cache 页直接塞进 crypto scatterlist
2015: authencesn 迁移到新 AEAD 接口
       ↓ 引入 assoclen + cryptlen 越界写
2017: algif_aead 加入"原地操作"优化 ← 致命一击
       ↓ req->src = req->dst,page cache 页被链进**可写**的 dst scatterlist

三层独立合理的改动,在 2017 年交叉,沉默近十年。

───

攻击流程(4 步)

1. 开 socketAF_ALG 绑定 authencesn(hmac(sha256),cbc(aes)),无需特权
2. 构造写sendmsg() 发 AAD(控制 4 字节写入值)+ splice() 把目标文件(如 /usr/bin/su)的 page cache 页送进 crypto
3. 触发写recv() 触发解密。authencesn 在重组 ESN 时把 seqno_lo 写到 dst[assoclen + cryptlen]——这个位置恰好是 splice 链进来的 page cache 页
4. 执行:HMAC 失败返回错误,但 4 字节已写入。execve("/usr/bin/su") 加载被污染的 page cache,shellcode 以 root 运行

攻击者控制三样东西:

哪个文件:任何当前用户可读的文件
哪个偏移:通过 splice 的 offset/length/assoclen 精确计算
写什么值:AAD 的 bytes 4-7

───

修复

内核补丁(a664bf3d603d)直接回滚 2017 年的原地优化,改回 out-of-place:

req->src → 指向 TX SGL(只读,可能含 page cache)
req->dst → 指向 RX SGL(用户 buffer,可写)
sg_chain 机制整个被移除

───

现在该做什么

# 1. 打补丁 / 更新内核包
sudo apt update && sudo apt upgrade  # 或对应发行版的命令

# 2. 临时缓解:禁用 algif_aead 模块
echo "install algif_aead /bin/false" > /etc/modprobe.d/disable-algif-aead.conf
rmmod algif_aead 2>/dev/null

───

一个有趣的点

这个漏洞是AI 辅助发现的——Theori 的 Taeyang Lee 用 Xint Code 扫描 crypto 子系统,operator prompt 就一句话:

"注意:splice() 可以把只读文件的 page cache 引用送到 crypto TX scatterlist"

一小时扫描,Copy Fail 是最高危输出。

这 bug 的优雅在于它不是内存越界、不是 use-after-free,而是一个跨十年的架构层交集——2011 年的 scratch pad 习惯、2015 年的接口迁移、2017 年的性能优化,各自合理,合在一起就是 root。

经典。
 
 
Back to Top