Copy Fail Banner

CVE-2026-31431(Copy Fail):一个 Python 脚本就能拿 root,Linux 内核的 9 年沉疴

2026 年 4 月 29 日,安全研究团队 Theori 公开了一个 Linux 内核漏洞,代号 Copy Fail,编号 CVE-2026-31431,CVSS 评分 7.8(高危)。

但这个漏洞真正让人不安的不是评分——而是三个事实:

  1. 影响范围极广:从 2017 年引入至今,几乎涵盖了所有主流 Linux 发行版——Ubuntu、Debian、RHEL、Rocky、SUSE、Amazon Linux……无一幸免
  2. 利用门槛极低:732 字节的 Python 脚本,普通用户运行后直接获得 root shell,不需要任何竞争条件,不需要多次尝试
  3. 还能容器逃逸:如果你在容器里拿到一个普通用户的权限,可以直接逃逸到宿主机

这是一个让人后背发凉的漏洞。


一句话理解 Copy Fail

要理解这个漏洞,不需要懂内核源码,只需要知道一个简单的机制:

Linux 内核里有一个叫 页缓存(page cache) 的东西。当你读一个文件时,内核把文件内容缓存到内存里。后续的读写操作直接操作内存中的缓存,不需要重新读磁盘。

Copy Fail 利用了加密子系统 AF\_ALG 的一个代码缺陷,通过 splice() 系统调用,把目标文件(比如 /usr/bin/su)的页缓存页面链入加密操作的数据链表中。加密过程中的一次越界写入,会直接修改这个页缓存。

关键点:这个修改只会发生在内存中,不会触发磁盘回写。 所以普通的文件完整性检查工具(比如 sha256sum)查不出问题——磁盘上的文件是完好的,但内存中的执行映像已经被篡改。

攻击者把 /usr/bin/su 这类 setuid 程序改掉一两个字节,下次执行时就直接变成 root 了。


漏洞时间线

  • 2017 年:提交 72548b093ee3 被合入内核主线。这是一个优化:AF\_ALG 的 AEAD 解密路径改成「就地操作(in-place)」,把用户传入的页面直接链入散列表,避免额外的内存拷贝。
  • 2017–2026 年(9 年):这个优化一直存在于内核中,没有被发现有问题。
  • 2026 年 4 月 22 日:Greg Kroah-Hartman 提交修复补丁 a664bf3d603d,标题是「crypto: algif\_aead – Revert to operating out-of-place」——回退到非就地模式,承认 in-place 优化带来的复杂性不值得。
  • 2026 年 4 月 29 日:Theori 公开漏洞详情和 PoC。
  • 2026 年 4 月 29–30 日:各大发行版紧急发布安全更新。

影响版本

漏洞从内核提交 72548b093ee3 开始引入,到修复 a664bf3d603d 结束。

具体的受影响内核版本范围:

分支 受影响版本 安全版本
4.14–5.10 < 5.10.254 >= 5.10.254
5.11–5.15 < 5.15.204 >= 5.15.204
5.16–6.1 < 6.1.170 >= 6.1.170
6.2–6.6 < 6.6.137 >= 6.6.137
6.7–6.12 < 6.12.85 >= 6.12.85
6.13–6.18 < 6.18.22 >= 6.18.22
6.19 < 6.19.12 >= 6.19.12
7.0-rc <= rc6 >= rc7

受影响的主流发行版:

发行版 受影响版本 安全版本
Ubuntu 24.04 LTS < 6.8.0-117.117 >= 6.8.0-117.117
Ubuntu 22.04 LTS < 5.15.0-179.189 >= 5.15.0-179.189
Ubuntu 20.04 LTS < 5.4.0-230.250 >= 5.4.0-230.250
Debian 12 < 6.1.170-1 >= 6.1.170-1
RHEL 9 < 5.14.0-611.54.1 >= 5.14.0-611.54.1
RHEL 8 < 4.18.0-553.123.1 >= 4.18.0-553.123.1

几乎每一个主流发行版的 LTS 版本都在射程内。


为什么叫 Copy Fail

这个名字来自漏洞的本质:内核在复制数据时出了错。

in-place 操作的本意是「不复制数据,直接操作原页面」。但在 authencesn 加密模板的特殊实现中,它错误地把输出缓冲区后面的页面也当成了自己的临时存储空间。

说白了就是——该复制的时候没复制,不该写的地方写了。


漏洞的实际利用

Theori 公开的 PoC 代码不到 100 行,用 Python 编写。

攻击过程大致如下:

  1. 创建一个 AF\_ALG 类型的 socket,选择 authencesn(hmac(sha256),cbc(aes)) 算法
  2. 以只读方式打开目标文件(比如 /usr/bin/su
  3. 通过 splice() 系统调用把文件页缓存直接链入加密操作的输入散列表
  4. 触发解密操作,AEAD 解密路径中的越界写入覆盖了 /usr/bin/su 的页缓存
  5. 写入的 4 字节数据经过精心构造,把 su 的某些字节改为特定值
  6. 执行 /usr/bin/su,此时它已经被篡改,直接以 root 权限执行攻击者的代码

整个过程不需要竞争条件、不需要重试、不需要特殊的系统配置。一次执行,稳定提权。

演示视频中,攻击者在 Ubuntu 24.04、22.04、RHEL 9、Debian 12 四个系统上运行同一个脚本,全都秒获 root。


为什么 9 年没人发现

有几个原因:

  1. 代码路径非常特殊。它要求 AF\_ALG + AEAD + authencesn + splice() 四个组件同时配合。这不是普通人日常使用的路径。

  2. splice() 和 AF\_ALG 的组合很少被审计。这两者分别是文件系统和加密子系统的接口,属于跨子系统交互,容易成为安全审查的盲区。

  3. in-place 优化看起来很自然。2017 年引入时,提交信息写的理由很有道理:源和目标来自不同的内存映射,没必要复制。这个推理本身没错,但忽略了 authencesn 算法的一个特殊行为——它在解密过程中会额外写入 4 字节。

  4. 越界写入非常隐蔽。4 字节的偏移量,恰好跨越了一个边界,不会触发常规的内存越界检测。


影响远不止本地提权

对于云环境和容器平台来说,这个漏洞的杀伤力更大。

因为 Copy Fail 操作的是页缓存——页缓存在容器和宿主机之间是共享的。 这意味着:如果你在容器里有一个普通用户权限,也可能利用这个漏洞篡改宿主机的 setuid 文件,实现容器逃逸。

多家安全厂商的报告中都明确提到了 Kubernetes 节点的风险。


写在最后

Copy Fail 不是那种需要特殊硬件、特定配置、复杂操作才能触发的漏洞。一个普通的 Linux 用户登录到系统上,运行一段不到 100 行的 Python 代码,就能拿走 root。

如果你是服务器管理员,第一件事就是检查你的内核版本是否在受影响范围内,然后尽快更新。下一篇文章我会讲具体的排查方法和修复步骤。

最后修改: 2026年7月6日

作者

评论

发表评论

您的邮箱地址不会被公开。