
Análisis y mitigación de la vulnerabilidad Copy Fail del kernel de Linux (CVE-2026-31431) que explota la mutación de la caché de páginas AF_ALG/splice, con verificador de PoC, reglas de detección de auditd y verificación de actualización del kernel.
Este proyecto es un miniproyecto que analiza el principio de funcionamiento de la vulnerabilidad Copy Fail (CVE-2026-31431) del kernel de Linux y compara el estado antes y después del parche utilizando el checker no destructivo del repositorio PoC público.
No se realiza la modificación real de binarios setuid ni la explotación de /etc/passwd. El enfoque está en la verificación segura de la vulnerabilidad basada en un testfile temporal y en el análisis desde la perspectiva de detección/mitigación.
El objetivo de este proyecto no es simplemente ejecutar un exploit, sino comprender cómo surge una vulnerabilidad del kernel de Linux a partir de la combinación de estructuras internas y documentar cómo se puede verificar y responder desde una perspectiva operativa.
El alcance del trabajo es el siguiente:
Análisis del principio de la vulnerabilidad
↓
Análisis de la estructura del código PoC
↓
Práctica basada en checker no destructivo
↓
Comparación antes y después del parche
↓
Documentación de medidas de detección/mitigación
En esta práctica, solo se ejecutó vulnerable.c del repositorio copy-fail-c.
| Elemento | Antes del parche | Después del parche |
|---|---|---|
| SO | Ubuntu 24.04.2 LTS | Ubuntu 24.04.4 LTS |
| Kernel | 6.8.0-53-generic | 6.8.0-134-generic |
| Cuenta | Usuario normal client | Usuario normal client |
| Checker | vulnerable | vulnerable |
| Método de prueba | Verificación no destructiva basada en testfile temporal | Re-ejecución del mismo checker |
Información del kernel antes del parche:
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
Información del kernel después del parche:
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
Resumen de cambios en paquetes del kernel:
- 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 es una vulnerabilidad que surge cuando la ruta de procesamiento AEAD de AF_ALG en el kernel de Linux se combina con la operación zero-copy de splice(), permitiendo que la caché de páginas de un archivo de solo lectura se utilice como destino de escritura incorrecto.
Los componentes clave son los siguientes:
| Elemento | Rol |
|---|---|
| Caché de páginas de Linux | Mecanismo del kernel que almacena en caché el contenido del disco en RAM |
splice() | Llamada al sistema zero-copy que enlaza datos mediante referencias dentro del kernel sin copiarlos al espacio de usuario |
AF_ALG | Interfaz que permite usar la API criptográfica del kernel de Linux como un socket desde el espacio de usuario |
| Procesamiento in-place de AEAD | Optimización que procesa el búfer de entrada y salida en el mismo búfer, sin separarlos |
authencesn | Plantilla criptográfica que genera una escritura scratch de 4 bytes durante el procesamiento AEAD |
El flujo central de la vulnerabilidad es el siguiente:
Archivo legible
↓
Se carga en la caché de páginas de Linux
↓
Se pasa una referencia de la caché de páginas a la ruta criptográfica AF_ALG mediante splice()
↓
El procesamiento in-place de AEAD entrelaza las listas dispersas (scatterlist) de entrada y salida
↓
Se produce una escritura scratch de 4 bytes durante el procesamiento de authencesn
↓
La escritura no se realiza en un búfer de salida separado, sino en la caché de páginas
↓
Se produce una mutación de la caché de páginas
Es decir, splice() transmite una referencia de la caché de páginas, el procesamiento in-place de AEAD entrelaza la entrada y la salida por la misma ruta, y authencesn es el responsable de generar la escritura real de 4 bytes.
La estructura del repositorio utilizado en la práctica es la siguiente:
copy-fail-c/
├── exploit.c
├── exploit-passwd.c
├── vulnerable.c
├── payload.c
├── utils.c
├── utils.h
├── Makefile
└── nolibc/
| Archivo | Rol | Uso en esta práctica |
|---|---|---|
utils.c, utils.h | Implementación de la primitiva de mutación de caché de páginas basada en AF_ALG/splice | Utilizado para análisis y ejecución de vulnerable |
vulnerable.c | Herramienta de verificación no destructiva de vulnerabilidad basada en testfile temporal | Ejecutado |
exploit.c | Variante de modificación de caché de páginas de binario setuid root | No ejecutado |
exploit-passwd.c | Variante de modificación de caché de páginas de /etc/passwd | No ejecutado |
payload.c | Payload que se ejecutaría con privilegios root | No ejecutado |
Makefile | Automatización de compilación | Solo se usó el target vulnerable |
nolibc/ | Código ligero alternativo a libc para construir pequeños ELF estáticos | Solo análisis |
utils.cEl núcleo de utils.c es la primitiva de mutación de caché de páginas de la familia patch_chunk(). Esta función utiliza AF_ALG y splice() para conectar la caché de páginas del archivo objetivo a la ruta de procesamiento criptográfico, y en kernels vulnerables verifica si una parte de la caché de páginas se sobrescribe durante el procesamiento AEAD.
vulnerable.cvulnerable.c no toca archivos reales del sistema. Crea un testfile temporal en el directorio actual y verifica si la caché de páginas de ese archivo se modifica.
En este proyecto, solo se ejecutó este archivo.
Antes de realizar la actualización del kernel, se registró el estado del SO, kernel y paquetes.
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
En esta práctica, no se compilaron los binarios de exploit con make por defecto; solo se utilizó el target vulnerable.
./vulnerable > ../before/vulnerable-output.txt 2>&1
echo $? >> ../before/vulnerable-output.txt
cat ../before/vulnerable-output.txt
Resultado de la ejecución antes del parche:

Juicio:
código de salida 100
→ mutación de caché de páginas confirmada
→ la primitiva Copy Fail funciona en el kernel anterior al parche
Después de guardar los resultados anteriores al parche, se realizó la actualización de paquetes de Ubuntu.
sudo apt update
sudo apt full-upgrade -y
sudo reboot
Después del reinicio, el kernel cambió a:
Antes: 6.8.0-53-generic
Después: 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
Resultado de la ejecución después del parche: