一个比.gitignore还短的Python脚本,是怎么在几小时内让全球安全团队集体加班的?

Theori研究平台Xint Code在2026年4月29日扔出的这个链接——copy.fail——揭开了Linux内核里藏了9年的逻辑漏洞。没有竞态条件,不需要内核符号,不碰ASLR。732字节,纯靠设计缺陷的组合拳。

打开网易新闻 查看精彩图片

这个漏洞到底攻击了哪里?

Linux从2015年开始把内核加密引擎暴露给用户空间,用的不是设备文件,而是标准socket接口:AF_ALG(地址族-算法)。任何无特权进程都能打开它,调用AES、HMAC、AEAD这些操作,硬件加速直接走内核。

OpenSSL的afalg引擎就用这个接口,几乎所有Linux发行版默认开启。

问题出在algif_aead模块——专门处理AEAD(认证加密关联数据)算法,比如AES-GCM。这类算法同时做加密和认证,IPsec这类场景重度依赖。

Copy Fail(CVE-2026-31431)是三个独立设计决策撞在一起的结果。

第一块多米诺:authencesn的越界写入

authencesn是给带扩展序列号的IPsec用的AEAD算法。解密时,它会故意往明文输出缓冲区末尾多写4字节,当临时空间用:

// crypto_authenc_esn_decrypt()内部:scatterwalk_map_and_copy(tmp + 1, dst, assoclen + cryptlen, 4, 1);// ^^^^^^^^^^^^^^^^^^^// 这里已经超出输出缓冲区

正常使用没问题,越界部分落在已分配内存里。但配上后面两个条件,这就成了突破口。

第二块多米诺:2017年的"优化"

2017年的commit 72548b093ee3给algif_aead加了个优化:不再把数据拷出去,直接复用源scatterlist当目标:

// 简化后的algif_aead.c(修复前):sg_chain(&out_sg, tfr_sg); // 把tag页链进输出scatterlistreq->src = req->dst; // 源=目标(原地操作!)

省了一次内存拷贝。副作用是:一批本该只读的页面,被标记成了可写。

第三块多米诺:splice的零拷贝陷阱

当你用splice()把文件塞进AF_ALG socket,内核根本不拷贝数据——直接把文件页缓存的引用交出去。这些页面原封不动进了AEAD的scatterlist。

splice(/usr/bin/su) → AF_ALG socket → 页缓存页面进入AEAD scatterlist

三条线交汇:splice进来的只读文件页,被2017年的优化变成可写目标,再被authencesn的越界写入篡改。攻击者能修改任意文件的页缓存——包括setuid二进制文件——而且不落盘,重启就消失,取证极难。

为什么这个组合等了9年才被发现?

单独看每个决策都有合理性。authencesn的越界写是已知行为,2017年的优化提升了性能,splice的零拷贝是标准设计。安全审计通常看单点漏洞,很少追踪跨子系统的交互。

Theori团队的关键洞察是:把文件I/O和加密子系统当成一个整体攻击面。页缓存的权限模型在splice路径下被AF_ALG打破了,而内核的scatterlist机制没做足够隔离。

732字节的利用代码核心逻辑很干净:打开AF_ALG socket,绑定authencesn算法,splice目标文件进来,触发解密操作,越界写修改页缓存,执行被篡改的setuid程序拿root。

没有内存损坏的随机性,没有内核指针泄露,稳定复现。

对基础设施意味着什么?

这个漏洞影响2017年以来的所有主流Linux发行版。容器逃逸、多租户隔离绕过、主机入侵——攻击者拿到普通用户shell就能一路打到root,而且内存里改过的文件执行完就"自愈",日志里几乎留不下痕迹。

云厂商的反应速度成了关键变量。页缓存投毒需要本地执行,但现代攻击链里这步的门槛越来越低——供应链漏洞、Web RCE、凭证泄露都能铺好路。

修复方案已经合并:内核给splice进AF_ALG的页面加只读标记,阻断篡改路径。但打补丁只是开始,安全团队得重新评估:还有多少子系统存在类似的跨边界优化,把安全假设悄悄改写?

如果你负责生产环境的Linux系统,现在该做的三件事:确认内核版本是否包含修复,审计AF_ALG的使用场景,检查有没有异常的非持久化root权限获取迹象——这种攻击不留文件,但内存痕迹和短时行为异常仍可能暴露。