文章总结: CVE-2026-31431是Linux内核高危本地提权漏洞,通过AFALG套接字串联crypto模块两个独立缺陷实现页缓存污染,允许普通用户对系统可读文件进行4字节可控写入。影响4.14至7.0间所有主流发行版,PoC已公开。修复方案需升级内核至6.18.22/6.19.12/7.0或禁用algifaead模块。 综合评分: 87 文章分类: 漏洞分析,漏洞预警,解决方案,Linux安全,二进制安全
CopyFail本地提权漏洞影响主流Linux系统最新版(CVE-2026-31431)
原创
安全实验室 安全实验室
墨菲安全实验室
2026年4月30日 11:55 北京
在小说阅读器读本章
去阅读
简述
2026 年 4 月 29 日,安全研究团队 Xint Code 通过copy.fail与公司博客公开了 Linux 内核本地提权漏洞 CVE-2026-31431(代号Copy Fail)的完整技术分析,并在 GitHub 放出 732 字节的 Python PoC。该 CVE 编号实际上在 4 月 22 日已悄悄登记到 NVD,对应的主线修复 commita664bf3d603d早在大约一个月前就已合入内核,但当时并未以”本地提权漏洞”的口径对外披露。4 月 29 日 oss-security 邮件列表跟进转发后,漏洞开始大范围扩散。
PoC 在 Ubuntu 24.04 LTS、Amazon Linux 2023、RHEL 10.1、SUSE 16 等主流发行版上均直接拿到 root。
漏洞根源是 2017 年加进crypto/algif\_aead.c的一处「就地 AEAD 操作」优化(commit72548b093ee3),这条九年前的优化和早就存在于crypto/authencesn.c里的一处 4 字节越界 scratch 写互相串联,让一个普通用户能够:对系统中任何可读文件的页缓存(page cache),发起一次确定性的、可控偏移、可控内容的 4 字节写入。
页缓存被污染后,任何后续 mmap/read 这些文件的进程都会读到被改过的内容——典型攻击路径就是改写 setuid 二进制的代码段以提权。
漏洞从 4.14 内核引入,Linux 7.0 主线(commita664bf3d603d)和 6.19.12、6.18.22 两个稳定分支已修复。
图 1:copy.fail 漏洞披露页
漏洞基本信息
| 项 | 值 |
| — | — |
| 漏洞编号 | CVE-2026-31431 |
| 别称 | Copy Fail |
| 漏洞类型 | CWE-669 资源在不同领域之间的不当传输 |
| CVSS 3.1 | 7.8(高危) AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H |
| 漏洞等级 | 高危 |
| 处置建议 | 立刻修复 |
| 利用所需权限 | 本地普通用户 |
| 利用条件 | 内核未禁用AF\_ALG且algif\_aead模块可加载 |
| 利用成本 | 低(PoC 已公开,732 字节) |
| 影响范围 | Linux 内核 4.14 起的全部版本,至 7.0 / 6.19.12 / 6.18.22 之前 |
| POC | 已公开(GitHub:theori-io/copy-fail-CVE-2026-31431) |
| 复现时间 | 2026.4.29 |
漏洞详细分析
这个漏洞之所以具备研究价值,是因为它由两个本身都看起来没问题的 bug 拼成。单独看每一个,maintainer 都不会认为是漏洞;放在一起就构成了一个稳定的页缓存写原语。
- authencesn 模板的 4 字节 scratch 写
authencesn是内核 crypto 子系统里给 IPsec 扩展序列号(ESN)用的 AEAD 包装算法。它做解密时需要把 32 位的高位序列号塞进 IV 计算,于是在crypto/authencesn.c里有一处 scratch-pad 操作:
// crypto/authencesn.c crypto_authencesn_decrypt() (节选)
// [1] 算出 tag 区域起点:assoclen + cryptlen
// [2] 把序列号低 4 字节临时写进 dst 缓冲,作为 hash 计算的一部分
scatterwalk_map_and_copy(tmp +1, dst,
assoclen + cryptlen,4,1);
// [3] 用临时拼好的数据计算 hash 并比对 tag
// [4] 验证完成后……并未把这 4 字节恢复回去
也就是说:无论解密成功还是失败,dst 缓冲区中assoclen + cryptlen偏移处的 4 字节会被永久改写为seqnolo的内容*,而seqno*lo完全由用户态可控。
这个行为本身在 IPsec 的正常调用路径里没有问题——dst 是内核临时申请的缓冲,写就写了。问题出在第二个 bug 让 dst 不再是内核临时缓冲。
- 2017 年那一处「就地 AEAD」优化
2017 年内核为了减少一次内存拷贝,在crypto/algif*aead.c里加了 commit72548b093ee3——当用户通过AF*ALG套接字发起 AEAD 解密时,把源 scatterlist 和目的 scatterlist 拼到一起,让算法就地处理:
// crypto/algif_aead.c _aead_recvmsg() 优化路径(简化)
// [1] AAD + 密文从发送 SGL 拷到接收缓冲
// [2] tag 页通过引用直接挂进 SGL,没有拷贝
sg_chain(rsgl, ..., tsgl);// 把 TX 的 tag 页链到 RX 上
// [3] 关键一步:让 src 与 dst 指向同一条链
req->src = req->dst;
// [4] 调下层 AEAD 算法做就地解密
正常思路下,src 和 dst 来自同一个用户进程的内存映射,就地操作是安全的。但AF\_ALG套接字可以接收来自splice()的输入——也就是说用户能用splice把任意可读文件的页缓存页直接拼进发送 SGL,而不经过拷贝:
[文件 /usr/bin/passwd 的 page cache 页]
│ splice(file_fd, pipe)
▼
[pipe buffer 持有 page cache 页的引用]
│ splice(pipe, alg_fd)
▼
[AF_ALG TX SGL 直接持有 page cache 页]
│ sg_chain → req->dst
▼
[内核把页缓存页放进了"可写目的"链表]
到这一步,内核已经把系统中任意一个可读文件的页缓存页当成了 AEAD 的可写目的缓冲。
- 两个 bug 的串联
接下来authencesn的解密路径被触发,它在 dst 偏移assoclen + cryptlen处写下 4 字节——而 dst 这条链的对应位置正是某个文件的页缓存页。攻击者通过控制assoclen与cryptlen字段决定写在哪一页的哪一位,通过控制扩展序列号决定写什么 4 字节内容。
更糟的是这次写入发生在 tag 校验之前——也就是即便后续 AEAD 校验失败、recvmsg()返回-EBADMSG,那 4 字节也已经被永久写进了页缓存。攻击者完全不需要构造合法的密文/tag。
得到的原语:对系统上任意一个本进程可读的文件,发起一次确定性的、偏移可控、内容可控的 4 字节页缓存写。
- 从 4 字节页缓存写到 root
页缓存写有一个特殊属性:它绕过文件权限模型。普通用户对/usr/bin/passwd没有写权限,但只要它能read()该文件,对应的物理页就已经在自己的进程里通过页缓存可达;而页缓存是全局共享的——一旦内核改写了这块物理页,之后任何进程mmap()或read()同一文件时,读到的都是被污染后的内容。
攻击者只要选一个 root 拥有的 setuid 二进制(系统里有的是:/usr/bin/passwd、/usr/bin/sudo、/usr/bin/su等),定位到一条无害指令的偏移,用 4 字节写改成跳到自己控制的 shellcode,然后调用该 setuid 程序——内核执行的是被污染的页缓存内容,进程拥有 root 权限。
PoC 的全部代码长度是732 字节。Xint Code 在 Ubuntu 24.04 LTS(6.17.0-1007-aws)、Amazon Linux 2023(6.18.8-9.213)、RHEL 10.1(6.12.0-124.45.1.el10\_1)、SUSE 16(6.12.0-160000.9-default)上均成功提权。
修复方案
主线在 commita664bf3d603d中直接 revert 了 2017 年的就地优化,恢复成 out-of-place 操作:AAD 与密文从 TX SGL 拷贝到 RX 缓冲,src 与 dst 各自独立。这意味着即便authencesn那 4 字节越界写依然存在,目的缓冲也不会再是来自splice()的页缓存页。
// 修复后:req->src 与 req->dst 完全分离
req->src = areq->tsgl;// TX SGL:用户发来的密文
req->dst = areq->first_rsgl.sgl.sgl;// RX SGL:内核独立缓冲
修复合并到三个分支:
| 分支 | 修复 commit | 起始可用版本 |
| — | — | — |
| 主线 7.0+ | a664bf3d603dc3bdcf9ae47cc21e0daec706d7a5 | Linux 7.0 |
| 6.19.y | ce42ee423e58dffa5ec03524054c9d8bfd4f6237 | 6.19.12 |
| 6.18.y | fafe0fa2995a0f7073c1c358d7d3145bcc9aedd8 | 6.18.22 |
注意authencesn.c那个根因 4 字节 scratch 写仍未单独修复。社区认为该 scratch 写在没有 page-cache-attack 表面的前提下不算独立漏洞,但这意味着如果将来再有别的 AEAD 路径让用户态可控页面进入 dst SGL,同样的事情会重演。
影响分析
几乎所有在用的 Linux 内核都受影响。algif\_aead是绝大多数发行版默认编译进内核的模块,且 9 年间从未被任何加固方案默认关闭。
云上影响尤其大。Xint Code 的成功验证清单覆盖:
-
Ubuntu 全系(14.04 LTS 至 26.04 LTS),含
linux-aws、linux-azure、linux-gcp、linux-gke、linux-oracle、linux-ibm等所有云厂商定制内核 -
Amazon Linux 2 / 2023
-
Red Hat Enterprise Linux 7 / 8 / 9 / 10
-
SUSE Linux Enterprise Server 12 SP5 至 16.1
-
openSUSE Leap 15.x
凡是允许多租户共用同一台 Linux 实例(共享 CI runner、Kubernetes 多租 Pod、PaaS 容器宿主、跳板机、研发用沙箱)的场景,都需要按高优先级处置——一个普通用户拿到 shell 就等于拿到 root。
容器边界并不能挡住这个漏洞。默认的 Docker / containerd 配置里AF*ALG套接字是允许的,algif*aead模块也是宿主机上加载好的;除非显式用 seccomp 拒绝socket(AF\_ALG, ...),否则容器内拿到 root 等价于宿主机内核里写一次页缓存——而页缓存是全宿主共享的,会把宿主机上的 setuid 二进制污染掉。这是典型的容器逃逸路径。
对开发者:本地开发机若运行了不受信第三方代码(构建脚本、npm install钩子、跑别人的 Docker 镜像、远程 VS Code 调试一段陌生代码),都已具备触发条件。
对安全运营团队:传统的 EDR、HIDS 通常不会把AF\_ALG套接字调用作为可疑行为告警,需要在 PoC 公开后的窗口期内主动做行为补盲。
排查与处置建议
- 优先升级内核
按发行版升级到包含 commita664bf3d603d/ce42ee423e58df/fafe0fa2995a0f的版本:
# Ubuntu / Debian
apt-getupdate&&apt-getinstall--only-upgradelinux-image-$(uname-r|sed's/-generic//')-generic
# Amazon Linux 2023
dnfupdatekernel
# RHEL / Rocky / Alma
dnfupdatekernel
# SUSE
zypperpatch
升级完重启,并校验:
uname-r# 确认到了已修复版本
- 来不及打补丁时的临时缓解
把algif\_aead模块加入黑名单并卸载:
echo"blacklist algif_aead">/etc/modprobe.d/blacklist-algif_aead.conf
echo"install algif_aead /bin/false">>/etc/modprobe.d/blacklist-algif_aead.conf
modprobe-ralgif_aead
如果业务确认不依赖AF\_ALG,更彻底的做法是用 seccomp 在容器/沙箱层面直接拒绝该协议族:
# Docker / Kubernetes seccomp profile 片段
{
"syscalls": [
{
"names": ["socket"],
"action":"SCMP_ACT_ERRNO",
"args": [
{"index":0,"value":38,"op":"SCMP_CMP_EQ"}
]
}
]
}
# 38 = AF_ALG
- 排查是否已被利用
PoC 不会留下日志——但页缓存被污染的副作用会在重启后消失(页会被重新从磁盘读入)。因此对 7 × 24 长跑的服务器,建议:
# 检查 setuid 程序文件 hash 是否与发行版包对应
rpm-Va|grep'^..5'# RHEL 系
debsums-c# Debian 系
# 列出当前加载了 algif_aead 的进程(异常环境下应为 0)
lsof/dev/null|grep-ialg# 粗筛
- 长期加固
云厂商 / 自建 K8s 平台应把「禁用AF*ALG协议族」作为默认 seccomp baseline 的一部分,与禁用userfaultfd、io*uring等历史多发的内核攻击面同步处理。
参考链接
-
漏洞披露页:https://copy.fail/
-
技术深度分析(Xint):https://xint.io/blog/copy-fail-linux-distributions
-
PoC 仓库:https://github.com/theori-io/copy-fail-CVE-2026-31431
-
NVD 条目:https://nvd.nist.gov/vuln/detail/CVE-2026-31431
-
主线修复 commit:https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=a664bf3d603dc3bdcf9ae47cc21e0daec706d7a5
-
引入问题的旧 commit(2017):https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=72548b093ee3
-
oss-security 公告:https://seclists.org/oss-sec/2026/q2/281
-
Ubuntu 安全跟踪:https://ubuntu.com/security/CVE-2026-31431
-
SUSE 安全跟踪:https://www.suse.com/security/cve/CVE-2026-31431.html
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:墨菲安全实验室 安全实验室 安全实验室《CopyFail本地提权漏洞影响主流Linux系统最新版(CVE-2026-31431)》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。








评论