
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:

Comparación de resultados:
| Elemento | Antes del parche | Después del parche |
|---|---|---|
| Kernel | 6.8.0-53-generic | 6.8.0-134-generic |
| Resultado del checker | VULNERABLE | authencesn template not registered |
| Código de salida | 100 | 2 |
| Mutación de caché de páginas | Confirmada | El checker no pudo llegar a la etapa de mutación |
| Interpretación | La primitiva Copy Fail funciona | Falló la entrada a la ruta AEAD/authencesn requerida por el PoC |
Después del parche, exit_code=2 no significa simplemente "no vulnerable". Exactamente es:
La plantilla authencesn (hmac(sha256),cbc(aes)) de AF_ALG no está registrada,
por lo que el checker no pudo determinar directamente la vulnerabilidad.
Una verificación adicional mostró que después de la actualización de Ubuntu, la carga del módulo algif_aead estaba bloqueada.
lsmod | grep -E 'af_alg|algif_aead'
Resultado:
af_alg 32768 0
algif_aead no estaba cargado.
sudo modprobe algif_aead
Resultado:
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
Verificación de la configuración de bloqueo:
grep -R "algif_aead" /etc/modprobe.d /lib/modprobe.d 2>/dev/null
Resultado:
/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
Por lo tanto, el resultado después del parche se interpreta con mayor precisión de la siguiente manera:
Después de la actualización de seguridad de Ubuntu, el kernel cambió a 6.8.0-134-generic,
y se aplicó una mitigación basada en kmod que bloquea el módulo algif_aead.
Como resultado, el checker vulnerable de copy-fail-c no pudo enlazar (bind) a la plantilla AF_ALG
authencesn(hmac(sha256),cbc(aes)) requerida por el PoC,
y no se avanzó a la etapa de mutación de la caché de páginas.
Es decir, lo que se verificó en esta práctica no es solo el "efecto del parche de código del kernel", sino que después de la actualización de seguridad de Ubuntu, se aplicaron la actualización del kernel y la mitigación de bloqueo del módulo algif_aead, lo que impidió que la misma ruta del PoC progresara.
Copy Fail puede modificar la caché de páginas sin alterar directamente los archivos de disco, por lo que la detección basada únicamente en hashes de archivos tiene limitaciones. Por lo tanto, es importante la detección basada en el comportamiento de las llamadas al sistema.
En esta práctica, se observaron las siguientes llamadas al sistema usando 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)En los registros se confirmó que el proceso vulnerable creó un socket AF_ALG.
comm=vulnerable
syscall=socket
success=yes
a0=alg
key=copyfail_afalg
bind()En el entorno posterior al parche/mitigación, el proceso vulnerable intentó enlazar a la plantilla authencesn, pero falló.
comm=vulnerable
syscall=bind
success=no
exit=ENOENT(No such file or directory)
saddr_fam=alg
key=copyfail_bind
Esto indica que, en el entorno posterior al parche, el PoC pudo crear el socket AF_ALG, pero falló en la etapa de enlace (bind) a la plantilla authencesn(hmac(sha256),cbc(aes)).
splice() / sendmsg()Después del parche, al fallar en la etapa bind(), el checker no pudo avanzar a las etapas de splice() y sendmsg(). Por lo tanto, en los registros de esas llamadas al sistema no se observó un flujo significativo de vulnerable.
En un entorno operativo, para observar vulnerabilidades del tipo Copy Fail, se puede buscar la siguiente combinación de comportamientos:
| Objetivo de detección | Significado |
|---|---|
socket(AF_ALG, ...) | Intento de uso de la API criptográfica del kernel |
bind() con authencesn | Intento de uso de la plantilla criptográfica AEAD/authencesn |
splice() | Transferencia de referencia de caché de páginas a una ruta interna del kernel |
sendmsg() / recvmsg() | Ejecución de solicitud criptográfica AF_ALG |
| Ejecución de binario setuid | Posibilidad de cashout de escalada de privilegios |
En esta práctica, se verificaron los eventos de socket(AF_ALG) y fallo de bind() mediante auditd.
La respuesta más básica es aplicar las actualizaciones de seguridad de la distribución.
sudo apt update
sudo apt full-upgrade -y
sudo reboot
En esta práctica, después de la actualización, el entorno cambió a Ubuntu 24.04.4 / kernel 6.8.0-134-generic.
algif_aeadDespués de la actualización de Ubuntu, se verificó la siguiente configuración:
/etc/modprobe.d/disable-algif_aead.conf
install algif_aead /bin/false
Esta configuración bloquea la carga del módulo algif_aead, impidiendo la entrada a la ruta AF_ALG AEAD requerida por el PoC.
En aplicaciones de servidor típicas, el uso directo de AF_ALG puede no ser común, por lo que las llamadas a socket(AF_ALG) pueden ser un punto de detección.
Los resultados de esta práctica se pueden resumir de la siguiente manera:
Antes del parche:
Ubuntu 24.04.2 / kernel 6.8.0-53-generic
código de salida del checker vulnerable: 100
mutación de caché de páginas confirmada
→ La primitiva Copy Fail funciona
Después del parche:
Ubuntu 24.04.4 / kernel 6.8.0-134-generic
código de salida del checker vulnerable: 2
fallo en el enlace de la plantilla authencesn
configuración de bloqueo del módulo algif_aead confirmada
→ La misma ruta del PoC no avanzó a la etapa de mutación de caché de páginas
Por lo tanto, la conclusión de este proyecto es la siguiente:
En el kernel anterior al parche, la primitiva de mutación de caché de páginas de Copy Fail realmente funcionaba.
Luego de aplicar la actualización de seguridad de Ubuntu, el kernel cambió a6.8.0-134-genericy se aplicó una configuración de bloqueo del móduloalgif_aead, aparentemente basada enkmod.
Como resultado, el checker no pudo enlazar a la plantilla AF_ALGauthencesn(hmac(sha256),cbc(aes))requerida por el PoC, por lo que no se avanzó a la etapa de mutación de la caché de páginas.
Es decir, en los resultados de esta práctica no se puede afirmar que "el parche de código del kernel por sí solo bloqueó directamente la mutación de la caché de páginas", pero lo que se puede afirmar con certeza basándose en los registros y resultados hasta ahora es que después de la actualización de seguridad de Ubuntu, se aplicó una mitigación de bloqueo del módulo algif_aead que bloqueó la ruta del PoC.
Aviso de seguridad de Ubuntu - USN-8226-1: actualización de kmod
https://ubuntu.com/security/notices/USN-8226-1
Blog de Ubuntu - Correcciones disponibles para CVE-2026-31431 Copy Fail
https://ubuntu.com/blog/copy-fail-vulnerability-fixes-available
Repositorio PoC copy-fail-c
https://github.com/jihwan77/copy-fail-c
Los puntos clave verificados a través de este proyecto son los siguientes:
1. Copy Fail es una vulnerabilidad del kernel que combina AF_ALG, splice(), AEAD in-place, authencesn y la caché de páginas.
2. En el entorno anterior al parche (Ubuntu 24.04.2 / kernel 6.8.0-53), el checker no destructivo confirmó la mutación de la caché de páginas.
3. En el entorno posterior al parche (Ubuntu 24.04.4 / kernel 6.8.0-134), falló en la etapa de enlace de authencesn.
4. Se confirmó que la carga del módulo algif_aead estaba bloqueada con la configuración /bin/false.
5. Se pudieron observar eventos de socket(AF_ALG) y fallo de bind mediante auditd.
6. Las medidas de respuesta operativas se pueden resumir en: actualización del kernel/paquetes de seguridad, restricción de algif_aead, monitoreo de llamadas al sistema AF_ALG y revisión de binarios setuid.