本项目分析了 Linux Kernel Copy Fail(CVE-2026-31431) 漏洞的工作原理,并利用公开 PoC 仓库的非破坏性 checker 对比了补丁前后的状态,是一个微型项目。
实际并未执行 setuid 二进制文件篡改或 /etc/passwd 篡改漏洞利用,而是专注于基于临时 testfile 的安全漏洞检测,以及从检测/缓解角度进行的分析。
本项目的目的并非单纯执行漏洞利用,而是理解 Linux 内核漏洞是如何通过内部结构的组合产生的,并从运维角度总结如何确认和应对。
研究范围如下:
漏洞原理分析
↓
PoC 代码结构分析
↓
基于非破坏性 checker 的实践
↓
补丁前后对比
↓
检测/缓解方案整理
本实践中仅执行了 copy-fail-c 仓库中的 vulnerable.c。
| 分类 | 补丁前 | 补丁后 |
|---|---|---|
| OS | Ubuntu 24.04.2 LTS | Ubuntu 24.04.4 LTS |
| Kernel | 6.8.0-53-generic | 6.8.0-134-generic |
| 账户 | 普通用户 client | 普通用户 client |
| checker | vulnerable | vulnerable |
| 测试方式 | 基于临时 testfile 的非破坏性检查 | 同一 checker 重新执行 |
补丁前内核信息:
Linux ubuntu-server 6.8.0-53-generic #55-Ubuntu SMP PREEMPT_DYNAMIC Fri Jan 17 15:37:52 UTC 2025 x86_64 x86_64 x86_64 GNU/Linux
补丁后内核信息:
Linux ubuntu-server 6.8.0-134-generic #134-Ubuntu SMP PREEMPT_DYNAMIC Fri Jun 26 18:43:11 UTC 2026 x86_64 x86_64 x86_64 GNU/Linux
内核包变更摘要:
- linux-image-6.8.0-53-generic 6.8.0-53.55
- linux-image-generic 6.8.0-53.55+1
+ linux-image-6.8.0-134-generic 6.8.0-134.134
+ linux-image-generic 6.8.0-134.134
+ linux-generic 6.8.0-134.134
+ linux-headers-generic 6.8.0-134.134
Copy Fail 漏洞是 Linux 内核的 AF_ALG AEAD 处理路径与 splice() 零拷贝操作结合,导致只读文件的 page cache 可能被错误用作写入目标。
核心组件如下:
漏洞的核心流程如下:
可读取的文件
↓
加载到 Linux page cache
↓
通过 splice() 将 page cache 引用传递给 AF_ALG crypto 路径
↓
AEAD in-place 处理使输入与输出 scatterlist 交织
↓
authencesn 处理过程中产生 4 字节 scratch write
↓
写入点并非独立的输出缓冲区,而是 page cache
↓
发生 page cache 突变
即,splice() 传递 page cache 引用,AEAD in-place 处理将输入与输出绑定在相同路径,authencesn 实际产生 4 字节写入。
实践所用仓库的结构如下:
copy-fail-c/
├── exploit.c
├── exploit-passwd.c
├── vulnerable.c
├── payload.c
├── utils.c
├── utils.h
├── Makefile
└── nolibc/
utils.cutils.c 的核心是 patch_chunk() 系列的 page cache 突变原语。该函数利用 AF_ALG 和 splice() 将目标文件的 page cache 连接到 crypto 处理路径,并在易受攻击的内核中检查 AEAD 处理过程中部分 page cache 是否被覆盖。
vulnerable.cvulnerable.c 不会触碰实际系统文件。它在当前目录创建临时 testfile,并检查该文件的 page cache 是否被篡改。
本项目中仅执行了此文件。
在内核更新前,记录了 OS、内核及包状态。
mkdir -p ~/copyfail-mini/{before,after,logs}
cd ~/copyfail-mini
uname -a | tee before/uname.txt
cat /etc/os-release | tee before/os-release.txt
dpkg -l | grep -E 'linux-image|linux-headers|linux-generic|linux-virtual' | tee before/kernel-package.txt
git clone https://github.com/jihwan77/copy-fail-c.git
cd copy-fail-c
make clean
make vulnerable
本实践未通过默认 make 一并构建漏洞利用二进制文件,仅使用了 vulnerable 目标。
./vulnerable > ../before/vulnerable-output.txt 2>&1
echo $? >> ../before/vulnerable-output.txt
cat ../before/vulnerable-output.txt
补丁前执行结果:

判断:
exit code 100
→ 确认 page cache 突变
→ 补丁前内核中 Copy Fail 原语生效
保存补丁前结果后,执行 Ubuntu 包更新。
sudo apt update
sudo apt full-upgrade -y
sudo reboot
重启后内核变更如下:
Before: 6.8.0-53-generic
After : 6.8.0-134-generic
cd ~/copyfail-mini/copy-fail-c
make clean
make vulnerable
./vulnerable > ../after/vulnerable-output.txt 2>&1
echo "exit_code=$?" >> ../after/vulnerable-output.txt
cat ../after/vulnerable-output.txt
补丁后执行结果:

结果对比:
补丁后 exit_code=2 并不表示“不受影响”。准确来说如下:
AF_ALG 的 authencesn(hmac(sha256),cbc(aes)) template 未注册,
因此 checker 无法直接判定是否受影响
进一步确认,Ubuntu 更新后 algif_aead 模块加载已被阻止。
lsmod | grep -E 'af_alg|algif_aead'
结果:
af_alg 32768 0
algif_aead 未加载。
sudo modprobe algif_aead
结果:
modprobe: ERROR: ../libkmod/libkmod-module.c:1084 command_do() Error running install command '/bin/false' for module algif_aead: retcode 1
modprobe: ERROR: could not insert 'algif_aead': Invalid argument
确认阻止设置:
grep -R "algif_aead" /etc/modprobe.d /lib/modprobe.d 2>/dev/null
结果:
/etc/modprobe.d/disable-algif_aead.conf:# Disable algif_aead module due to CVE-2026-31431 (AKA copy.fail)
/etc/modprobe.d/disable-algif_aead.conf:install algif_aead /bin/false
因此,将补丁后结果解释为以下几点更为准确:
Ubuntu 安全更新后,内核升级至 6.8.0-134-generic,
并应用了基于 kmod 的 algif_aead 模块阻止缓解措施。
因此 copy-fail-c 的 vulnerable checker
无法绑定 PoC 所需的 authencesn(hmac(sha256),cbc(aes)) AF_ALG template,
未进入 page cache 突变阶段。
也就是说,本实践确认的并非“仅内核代码补丁的效果”,而是 Ubuntu 安全更新后,内核升级与 algif_aead 模块阻止缓解措施共同作用,导致同一 PoC 路径无法继续执行。
Copy Fail 能够篡改 page cache 而不直接修改磁盘文件,因此基于文件哈希的检测存在局限。基于系统调用行为的检测至关重要。
本实践使用 auditd 监测以下系统调用:
sudo auditctl -a always,exit -F arch=b64 -S socket -F a0=38 -k copyfail_afalg
sudo auditctl -a always,exit -F arch=b64 -S bind -k copyfail_bind
sudo auditctl -a always,exit -F arch=b64 -S splice -k copyfail_splice
sudo auditctl -a always,exit -F arch=b64 -S sendmsg -k copyfail_sendmsg
socket(AF_ALG)日志中确认了 vulnerable 进程创建 AF_ALG socket。
comm=vulnerable
syscall=socket
success=yes
a0=alg
key=copyfail_afalg
bind() 失败在补丁后/缓解后的环境中,vulnerable 进程尝试绑定 authencesn template 但失败。
comm=vulnerable
syscall=bind
success=no
exit=ENOENT(No such file or directory)
saddr_fam=alg
key=copyfail_bind
这表明在补丁后环境中,PoC 成功执行了 AF_ALG socket 创建,但在 authencesn(hmac(sha256),cbc(aes)) template 绑定阶段失败。
splice() / sendmsg() 日志解读补丁后由于 bind() 阶段已失败,checker 未能进行到 splice() 和 sendmsg() 阶段。因此,在这些系统调用的日志中未观察到 vulnerable 执行流的有效信息。
在生产环境中观察 Copy Fail 类漏洞时,可关注以下行为组合:
本实践通过 auditd 确认了 socket(AF_ALG) 和 bind() 失败事件。
最基本的是应用发行版安全更新。
sudo apt update
sudo apt full-upgrade -y
sudo reboot
本实践更新后,环境变为 Ubuntu 24.04.4 / kernel 6.8.0-134-generic。
algif_aead 模块Ubuntu 更新后,以下设置已被确认:
/etc/modprobe.d/disable-algif_aead.conf
install algif_aead /bin/false
该设置阻止了 algif_aead 模块加载,从而阻止 PoC 所需的 AF_ALG AEAD 路径进入。
一般服务器应用程序直接使用 AF_ALG 的情况可能不多,因此 socket(AF_ALG) 调用可作为检测点使用。
本实践的结果总结如下:
补丁前:
Ubuntu 24.04.2 / kernel 6.8.0-53-generic
vulnerable checker exit code 100
确认 page cache 突变
→ Copy Fail 原语生效
补丁后:
Ubuntu 24.04.4 / kernel 6.8.0-134-generic
vulnerable checker exit code 2
authencesn template 绑定失败
确认 algif_aead 模块阻止设置
→ 同一 PoC 路径未进入 page cache 突变阶段
因此,本项目的结论如下:
在补丁前的内核中,Copy Fail 的 page cache 突变原语确实生效。
随后应用 Ubuntu 安全更新后,内核升级至6.8.0-134-generic,并应用了基于kmod的algif_aead模块阻止设置。
结果导致 PoC 所需的authencesn(hmac(sha256),cbc(aes))AF_ALG template 无法绑定,同一 checker 未进入 page cache 突变阶段。
也就是说,尽管本实践结果尚不能断定“内核代码补丁本身直接阻止了 page cache 突变”,但根据目前日志及结果可以明确的是:Ubuntu 安全更新后,algif_aead 模块阻止缓解措施生效,从而封锁了 PoC 路径。
Ubuntu Security Notice - USN-8226-1: kmod update
https://ubuntu.com/security/notices/USN-8226-1
Ubuntu Blog - Fixes available for CVE-2026-31431 Copy Fail
https://ubuntu.com/blog/copy-fail-vulnerability-fixes-available
copy-fail-c PoC repository
https://github.com/jihwan77/copy-fail-c
通过本项目确认的核心要点如下:
1. Copy Fail 是 AF_ALG、splice()、AEAD in-place、authencesn、page cache 相结合的内核漏洞。
2. 在补丁前 Ubuntu 24.04.2 / kernel 6.8.0-53 环境中,非破坏性 checker 确认了 page cache 突变。
3. 在补丁后 Ubuntu 24.04.4 / kernel 6.8.0-134 环境中,authencesn 绑定阶段失败。
4. 进一步确认 algif_aead 模块加载被 /bin/false 设置阻止。
5. 可通过 auditd 观察 socket(AF_ALG) 及 bind 失败事件。
6. 运维应对措施归纳为:更新内核/安全包、限制 algif_aead、监控 AF_ALG 系统调用、检查 setuid 二进制文件。
| 元素 |
|---|
| 作用 |
|---|
| Linux page cache | 将磁盘文件内容缓存到 RAM 的内核机制 |
splice() | 不将数据复制到用户空间,而是在内核内部通过引用连接的零拷贝系统调用 |
AF_ALG | 允许用户空间像使用 socket 一样使用 Linux 内核 crypto API 的接口 |
| AEAD in-place 处理 | 不将输入缓冲区和输出缓冲区分开,而是在同一缓冲区中处理的优化 |
authencesn | 在 AEAD 处理过程中产生 4 字节 scratch write 的 crypto template |
| 文件 | 作用 | 本实践中是否使用 |
|---|
utils.c, utils.h | 基于 AF_ALG/splice 的 page cache 突变原语实现 | 用于分析及执行 vulnerable |
vulnerable.c | 基于临时 testfile 的非破坏性漏洞检测工具 | 已执行 |
exploit.c | setuid root 二进制文件 page cache 篡改变体 | 未执行 |
exploit-passwd.c | /etc/passwd page cache 篡改变体 | 未执行 |
payload.c | 以 root 权限执行的 payload | 未执行 |
Makefile | 构建自动化 | 仅使用 vulnerable 目标 |
nolibc/ | 用于构建小型静态 ELF payload 的轻量级 libc 替代代码 | 仅分析 |
| 项目 | 补丁前 | 补丁后 |
|---|
| Kernel | 6.8.0-53-generic | 6.8.0-134-generic |
| Checker 结果 | VULNERABLE | authencesn template not registered |
| Exit Code | 100 | 2 |
| Page cache 突变 | 已确认 | checker 未进入突变阶段 |
| 解读 | Copy Fail 原语生效 | PoC 所需的 AEAD/authencesn 路径进入失败 |
| 检测目标 | 含义 |
|---|
socket(AF_ALG, ...) | 尝试使用内核 crypto API |
bind() with authencesn | 尝试使用 AEAD/authencesn crypto template |
splice() | 将文件 page cache 引用传递到内核内部路径 |
sendmsg() / recvmsg() | 执行 AF_ALG crypto 请求 |
| setuid 二进制文件执行 | 权限提升兑现可能性 |