昨晚十一点多,我还在享受五一假期,看到群里有人扔了一个链接copy.fail,打开一看,人麻了。
这是四天前,也就是4月29号刚披露的一个Linux内核漏洞,编号CVE-2026-31431,外号"Copy Fail"。 我大概看了了十分钟,然后打开了公司的运维群,发了一句话:明天第一件事,所有Linux机器看内核版本。可能有朋友看到之后一脸懵,这是什么?下面我就给大家详细说说。一个普通用户,什么权限都没有,跑一段732字节的Python脚本,不到几秒钟,变成root。你可能觉得这听起来很普通,提权漏洞又不是没有。 但这个的恶心之处在于:它不需要碰运气。大多数提权漏洞,比如09年那个"脏牛"(Dirty COW),需要在内核还没反应过来的瞬间把脏数据塞进去。 成功率看RP,有时候搞一半系统就崩了。Copy Fail完全不一样,整个攻击路径是一条直线,按步骤走,内核规规矩矩帮你执行,每一步都是确定性的,没有运气成分。有研究者测了一些Linux发行版,同一个脚本,无差别复现,100%成功率。这类漏洞更接近2022年的"脏管道"(Dirty Pipe,CVE-2022-0847),同样是操纵内核页缓存,同样简洁可靠,但攻击面更大,因为这次涉及的是加密子系统,几乎默认启用。2017年,有个内核开发者在优化AF_ALG加密接口的性能。 具体来说,是模块里的AEAD操作。 原来的逻辑是:解密完,把结果写到一个独立开辟的新缓冲区里。他觉得这太浪费了,为什么不直接在原地改? 反正解密就是把密文变成明文,输入和输出的大小一样,原地覆写,省掉一次内存分配和数据拷贝,快不少。然后是2026年4月,韩国安全团队Xint Code的Brian Pak,借助他们自研的AI代码审计工具,在大约一个小时内定位到了这个问题。 我看他们的技术报告写的,是先凭经验觉得AF_ALG和splice()的组合"感觉哪里不对",然后把这个方向丢给AI做大规模扫描,AI自动追出了2017年那次优化的问题所在,并推导出了完整的攻击链。问题这么找到了,三个看起来都没问题的东西,凑在一起就成立定时炸弹了。第一个:AF_ALG,Linux 2011年引入的用户态加密接口。 简单说,普通程序可以像开一个socket一样,请求内核帮它做AES加密、HMAC哈希之类的操作。 不需要root,任何用户都能用。 本来是个好东西,让加密更安全、更高效。第二个:splice(),零拷贝系统调用。 正常从文件读数据再写到别的地方,数据要在内核和用户态之间来回倒腾好几次。 splice()聪明,直接在内核内部把"数据的引用"传过去,不复制实体。 如果你把文件通过splice送进AF_ALG套接字,内核拿到的不是数据副本,而是那个文件在内存里的页缓存的直接引用。第三个:2017年的in-place优化。 就是前面提到的,把解密结果直接写回输入内存,不开新缓冲区。单独看,每个都合理。 组合起来:splice() 把缓存页面直接送进了AF_ALG套接字。 in-place优化让这些页缓存页面出现在了可写的目标scatterlist里。 然后算法在解密时,需要在目标缓冲区的某个位置临时写4个字节的序列号数据——而现在这个位置,恰好落在了的页缓存上。即使后来HMAC认证失败,返回错误,那4个字节已经写进去了。攻击者可以精确控制写什么、写在哪里。 多次操作叠加,把在内存里的逻辑改掉。 下次有人执行这个程序,跑的是被篡改过的内存版本,shell就来了。最阴的部分是,磁盘上的文件,一个字节都没动。你用MD5、SHA-256去校验,结果完全正常。 因为攻击只发生在内存里的页缓存,文件完整性检查工具看的是磁盘,看不出来。这种隐蔽性,是传统提权漏洞很难做到的。而云原生环境是更大的麻烦,很多人第一反应:我跑的是容器,我应该没事吧?恰恰相反。页缓存是宿主机内核的全局共享资源,所有容器都用同一份。 哪怕你的容器里只是个没有任何权限的用户,只要能在容器里执行代码,就能通过宿主机的页缓存向宿主机或其他容器的共享基础镜像写入恶意内容。 一旦宿主机或高权限容器执行了被污染的文件,攻击者就从容器跳到了宿主机root。Kubernetes集群、CI/CD流水线、多租户云平台,全都在射程内。几乎所有2017年之后构建的Linux发行版。 确认受影响的包括:- Debian、Arch、Fedora、Rocky、AlmaLinux......
优先打补丁。内核主线已经在4月1日提交了修复,思路就是把2017年的in-place优化回滚掉。 各大发行版的修复包陆续在推,AlmaLinux等已经发了,其他的跟进中。 能重启的机器,更新内核重启,了事。echo "install algif_aead /bin/false" > /etc/modprobe.d/disable-algif.confrmmod algif_aead 2>/dev/null || true
这两行把内核模块卸载并拉黑,不影响常规加密功能,应用程序会自动降级到用户态加密库。容器环境可以额外加一层:用seccomp profile限制容器内创建AF_ALG套接字的能力,或者用AppArmor/SELinux收紧加密接口的访问权限。还有一件事很重要:如果你的系统在这段时间内暴露过不可信的本地用户或容器,而当时内核版本正好在影响范围内,那就不能只打补丁就完事了。 得认真考虑重新安装setuid二进制文件,甚至从可信介质重装系统。 因为攻击可能已经发生在内存里,升级内核不会清掉已经被篡改的内存状态,但如果系统重启或二进制被重新加载,干净的副本会从磁盘重新读入页缓存,重置篡改效果。我看安全报告这么多年,Copy Fail让我印象深的不是技术复杂度,它其实不算复杂,三个特性的交叉出了问题,让我印象深的是2017年,那个优化当时肯定是经过审查的,逻辑也确实没问题。 没有人想到八年后会有人把splice()的页缓存引用和这个in-place逻辑接在一起用。内核代码的问题就在这里,每一行都可能是九年后某个攻击链里的一块砖。以及AI一小时就找到了人类八年没注意到的东西,这件事本身也值得细想。我建议大家立即检查一下自己的机器,别让人有洞可钻。本期就到这里啦,朋友们,觉得有用的话,别忘了“点赞+收藏”,分享给身边的朋友~,正是因为你们的支持,博主才有更多的动力。关注我,后续也会继续分享更多电脑好用的系统和实用小技巧!