CVE-2026-31431 "Copy Fail" 深度解析:一次改4字节,拿下root权限——Linux内核加密子系统的致命缺陷
前言:一个700字节的脚本,如何撬动整台服务器
2026年4月,韩国安全研究团队 Theori 披露了一个编号为 CVE-2026-31431 的 Linux 内核漏洞,代号 "Copy Fail"。这个漏洞的可怕之处不在于它需要多复杂的技术,而在于它的极简攻击面——一个不到 700 字节的 Python 脚本,在单线程、无竞争条件下,就能把一个普通用户提升为 root。整个过程稳定、可复现,且几乎不依赖内核符号信息。
CVSS 3.1 评分 7.8(高危),影响范围覆盖 2017 年至 2026 年修复前几乎所有主流 Linux 发行版——Ubuntu、RHEL、Debian、Fedora、Amazon Linux、欧拉、UOS、麒麟,无一幸免。
本文将从漏洞背景、核心原理、代码级分析、实战复现、检测方法、修复与临时规避六个维度,对这个漏洞进行彻底的深度拆解。目标是让每个看到这篇文章的开发者不仅"知道"这个漏洞,而是真正理解它为什么发生、如何发生、怎么防御。
⚠️ 免责声明:本文所有代码仅用于安全研究、漏洞验证和防御加固学习。请勿在未授权环境中测试或利用漏洞。
一、背景:Linux Kernel Crypto API 与 AF_ALG
要理解这个漏洞,首先需要理解 Linux 内核暴露给用户态的加密能力。
1.1 Kernel Crypto API
Linux 内核从很早版本开始就内置了一套完整的加密框架——Kernel Crypto API。这个框架为内核自身以及用户态程序提供了丰富的加密算法实现,包括对称加密(AES、DES)、哈希算法(SHA1、SHA256)、非对称加密(RSA)以及 AEAD(Authenticated Encryption with Associated Data)等。
这套 API 的设计初衷是让内核各子系统(文件系统、网络堆栈等)能方便地使用加密能力,同时也向用户态暴露接口。AEAD 是现代密码学中非常重要的一类算法,它同时提供加密和完整性校验,典型代表如 ChaCha20-Poly1305、AES-GCM 等。
1.2 AF_ALG:用户态加密 Socket
Linux 通过一个特殊的 socket 族——AF_ALG(Address Family ALGorithm,family=38)——向用户态程序暴露加密能力。使用方式类似于 TCP/UDP socket:
import socket
# 创建一个 AF_ALG socket
# AF_ALG 是 Linux 特有的,不是 POSIX 标准
alg_fd = socket.socket(socket.AF_ALG, socket.SOCK_SEQPACKET, 0)
# 绑定到指定的算法
# 这里以 authencesn 为例——这是漏洞涉及的核心算法
alg_fd.bind(("aead", "authencesn(hmac(sha1),cbc(aes))"))
# 之后可以通过 sendmsg/recvmsg 与内核加密模块交互
这个接口的设计本身没有问题,它让用户态程序可以在不依赖 OpenSSL 等外部库的情况下调用内核内置的高效加密实现。但问题出在 algif_aead 模块的具体实现中——特别是当它与 splice() 系统调用结合时。
1.3 algif_aead 与 in-place 优化
algif_aead 是 AF_ALG 中处理 AEAD(带关联数据的认证加密)算法的内核模块。内核开发者在 2017 年左右为它引入了一个性能优化:in-place 操作(原地操作)。
传统的加密操作通常是:
输入缓冲区 [input] → 加密处理 → 输出缓冲区 [output]
In-place 优化后:
输入/输出缓冲区复用同一块内存 [buf] → 加密处理(就地完成)
这减少了内存分配和数据拷贝,对性能有明显提升。但这个优化引入了一个微妙的假设:当源缓冲区和目标缓冲区是同一块内存时,内核可以安全地将这块内存视为可写的。
问题来了——当攻击者精心构造数据路径,让来自文件 page cache 的页面(本应是只读的源数据)被当作可写的目标缓冲区使用时,这个假设就被打破了。
1.4 splice():零拷贝的隐患
splice() 是 Linux 提供的一个系统调用,可以在两个文件描述符之间零拷贝传输数据。它的典型用法包括:
- 将文件内容直接送入管道:
splice(fd, NULL, pipe_fd, NULL, size, SPLICE_F_MOVE) - 将管道数据直接写入文件:
splice(pipe_fd, NULL, fd, NULL, size, SPLICE_F_MOVE) - 在 socket 和文件之间传输数据
零拷贝的好处是避免了在用户态和内核态之间反复拷贝数据。但 splice 的副作用是数据页的所有权和语义变得复杂——页面可能在不同上下文之间流转,内核需要小心维护"谁可以写、谁只能读"的状态。
CVE-2026-31431 的核心漏洞就出现在 algif_aead 处理 splice() 数据路径时,没有正确区分"应该被当作源(只读)"和"可以被当作目标(可写)"的缓冲区。
二、漏洞原理:从"本应失败"到"可控写入"
2.1 攻击的核心思路
漏洞利用的整体思路可以用三句话概括:
- 通过 splice() 将一个可读文件的 page cache 页面注入到 AEAD 解密操作的输入路径中
- 利用 algif_aead 的 in-place 解密优化,让这个页面同时成为"解密输出目标"
- AEAD 认证解密失败(tag 不匹配),但已经写入了 4 字节的密文解密结果到 page cache 中
关键点在于第三步:AEAD 认证加密模式(尤其是 authencesn)有一个特性——它在处理数据时会先将密文写入输出缓冲区,然后才验证认证标签。如果标签验证失败,操作会返回错误,但已经写入的那部分数据不会回滚。
在正常场景下,这是无害的——输出缓冲区本来就是用户态分配的可写内存。但在攻击者精心构造的数据路径下,当 page cache 页面通过 splice 进入这个流程时,内核错误地将其放入了"输出 scatterlist"(目标缓冲区列表),导致解密出的 4 字节被写入了 page cache。
2.2 根因分析:scatterlist 混淆
在 Linux 内核的加密实现中,数据以 scatterlist(分散-聚集列表)的形式组织。一个 scatterlist 描述了一系列内存区域,告知加密引擎"从哪里读输入数据,写入到哪里"。
正常的数据路径:
用户态 buffer(可写)→ 设置为"读源"
→ 设置为"写目标"
→ 加密操作完成(输入=输出,同一块内存,in-place)
攻击者构造的数据路径:
文件 page cache(只读)→ 通过 splice 注入到 scatterlist
→ 被设置为"读源"
→ 但因为 in-place 优化的实现缺陷,也被设置为"写目标"
→ 解密结果写入 page cache → 成功污染
内核的 crypto_aead_decrypt() 或类似函数在处理 authencesn 的 in-place 路径时,会遍历 scatterlist。问题出在 aead_copy_frags 或类似的辅助函数中——它没有正确检查"这块内存是否真的来自 page cache 且不应该被写入"。
2.3 精确控制:为什么是4字节?
答案藏在内核代码中 authencesn 的实现细节里。AEAD 算法在解密时,会先将数据拷贝到一个临时缓冲区(通常是 4 字节对齐的),处理完成后再写回。如果在这个过程中出现错误(例如认证标签不匹配),写回操作可能只完成了一部分——恰好是 4 字节。
这就是为什么公开的 exploit 每次写入固定 4 字节。攻击者无法一次性写入任意长度,但可以通过多次调用逐步修改 setuid 二进制文件的任意位置:
# 伪代码:多次写入以覆盖 ELF 入口点
for offset in range(0, len(shellcode), 4):
write_4_bytes_at_offset(target_file, offset, shellcode_chunk)
2.4 为什么不会触发文件哈希检测?
这是这个漏洞最"狡猾"的地方。攻击者修改的是 page cache——操作系统为磁盘文件在内存中维护的缓存。修改 page cache 不等于修改磁盘文件:
用户修改文件 → 操作系统先写入 page cache
→ 操作系统决定何时将修改同步回磁盘(dirty page writeback)
→ 如果文件没有再次被访问或系统没有 sync,磁盘上的原始内容保持不变
即使攻击者修改了 /usr/bin/su 的 page cache,在 page cache 被回收(系统重启、内存压力触发、文件被覆盖)之前:
ls -la /usr/bin/su显示文件时间戳不变sha256sum /usr/bin/su显示哈希不变(因为读的是磁盘)- 只有当程序被执行时,才会从 page cache 加载被污染的代码
这也意味着磁盘文件哈希检测无法发现这个漏洞的利用。
三、漏洞利用分析:跨架构的通用 exploit
3.1 exploit 架构
研究团队发布的 exploit 仓库(theori-io/copy-fail-CVE-2026-31431)支持多个 CPU 架构:
| 架构 | Payload 大小 | 特点 |
|---|---|---|
| x86-64 | 160 字节 | 通用,覆盖大多数服务器 |
| i386 | 126 字节 | 32 位系统 |
| AArch64 (ARM64) | 172 字节 | 苹果 M 系列、ARM 服务器 |
| ARMv7 | 138 字节 | 32 位 ARM 设备 |
所有架构的 payload 都可以在同一套逻辑下工作——这得益于漏洞利用的是内核加密子系统的通用实现,而不是特定于某架构的代码。
3.2 核心利用步骤
#!/usr/bin/env python3
"""
CVE-2026-31431 Copy Fail - 简化版利用流程(注释版)
实际 exploit 代码请参考官方仓库: https://github.com/theori-io/copy-fail-CVE-2026-31431
"""
import os
import socket
import struct
import ctypes
AF_ALG = 38
SOL_ALG = 279
# ==================== 第一步:建立 AF_ALG socket ====================
# 创建一个 AF_ALG socket,用于与内核加密子系统通信
sock = socket.socket(AF_ALG, socket.SOCK_SEQPACKET, 0)
# ==================== 第二步:绑定 authencesn 算法 ====================
# authencesn 是 AEAD 算法的一种,漏洞就出现在这个算法的 in-place 处理路径中
# authencesn(hmac(sha1),cbc(aes)) 表示:认证使用 HMAC-SHA1,加密使用 CBC-AES
sock.bind(("aead", "authencesn(hmac(sha1),cbc(aes))"))
# ==================== 第三步:获取文件 page cache 的文件描述符 ====================
# 打开目标 setuid 程序,这里以 /usr/bin/su 为例
target_path = "/usr/bin/su"
target_fd = os.open(target_path, os.O_RDONLY)
# ==================== 第四步:通过 splice 将 page cache 注入到加密流程 ====================
# 关键步骤:通过 splice() 系统调用,将目标文件的 page cache 页面
# 注入到 AF_ALG socket 的发送路径中
#
# 内核在处理 splice → AF_ALG 的组合路径时,会将 page cache 页面
# 错误地放入解密操作的"输出目标"位置
#
# 这里需要创建一个管道作为中介:
pipe_rd, pipe_wr = os.pipe()
# 从目标文件 splice 到管道(此时 page cache 被加载到内存)
os.splice(target_fd, pipe_rd, pipe_wr, ...) # 实际调用更复杂
# 从管道 splice 到 AF_ALG socket
# 内核在这里将 page cache 页面错误地设置为"可写目标"
os.splice(pipe_rd, ..., sock, ...) # 实际调用更复杂
# ==================== 第五步:构造解密请求 ====================
# 发送精心构造的解密请求
# 关键:认证标签(tag)是精心设计的,使得:
# 1. 认证验证会"部分"通过
# 2. 解密操作执行了一部分
# 3. 恰好有 4 字节被写入 page cache
# 4. 最终返回认证错误
sock.send(crafted_decrypt_request)
# ==================== 第六步:触发 setuid 程序执行 ====================
# 此时被污染的 page cache 已被加载到内存
# 当 /usr/bin/su 被执行时,CPU 从被污染的 page cache 中取指
# 攻击者的 shellcode 被执行 → 获得 root shell
os.system("/usr/bin/su")
3.3 提权的核心:ELF 入口点覆盖
公开的通用 exploit 采用的是 ELF 入口点覆盖策略:
- 选择目标:ELF 可执行文件的入口点(
_start或 main 的 prologue) - 构造 shellcode:一小段能在 setuid root 上下文中打开
/bin/sh的机器码 - 多次写入:每次写入 4 字节,覆盖入口点的不同部分
- 执行触发:运行被污染的 setuid 程序,跳转到被覆盖的入口点 → shellcode 执行 → root shell
为什么选择入口点?因为入口点通常包含固定的、已知长度的 prologue 代码,攻击者可以精确计算出需要覆盖哪些字节:
# x86-64 典型入口点 prologue(被覆盖前)
_start:
xor ebp, ebp ; 3 字节
mov rsi, rsp ; 2 字节
and rsp, 0xfffffffffffffff0 ; 4 字节
mov rdi, qword ptr [rsp] ; 3 字节
call __libc_start_main ; 5 字节
# 攻击者只需要覆盖前面的几个字节,替换为跳转到 shellcode 的指令
四、环境检测:判断系统是否暴露于攻击面
4.1 快速暴露面检测脚本
下面的脚本不会执行提权,也不会修改任何系统文件。它只检测当前用户是否可以访问 AF_ALG AEAD 接口——这是漏洞利用的必要前提条件。
#!/usr/bin/env python3
"""
CVE-2026-31431 暴露面检测脚本(非破坏性)
用法: python3 check_exposure.py
退出码: 0=未暴露, 2=已暴露(可能存在漏洞)
"""
import os
import sys
import platform
import subprocess
AF_ALG = getattr(socket, "AF_ALG", 38) if 'socket' in dir() else 38
try:
import socket
AF_ALG = socket.AF_ALG
except AttributeError:
# AF_ALG 在某些平台上不可用
print("[-] AF_ALG socket family not available on this platform")
sys.exit(0)
# 测试的 AEAD 算法(按优先级排列)
AEAD_CANDIDATES = [
"authencesn(hmac(sha1),cbc(aes))",
"authenc(hmac(sha1),cbc(aes))",
"authencesn(hmac(sha256),cbc(aes))",
]
def run_cmd(cmd):
"""执行命令并返回输出"""
try:
return subprocess.check_output(cmd, shell=True, text=True, stderr=subprocess.DEVNULL).strip()
except Exception:
return ""
def check_algif_aead_loaded():
"""检查 algif_aead 内核模块是否加载"""
result = run_cmd("lsmod | grep algif_aead")
return bool(result)
def check_proc_crypto():
"""检查 /proc/crypto 中是否有 authencesn 相关算法"""
try:
with open("/proc/crypto", "r") as f:
content = f.read()
return "authencesn" in content or "authenc" in content
except Exception:
return False
def check_kernel_config():
"""检查内核是否配置了 AF_ALG AEAD 支持"""
# 尝试多个可能的配置文件位置
uname_r = platform.release()
configs = [
"/proc/config.gz",
f"/boot/config-{uname_r}",
f"/lib/modules/{uname_r}/build/.config",
]
for cfg in configs:
result = run_cmd(f"zcat {cfg} 2>/dev/null | grep CONFIG_CRYPTO_USER_API_AEAD || "
f"cat {cfg} 2>/dev/null | grep CONFIG_CRYPTO_USER_API_AEAD || true")
if "CONFIG_CRYPTO_USER_API_AEAD=y" in result or "CONFIG_CRYPTO_USER_API_AEAD=m" in result:
return result.strip()
return "not found"
def try_afalg_aead(alg_name):
"""尝试绑定 AF_ALG AEAD 算法"""
try:
s = socket.socket(AF_ALG, socket.SOCK_SEQPACKET, 0)
s.bind(("aead", alg_name))
s.close()
return True, None
except OSError as e:
return False, f"errno={e.errno} {e.strerror}"
except Exception as e:
return False, str(e)
def main():
import socket
print("=" * 60)
print("CVE-2026-31431 Copy Fail - 暴露面检测")
print("=" * 60)
print()
print(f"[*] 内核版本: {platform.release()}")
print(f"[*] 用户: uid={os.getuid()} euid={os.geteuid()}")
print(f"[*] 平台: {platform.system()} {platform.machine()}")
print()
# 检查内核配置
config = check_kernel_config()
print(f"[*] CONFIG_CRYPTO_USER_API_AEAD: {config}")
# 检查模块是否加载
loaded = check_algif_aead_loaded()
print(f"[*] algif_aead 模块: {'已加载' if loaded else '未加载'}")
# 检查 /proc/crypto
has_crypto = check_proc_crypto()
print(f"[*] /proc/crypto 包含 AEAD 算法: {'是' if has_crypto else '否'}")
print()
print("[*] 尝试访问 AF_ALG AEAD 接口...")
print("-" * 60)
exposed = False
for alg in AEAD_CANDIDATES:
ok, err = try_afalg_aead(alg)
if ok:
print(f"[+] 可访问: {alg}")
exposed = True
else:
print(f"[-] 不可访问: {alg} ({err})")
print()
print("=" * 60)
if exposed:
print("[!] 结果: 当前用户可以访问 AF_ALG AEAD 接口")
print("[!] 如果内核未修复,此系统存在被提权的风险")
print("[!] 建议: 立即检查内核安全公告并应用修复补丁")
sys.exit(2)
else:
print("[+] 结果: AF_ALG AEAD 接口不可访问")
print("[+] 可能原因: 模块未加载 / 策略限制 / 架构不支持")
print("[+] 此系统在当前用户上下文下不存在直接暴露面")
sys.exit(0)
if __name__ == "__main__":
main()
4.2 快速诊断命令清单
在任意 Linux 终端中执行以下命令,快速判断系统状态:
# 1. 查看内核版本
uname -r
# 2. 检查 algif_aead 模块是否加载
lsmod | grep algif_aead
# 3. 查看内核加密接口
cat /proc/crypto | grep -E 'authencesn|aead|name' | head -20
# 4. 检查内核配置
cat /proc/config.gz 2>/dev/null | zcat | grep CONFIG_CRYPTO_USER_API_AEAD
# 或
grep CONFIG_CRYPTO_USER_API_AEAD /boot/config-$(uname -r) 2>/dev/null
# 5. Ubuntu/Debian 安全更新检查
apt list --upgradable 2>/dev/null | grep -E 'linux-image|linux-generic|linux-base'
# 6. RHEL/Fedora 安全更新检查
dnf updateinfo list --cves 2>/dev/null | grep CVE-2026-31431
# 7. 查看已安装的内核版本(多版本共存时)
dpkg -l | grep linux-image # Debian/Ubuntu
# 或
rpm -qa | grep kernel # RHEL/Fedora
五、修复方案:多层次的防御策略
5.1 首选方案:升级内核
最根本的修复方式是升级到发行版官方发布的包含 CVE-2026-31431 修复补丁的内核版本。
Ubuntu / Debian:
# 更新软件包列表
sudo apt update
# 查看可用的内核更新
apt list --upgradable | grep -E 'linux-image|linux-generic|linux-base'
# 执行完整升级(会同时升级所有软件包)
sudo apt full-upgrade -y
# 如果只想升级内核
sudo apt install --only-upgrade linux-image-$(uname -r) -y
RHEL / Rocky / AlmaLinux / Fedora:
sudo dnf check-update
sudo dnf update kernel -y
# 或升级所有软件包
sudo dnf update -y
SUSE:
sudo zypper patch
# 或指定 CVE
sudo zypper patch --cve=CVE-2026-31431
升级后必须重启才能加载新内核:
sudo reboot
重启后验证:
# 确认运行的是新内核
uname -r
# 确认没有已知的高危漏洞
cat /proc/version
5.2 临时规避:禁用 algif_aead 模块
如果无法立即重启或升级内核(生产环境常见),可以先禁用 algif_aead 模块来阻止攻击面:
# 创建模块黑名单配置
echo "install algif_aead /bin/true" | sudo tee /etc/modprobe.d/disable-algif-aead.conf
# 立即卸载已加载的模块(如果可以的话)
sudo rmmod algif_aead 2>/dev/null || echo "模块未加载或无法卸载(正常,如果模块没有显式加载)"
# 验证:检查模块是否在黑名单中
cat /etc/modprobe.d/disable-algif-aead.conf
# 再次检查 lsmod 是否还有 algif_aead
lsmod | grep algif_aead || echo "algif_aead 不在已加载模块列表中"
注意:即使模块不在
lsmod输出中,如果内核编译时将CONFIG_CRYPTO_USER_API_AEAD编译为内置(y 而不是 m),用户仍可能通过modprobe动态加载它。/etc/modprobe.d/disable-algif-aead.conf中的install指令可以确保即使有人尝试加载模块,也会被替换为true(空操作)。
5.3 容器/沙箱环境的特殊处理
Kubernetes / Docker 节点:
如果你的容器运行在共享内核的主机上(这是 Docker 的默认模式),容器内的漏洞利用同样可以影响宿主机——因为内核漏洞的利用不依赖 namespace 隔离。
容器内普通用户
↓ (通过 /proc 或 socket)
宿主机内核 ← CVE-2026-31431 在这里被利用
↓
容器逃逸 + root 提权
缓解措施:
- 确保宿主机内核已升级到修复版本
- 考虑使用 gVisor 或 Kata Containers 等内核隔离方案(但这些方案本身也有攻击面)
- 在 Kubernetes 中使用 Security Context 限制容器 capabilities:
securityContext:
# 移除 CAP_SYS_ADMIN 可以阻止 splice() 在某些路径上的使用
capabilities:
drop:
- CAP_SYS_ADMIN
- 启用 seccomp 过滤,阻止
socket(AF_ALG, ...)调用:
{
"names": ["socket"],
"action": "SCMP_ACT_ERRNO"
}
但注意:这可能影响需要使用 AF_ALG 的合法应用。
在线代码执行平台 / Notebook 环境:
这类平台是 CVE-2026-31431 的高危场景,因为它们需要执行用户提交的不可信代码:
- Jupyter Notebook 服务器
- 在线评测系统(OJ)
- 代码实验平台
- 沙箱执行环境
紧急措施:
- 在内核层面应用修复或禁用模块
- 如果使用容器隔离,确保容器不以 privileged 模式运行
- 考虑将内核升级为多版本共存,允许在线切换
六、为什么这个漏洞值得警惕:深度反思
6.1 漏洞的"优雅"之处
CVE-2026-31431 之所以在安全社区引起广泛关注,不仅仅因为它的高危评分,更因为它的利用美学:
极简攻击面:不需要复杂的竞争条件,不需要 ROP/JOP 链,不需要喷堆(heap spray),甚至不需要知道目标系统的内核符号表。一个 Python socket 调用 + splice + 精心构造的数据,就能完成提权。
跨架构通用性:同一个漏洞原理,在 x86-64、i386、ARM64、ARMv7 上都能工作。payload 代码量不到 200 字节。
隐蔽性:不修改磁盘文件,page cache 被污染后文件哈希不变,系统日志可能完全不记录任何异常。
确定性:单线程、零竞争,在大多数环境下可以稳定复现。
6.2 对内核安全的警示
这个漏洞暴露了 Linux 内核加密子系统在处理复杂数据路径组合时的脆弱性:
In-place 优化的危险性:性能优化往往引入微妙的状态假设。当这些假设在非预期的数据路径下被触发时,就会产生安全漏洞。
系统调用组合的不可预测性:单独看
splice()是安全的,单独看 AF_ALG 也是安全的,但它们组合在一起时产生了漏洞。这提醒我们:系统调用之间的交互是内核安全研究的重要方向。page cache 的双重语义:page cache 在大多数情况下是"只读的数据来源",但在内核的某些代码路径中,它可能被当作"可写的目标缓冲区"。这种语义混淆是漏洞的根本原因。
6.3 给开发者的建议
作为一线开发者,你可能不会直接修改内核代码,但这个漏洞仍然值得你关注:
了解你的运行环境:知道你的服务器跑的是什么内核版本,发行版的安全更新是否及时。
不要依赖"隔离"作为唯一防线:Docker 容器、Kubernetes pod 都不提供内核隔离。在共享内核的模式下,内核漏洞就是你的容器边界漏洞。
建立漏洞响应机制:CVE-2026-31431 的披露提醒我们,高危内核漏洞可能随时出现。你需要一套机制来:快速评估影响范围 → 决定是否需要紧急停机 → 执行修复升级 → 验证修复效果。
CI/CD 环境的安全加固:CI/CD Runner 往往以较高权限运行构建和测试代码。如果 Runner 执行来自 PR 的不可信代码,这个漏洞可能成为攻击者的入口。
七、总结:漏洞全景图
| 维度 | 内容 |
|---|---|
| CVE 编号 | CVE-2026-31431 |
| 代号 | Copy Fail |
| 漏洞类型 | Linux Kernel 本地权限提升 |
| 影响组件 | algif_aead / AF_ALG / Kernel Crypto API |
| 利用前提 | 本地普通用户账号、可访问 AF_ALG AEAD 接口 |
| 攻击复杂度 | 低(无需竞争条件、零依赖) |
| 影响结果 | 普通用户 → root |
| CVSS 3.1 评分 | 7.8(高危) |
| 影响范围 | 2017-2026 年主流 Linux 发行版内核 |
| 核心原理 | splice() + AF_ALG AEAD in-place 优化 → page cache 可控写入 |
| 写入粒度 | 每次 4 字节(可多次调用覆盖任意位置) |
| 修复方式 | 升级内核 或 禁用 algif_aead 模块 |
| 公开时间 | 2026 年 4 月(Theori 团队披露) |
参考资料:
- 原始漏洞报告:https://copy.fail/
- NVD 详情:https://nvd.nist.gov/vuln/detail/CVE-2026-31431
- 欧盟 CERT 公告:https://cert.europa.eu/publications/security-advisories/2026-005/
- 官方 Exploit 仓库:https://github.com/theori-io/copy-fail-CVE-2026-31431
- Sysdig 技术分析:https://www.sysdig.com/blog/cve-2026-31431-copy-fail-linux-kernel-flaw-lets-local-users-gain-root-in-seconds