
CVE-2026-31431 (Copy Fail) novel exploit: live code corruption via page cache. Overwrites libc exit() code through MAP_PRIVATE page sharing — affects ALL running processes.
A novel exploitation technique for CVE-2026-31431 ("Copy Fail") that corrupts executable code of running processes through the Linux kernel's page cache, achieving root privilege escalation.
All published exploits for this CVE corrupt data files — modifying /etc/passwd to change root's UID, or patching setuid binaries on disk. This exploit does something fundamentally different: it corrupts live executable code in memory through the kernel's page cache mechanism.
| Published exploits | This exploit | |
|---|---|---|
| Target | Data files (/etc/passwd, /usr/bin/su) | Executable code (libc .text section) |
| Mechanism | File content parsed by programs | Code pages directly executed by CPU |
| Scope | Single file | ALL processes mapping libc |
| Disk change | Yes (file content modified) | No (only page cache in memory) |
| Detection | File integrity monitoring | Invisible to filesystem checks |
When Linux maps a shared library with MAP_PRIVATE, it doesn't immediately copy the file pages. Instead, the process's page table entries point directly to the page cache physical pages. The copy only happens on write (copy-on-write). For code pages (.text), processes never write to them — so they remain shared with page cache forever.
Process A (bash) Process B (su) Page Cache (libc)
┌──────┐ ┌──────┐ ┌──────────┐
│ PTE │───────────>│ │ │ exit(): │
│ │ │ PTE │───────────>│ endbr64 │
└──────┘ └──────┘ │ push rax │
MAP_PRIVATE MAP_PRIVATE │ ... │
(clean page) (clean page) └──────────┘
↑
Copy Fail writes here!
CVE-2026-31431 gives us a controlled 4-byte write to any readable file's page cache. By corrupting libc's code pages, we modify the instructions that every process executes.
on_exit() function location in libc's page cache — 10 writes of 4 bytes eachexit() to jump to our shellcode — 1 write of 4 bytesexit() (virtually every program) executes our shellcodeThe shellcode performs setuid(0) → setgid(0) → execve("/bin/sh"), giving a root shell.
crypto/algif_aead.c — the 2017 in-place optimization (72548b093ee3) allows splice() to feed page cache pages into AEAD decrypt. The authencesn algorithm's ESN rearrangement writes 4 scratch bytes back to the source scatterlist, corrupting the spliced file's page cache.# Compile
gcc -o exploit exploit.c
# Run as unprivileged user
./exploit /lib/x86_64-linux-gnu/libc-2.31.so
# Trigger — run any program (it calls exit())
su -c id
# uid=0(root) gid=0(root) groups=0(root)
process 'id' launched '/bin/sh'exploit.c — Full exploit with shellcode injectioncopyfail_test.c — Primitive verification (tests 4-byte write)72548b093ee3)This tool is provided for authorized security research and educational purposes only. Do not use against systems you do not own or have explicit permission to test.
Dirty Frag disclosed two more page-cache write variants in the same bug class:
esp4/esp6): Same authencesn sink as Copy Fail, reached via IPsec ESP-in-UDP. Requires user namespaces. 4-byte write.rxrpc/rxkad): pcbc(fcrypt) in-place decrypt on splice-pinned page. No namespaces needed. 8-byte write.The live code corruption technique in this repo works with any of these page-cache write primitives — just replace the write4() function with the ESP or RxRPC trigger. The technique is primitive-agnostic.