
Analyse et atténuation de la vulnérabilité Copy Fail du noyau Linux (CVE-2026-31431) exploitant la mutation du cache de pages AF_ALG/splice, avec un vérificateur de preuve de concept (PoC), des règles de détection auditd et une vérification de mise à jour du noyau.
Ce projet est un mini-projet qui analyse le principe de fonctionnement de la vulnérabilité Copy Fail (CVE-2026-31431) du noyau Linux et compare l’état avant et après le patch à l’aide du checker non destructif du dépôt PoC public.
Aucun exploit réel de modification de binaires setuid ou de /etc/passwd n’est effectué ; l’accent est mis sur la vérification sécurisée de la vulnérabilité basée sur un testfile temporaire et sur l’analyse du point de vue de la détection et de l’atténuation.
L’objectif de ce projet n’est pas simplement d’exécuter un exploit, mais de comprendre comment une vulnérabilité du noyau Linux se produit par la combinaison de structures internes et de déterminer comment la vérifier et y répondre d’un point de vue opérationnel.
Le périmètre est le suivant :
Analyse du principe de la vulnérabilité
↓
Analyse de la structure du code PoC
↓
Exercice pratique basé sur un checker non destructif
↓
Comparaison avant et après le patch
↓
Synthèse des mesures de détection/atténuation
Dans cet exercice, seul vulnerable.c du dépôt copy-fail-c a été exécuté.
| Catégorie | Avant le patch | Après le patch |
|---|---|---|
| OS | Ubuntu 24.04.2 LTS | Ubuntu 24.04.4 LTS |
| Noyau | 6.8.0-53-generic | 6.8.0-134-generic |
| Compte | Utilisateur normal client | Utilisateur normal client |
| Checker | vulnerable | vulnerable |
| Méthode de test | Vérification non destructive basée sur testfile temporaire | Réexécution du même checker |
Informations sur le noyau avant le patch :
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
Informations sur le noyau après le patch :
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
Résumé des modifications des paquets du noyau :
- 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 est une vulnérabilité qui survient lorsque le chemin de traitement AEAD de AF_ALG du noyau Linux est combiné avec le comportement zero-copy de splice(), permettant au cache de pages d’un fichier en lecture seule d’être utilisé abusivement comme cible d’écriture.
Les composants clés sont les suivants :
| Élément | Rôle |
|---|---|
| Cache de pages Linux | Mécanisme du noyau qui met en cache le contenu des fichiers disque dans la RAM |
splice() | Appel système zero-copy qui relie des données par référence à l’intérieur du noyau sans les copier dans l’espace utilisateur |
AF_ALG | Interface permettant d’utiliser l’API crypto du noyau Linux comme une socket depuis l’espace utilisateur |
| Traitement AEAD in-place | Optimisation qui traite les buffers d’entrée et de sortie dans le même buffer au lieu de les séparer |
authencesn | Template crypto qui génère une écriture scratch de 4 octets pendant le traitement AEAD |
Le flux principal de la vulnérabilité est le suivant :
Fichier lisible
↓
Chargé dans le cache de pages Linux
↓
Référence du cache de pages transmise au chemin crypto AF_ALG via splice()
↓
Le traitement AEAD in-place lie les scatterlists d’entrée et de sortie
↓
Écriture scratch de 4 octets lors du traitement authencesn
↓
L’écriture se produit non pas dans un buffer de sortie séparé, mais dans le cache de pages
↓
Mutation du cache de pages
Autrement dit, splice() transmet une référence au cache de pages, le traitement AEAD in-place lie l’entrée et la sortie sur le même chemin, et authencesn provoque effectivement une écriture de 4 octets.
La structure du dépôt utilisé pour l’exercice est la suivante :
copy-fail-c/
├── exploit.c
├── exploit-passwd.c
├── vulnerable.c
├── payload.c
├── utils.c
├── utils.h
├── Makefile
└── nolibc/
| Fichier | Rôle | Utilisation dans cet exercice |
|---|---|---|
utils.c, utils.h | Implémentation de la primitive de mutation du cache de pages basée sur AF_ALG/splice | Utilisé pour l’analyse et l’exécution de vulnerable |
vulnerable.c | Outil non destructif de vérification de vulnérabilité basé sur un testfile temporaire | Exécuté |
exploit.c | Variante de modification du cache de pages d’un binaire setuid root | Non exécuté |
exploit-passwd.c | Variante de modification du cache de pages de /etc/passwd | Non exécuté |
payload.c | Payload exécuté avec les privilèges root | Non exécuté |
Makefile | Automatisation de la construction | Utilisé uniquement pour la cible vulnerable |
nolibc/ | Code de remplacement de la libc légère pour construire de petits ELF statiques | Analyse uniquement |
utils.cLe cœur de utils.c est la primitive de mutation du cache de pages de la famille patch_chunk(). Cette fonction utilise AF_ALG et splice() pour connecter le cache de pages du fichier cible au chemin de traitement crypto, et vérifie si, sur un noyau vulnérable, une partie du cache de pages est écrasée pendant le traitement AEAD.
vulnerable.cvulnerable.c ne touche à aucun fichier système réel. Il crée un testfile temporaire dans le répertoire courant et vérifie si le cache de pages de ce fichier est altéré.
Dans ce projet, seul ce fichier a été exécuté.
Avant de mettre à jour le noyau, l’état de l’OS, du noyau et des paquets a été enregistré.
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
Dans cet exercice, nous n’avons pas utilisé la construction par défaut make qui compile également les binaires d’exploit ; seule la cible vulnerable a été utilisée.
./vulnerable > ../before/vulnerable-output.txt 2>&1
echo $? >> ../before/vulnerable-output.txt
cat ../before/vulnerable-output.txt
Résultat avant le patch :

Diagnostic :
code de sortie 100
→ Mutation du cache de pages confirmée
→ La primitive Copy Fail fonctionne sur le noyau avant le patch
Après avoir sauvegardé les résultats avant le patch, la mise à jour des paquets Ubuntu a été effectuée.
sudo apt update
sudo apt full-upgrade -y
sudo reboot
Après redémarrage, le noyau est passé à :
Avant : 6.8.0-53-generic
Aprè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
Résultat après le patch :

Comparaison des résultats :