Android普通应用用不了algif_aead,有个selinux的限制
漏洞是什么
1. 漏洞基本信息
- CVE 编号:CVE-2026-31431
- 代号:Copy Fail
- 类型:本地权限提升(普通用户→root)、容器逃逸
- 影响范围:2017 年之后主流 Linux 内核(Ubuntu、Debian、CentOS、Fedora 等)
- 评级:严重(CVSS 7.8~9.8)
- 披露时间:2026-04-29(韩国安全公司 Theori 公开)
- 利用难度 :极低------732 字节 Python 脚本即可提权,无竞争、无复杂构造
2. 漏洞到底是什么
简单说:
内核里有个 AF_ALG(用户态加密接口)+ splice(零拷贝文件传输)+ authencesn(IPsec 用的加密模板) 的组合bug,导致普通用户可以向任意可读文件的内核页缓存写入 4 个受控字节。
2.1 核心根源:页缓存进了"可写"链表
- 用户用
splice()把一个文件"零拷贝"到管道,再发给 AF_ALG 加密套接字。 - 内核为了省内存,不复制文件内容,直接引用内核页缓存(page cache)的物理页。
- 2017 年内核加了个优化:AEAD 解密时"原地操作"------输入输出共用一个散列表(scatterlist)。
- 结果:只读的页缓存页面,被放进了可写的输出链表。
2.2 触发点:authencesn 越界写
authencesn是给 IPsec 用的 AEAD 模板,为了处理 64 位序列号(ESN),会把输出缓冲区当临时草稿纸。- 它在解密最后,会在合法输出区之外硬写 4 字节(序列号低 32 位)。
- 别的加密算法都老老实实只写合法区域,只有 authencesn 越界写。
2.3 结合 = 任意页缓存写
- 当"原地优化"+"splice 页缓存引用"+"authencesn 越界写"三者凑一起:
- 越界写直接落到内核页缓存的物理页上------也就是你 splice 的那个文件的内存镜像。
- 攻击者能控制三件事 :
- 写哪个文件(只要你能读)
- 写文件内哪个偏移
- 写哪 4 个字节内容
3. 能干嘛?
最直接:
- 普通用户篡改 /usr/bin/su、/bin/bash、sudo 等 setuid 根程序的内存镜像(页缓存)。
- 不用改磁盘上的二进制(不触发校验),但系统运行时执行的是被篡改的内存版本,直接拿到 root 权限。
- 容器里可以改宿主机页缓存,实现容器逃逸。
和 Dirty Cow、Dirty Pipe 比:
- 不用竞争条件(一次就成)
- 不用找内核偏移
- 不用编译,纯 Python 脚本
- 成功率几乎 100%
4. 时间线
- 2011:authencesn 加入内核,开始用输出区当草稿
- 2015:AF_ALG 支持 AEAD,但当时是"非原地",输入输出分离,页缓存只读
- 2017:原地优化合入(commit 72548b093ee3),页缓存进入可写输出链表------漏洞成型
- 2026-04-29:公开披露,PoC 放出
漏洞细节
1. 修复前(漏洞状态)
c
// 输入 = 输出(同一个链表)
req->src = req->dst
问题点:
- 输入和输出共用同一个 scatterlist
- 页缓存页面通过
sg_chain()被链入了可写的输出链表 authencesn越界写 → 直接改写内核页缓存- 这就是漏洞根源
2. 修复后(安全状态)
c
// 输入 和 输出 完全分离
req->src = TX SGL(来自用户 sendmsg 的数据,只读)
req->dst = RX SGL(用户 recvmsg 缓冲区,只写)
关键修改(代码对照)
c
// 漏洞代码(in‑place)
aead_request_set_crypt(..., rsgl_src, rx_sgl, ...);
// src 和 dst 都是 RX SGL → 同一个链表
// 修复代码(out‑of‑place)
aead_request_set_crypt(..., tsgl_src, rx_sgl, ...);
// src = TX SGL(输入)
// dst = RX SGL(输出)
// 完全分开
3. 修复具体做了什么?
官方补丁做了 3 件关键事:
① 彻底取消 in‑place 原地操作
不再让输入输出共用链表,从设计上消灭页缓存进入可写链表的可能。
② 移除 sg_chain() 链式拼接
不再把文件的页缓存标签页(tag pages) 拼接到输出缓冲区后面。
→ 页缓存页面永远不会进入可写 dst 链表。
③ 只复制 AAD 数据,不再引用物理页
所有数据从 src → dst 都是真正复制,不再共享物理页。
4. 官方为什么这么修复?
"在 algif_aead 中使用原地操作没有任何好处,因为源和目标来自不同的映射。"
翻译成人话:那个 2017 年的优化本来就没性能收益,还带来了致命安全问题,所以直接删掉最安全。
5. 修复效果(100% 堵死漏洞)
修复后:
- 页缓存页面永远只存在于只读的输入链表(src)
- 不会进入可写输出链表(dst)
authencesn就算越界写,也只会写到用户自己的缓冲区- 无法写内核页缓存 → 漏洞完全消失
6. 系统管理员如何修复?
方法1(推荐)
升级内核(最干净、最彻底)
方法2(临时缓解)
如果不能马上升级内核,可以禁用 algif_aead 模块:
bash
echo "install algif_aead /bin/false" > /etc/modprobe.d/disable-algif-aead.conf
rmmod algif_aead 2>/dev/null