
AF_ALG/splice 기반 Linux Page Cache 변조 취약점 분석 및 대응 실습
This project analyzes the operational principle of the Linux Kernel Copy Fail (CVE-2026-31431) vulnerability and compares the pre-patch and post-patch state using the non-destructive checker from the public PoC repository.
It does not perform actual setuid binary modification or /etc/passwd modification exploits, but focuses on safely checking vulnerability based on a temporary testfile and analyzing detection/mitigation perspectives.
The goal of this project is not simply to run an exploit, but to understand the combination of internal structures that cause a Linux kernel vulnerability and to organize how to identify and respond from an operational perspective.
The scope of work is as follows:
Vulnerability principle analysis
↓
PoC code structure analysis
↓
Non-destructive checker-based practice
↓
Pre-patch vs. post-patch comparison
↓
Detection/mitigation measures summary
In this practice, only vulnerable.c from the copy-fail-c repository was executed.
Pre-patch kernel info:
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
Post-patch kernel info:
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
Kernel package change summary:
- 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 is a vulnerability that occurs when the Linux kernel's AF_ALG AEAD processing path and splice() zero-copy behavior combine, causing the page cache of a read-only file to be used as an incorrect write target.
The core components are as follows:
The core flow of the vulnerability is as follows:
Readable file
↓
Loaded into Linux page cache
↓
Page cache reference passed to AF_ALG crypto path via splice()
↓
Input and output scatterlists become entangled due to AEAD in-place processing
↓
4-byte scratch write occurs during authencesn processing
↓
Write occurs not to a separate output buffer but to the page cache
↓
Page cache mutation occurs
In other words, splice() passes a page cache reference, AEAD in-place processing ties input and output through the same path, and authencesn causes the actual 4-byte write.
The repository structure used in the practice is as follows:
copy-fail-c/
├── exploit.c
├── exploit-passwd.c
├── vulnerable.c
├── payload.c
├── utils.c
├── utils.h
├── Makefile
└── nolibc/
utils.cThe core of utils.c is the patch_chunk() family of page cache mutation primitives. This function uses AF_ALG and splice() to connect the page cache of the target file to the crypto processing path, and on vulnerable kernels checks whether part of the page cache gets overwritten during AEAD processing.
vulnerable.cvulnerable.c does not touch actual system files. It creates a temporary testfile in the current directory and checks whether its page cache is mutated.
In this project, only this file was executed.
Before performing the kernel update, the OS, kernel, and package states were recorded.
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
In this practice, the default make was not used to build exploit binaries together; only the vulnerable target was used.
./vulnerable > ../before/vulnerable-output.txt 2>&1
echo $? >> ../before/vulnerable-output.txt
cat ../before/vulnerable-output.txt
Pre-patch execution result:

Judgment:
exit code 100
→ page cache mutation confirmed
→ Copy Fail primitive confirmed in pre-patch kernel
After saving the pre-patch results, Ubuntu package update was performed.
sudo apt update
sudo apt full-upgrade -y
sudo reboot
After reboot, the kernel changed as follows:
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
Post-patch execution result:

Result comparison:
The post-patch exit_code=2 does not simply mean “not vulnerable.” Precisely, it means:
The authencesn(hmac(sha256),cbc(aes)) template of AF_ALG is not registered,
so the checker could not directly determine vulnerability.
Upon further checking, the algif_aead module load was blocked after the Ubuntu update.
lsmod | grep -E 'af_alg|algif_aead'
Result:
af_alg 32768 0
algif_aead was not loaded.
sudo modprobe algif_aead
Result:
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
Block configuration check:
grep -R "algif_aead" /etc/modprobe.d /lib/modprobe.d 2>/dev/null
Result:
/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
Therefore, the post-patch result should be interpreted as follows:
After the Ubuntu security update, the kernel changed to 6.8.0-134-generic,
and a kmod-based mitigation blocking the algif_aead module was applied.
As a result, the vulnerable checker from copy-fail-c
could not bind to the authencesn(hmac(sha256),cbc(aes)) AF_ALG template required by the PoC,
and the page cache mutation step was not reached.
In other words, what we confirmed in this practice is not “the effect of the kernel code patch alone,” but rather that after the Ubuntu security update, the kernel update and the algif_aead module block mitigation were applied, preventing the same PoC path from proceeding.
Copy Fail can modify the page cache without directly modifying disk files, so file hash-based detection alone has limitations. Therefore, syscall behavior-based detection is important.
In this practice, the following syscalls were observed using 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) DetectionLogs confirmed that the vulnerable process created an AF_ALG socket.
comm=vulnerable
syscall=socket
success=yes
a0=alg
key=copyfail_afalg
bind() Failure DetectionIn the post-patch/mitigation environment, the vulnerable process attempted to bind to the authencesn template but failed.
comm=vulnerable
syscall=bind
success=no
exit=ENOENT(No such file or directory)
saddr_fam=alg
key=copyfail_bind
This means that in the post-patch environment, the PoC performed up to creating the AF_ALG socket, but failed at the authencesn(hmac(sha256),cbc(aes)) template bind step.
splice() / sendmsg() Log InterpretationSince the bind() step failed after the patch, the checker did not proceed to the splice() and sendmsg() steps. Therefore, no meaningful vulnerable execution flow was observed in the corresponding syscall logs.
When observing Copy Fail-type vulnerabilities in an operational environment, the following combination of behaviors can be seen:
In this practice, socket(AF_ALG) and bind() failure events were confirmed via auditd.
The most basic response is to apply distribution security updates.
sudo apt update
sudo apt full-upgrade -y
sudo reboot
In this practice, after the update, the environment changed to Ubuntu 24.04.4 / kernel 6.8.0-134-generic.
algif_aead ModuleAfter the Ubuntu update, the following configuration was confirmed:
/etc/modprobe.d/disable-algif_aead.conf
install algif_aead /bin/false
This configuration blocks the loading of the algif_aead module, preventing PoC from entering the required AF_ALG AEAD path.
Since direct AF_ALG usage is uncommon in typical server applications, socket(AF_ALG) calls can serve as a detection point.
The results of this practice can be summarized as follows:
Pre-patch:
Ubuntu 24.04.2 / kernel 6.8.0-53-generic
vulnerable checker exit code 100
page cache mutation confirmed
→ Copy Fail primitive confirmed working
Post-patch:
Ubuntu 24.04.4 / kernel 6.8.0-134-generic
vulnerable checker exit code 2
authencesn template bind failure
algif_aead module block configuration confirmed
→ Same PoC path did not proceed to page cache mutation step
Therefore, the conclusion of this project is:
In the pre-patch kernel, the Copy Fail page cache mutation primitive actually worked.
After applying the Ubuntu security update, the kernel changed to6.8.0-134-generic, and a kmod-basedalgif_aeadmodule block configuration was applied.
As a result, the PoC could not bind to theauthencesn(hmac(sha256),cbc(aes))AF_ALG template, and the same checker did not proceed to the page cache mutation step.
In other words, based on this practice, we cannot claim that “the kernel code patch itself directly blocked page cache mutation,” but what can be said with certainty from the logs and results so far is that after the Ubuntu security update, the algif_aead module block mitigation was applied, blocking the PoC path.
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
The key takeaways from this project are:
1. Copy Fail is a kernel vulnerability combining AF_ALG, splice(), AEAD in-place, authencesn, and page cache.
2. In the pre-patch Ubuntu 24.04.2 / kernel 6.8.0-53 environment, the non-destructive checker confirmed page cache mutation.
3. In the post-patch Ubuntu 24.04.4 / kernel 6.8.0-134 environment, it failed at the authencesn bind step.
4. Further checking revealed that the algif_aead module load was blocked via /bin/false configuration.
5. socket(AF_ALG) and bind failure events could be observed via auditd.
6. Operational responses can be summarized as: kernel/security package updates, algif_aead restriction, AF_ALG syscall monitoring, and setuid binary inspection.
| Category | Pre-patch | Post-patch |
|---|
| OS | Ubuntu 24.04.2 LTS | Ubuntu 24.04.4 LTS |
| Kernel | 6.8.0-53-generic | 6.8.0-134-generic |
| Account | Normal user client | Normal user client |
| checker | vulnerable | vulnerable |
| Test method | Non-destructive check based on temporary testfile | Same checker re-executed |
| Element | Role |
|---|
| Linux page cache | Kernel mechanism that caches disk file contents in RAM |
splice() | A zero-copy syscall that connects data via references within the kernel without copying to user space |
AF_ALG | An interface that allows user space to use the Linux kernel crypto API like a socket |
| AEAD in-place processing | Optimization that processes input and output in the same buffer instead of separate buffers |
authencesn | Crypto template that generates a 4-byte scratch write during AEAD processing |
| File | Role | Usage in this practice |
|---|
utils.c, utils.h | Implementation of AF_ALG/splice based page cache mutation primitive | Used for analysis and executing vulnerable |
vulnerable.c | Non-destructive vulnerability check tool based on temporary testfile | Executed |
exploit.c | setuid root binary page cache modification variant | Not executed |
exploit-passwd.c | /etc/passwd page cache modification variant | Not executed |
payload.c | Payload to be executed with root privileges | Not executed |
Makefile | Build automation | Only vulnerable target used |
nolibc/ | Lightweight libc replacement for building small static ELF payloads | Only analyzed |
| Item | Pre-patch | Post-patch |
|---|
| Kernel | 6.8.0-53-generic | 6.8.0-134-generic |
| Checker result | VULNERABLE | authencesn template not registered |
| Exit Code | 100 | 2 |
| Page cache mutation | Confirmed | Checker did not reach mutation step |
| Interpretation | Copy Fail primitive working | PoC required AEAD/authencesn path entry failed |
| Detection target | Meaning |
|---|
socket(AF_ALG, ...) | Attempt to use kernel crypto API |
bind() with authencesn | Attempt to use AEAD/authencesn crypto template |
splice() | Pass file page cache reference into kernel internal path |
sendmsg() / recvmsg() | Perform AF_ALG crypto request |
| setuid binary execution | Potential privilege escalation cashout |