
Preuve de concept d'exploitation pour CVE-2026-31431, une élévation de privilèges locale du noyau Linux via l'écriture dans le cache de pages AF_ALG, permettant d'obtenir les droits root sur les principales distributions.
algif_aead (« Copy Fail »)
Auteur : Van Glenndon Enad
Découverte originale : Theori / Xint Code Research Team (Taeyang Lee)
Publié : 29 avril 2026
Sévérité : Élevée
Score CVSS v3.1 : 7,8
Vecteur CVSS v3.1 : CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
CWE : CWE-787 (Écriture hors limites), CWE-269 (Gestion inappropriée des privilèges)
La CVE-2026-31431, surnommée publiquement « Copy Fail », est une vulnérabilité d'élévation de privilèges locale (LPE) de sévérité élevée dans le module algif_aead du noyau Linux — l'interface de chiffrement AEAD de l'API cryptographique du noyau accessible depuis l'espace utilisateur (AF_ALG). Le défaut provient d'une optimisation de performance (opération « in-place ») introduite en 2017 via le commit 72548b093ee3, qui permettait par inadvertance de placer des pages de fichiers adossées au cache de pages dans la liste scatterlist de destination accessible en écriture lors d'une opération cryptographique AEAD.
En enchaînant trois sous-systèmes du noyau — les sockets AF_ALG, l'appel système splice() et le comportement d'écriture temporaire de l'algorithme authencesn — un utilisateur local non privilégié peut effectuer une écriture contrôlée de 4 octets dans le cache de pages de n'importe quel fichier lisible. En ciblant un binaire setuid tel que /usr/bin/su, cette écriture corrompt l'image exécutable en mémoire sans modifier le fichier sur disque, contournant ainsi les outils d'intégrité des fichiers sur disque. L'élévation de privilèges résultante vers root est déterministe — aucune condition de course, aucun décalage de noyau spécifique à une distribution et aucun privilège spécial ne sont requis. Un exploit PoC Python de 732 octets publié publiquement fournit des shells root sur Ubuntu, Amazon Linux, RHEL et SUSE en une seule exécution non modifiée.
| Composant | Détails |
|---|---|
| Sous-système concerné | crypto/algif_aead.c — interface AEAD AF_ALG du noyau Linux |
| Vulnérabilité introduite | Noyau Linux 4.14 (2017), commit 72548b093ee38a6d4f2a19e6ef1948ae05c181f7 |
| Versions corrigées | 6.18.22, 6.19.12, 7.0 |
| Commit de correction | a664bf3d603dc3bdcf9ae47cc21e0daec706d7a5 |
| Distributions vérifiées | Ubuntu 24.04 LTS, Amazon Linux 2023, RHEL 10.1, SUSE 16 |
| Implicitement concernées | Debian, Arch, Fedora, Rocky, AlmaLinux, Oracle Linux et toute distribution exécutant un noyau non corrigé compilé depuis 2017 |
La vulnérabilité est silencieusement présente dans toutes les distributions Linux grand public depuis près de neuf ans. Selon Theori, AF_ALG est activé dans la configuration de noyau par défaut de pratiquement toutes les distributions, ce qui signifie qu'aucun indicateur de compilation ou configuration spéciale n'est nécessaire pour qu'un système soit vulnérable.
Le noyau Linux expose des primitives cryptographiques à l'espace utilisateur via l'interface socket AF_ALG (crypto/algif_aead.c). En 2017, une optimisation de performance a été fusionnée, permettant à algif_aead d'effectuer des opérations AEAD en place — réutilisant le tampon mémoire source comme destination — afin d'éviter des copies de données inutiles.
Le défaut apparaît lorsque l'espace utilisateur alimente la socket AF_ALG via l'appel système splice(). Dans ce cas, les pages placées dans la liste scatterlist source sont des pages du cache de pages — une mémoire partagée gérée par le noyau qui soutient le fichier épissé. En raison de l'optimisation en place définissant req->src = req->dst, ces pages du cache de pages se retrouvent dans la liste scatterlist de destination accessible en écriture. L'algorithme authencesn effectue ensuite une écriture temporaire à dst[assoclen + cryptlen], qui se résout en un décalage dans ces pages du cache de pages — écrivant effectivement des données contrôlées par l'attaquant dans l'image mémoire du fichier épissé.
Parce que le cache de pages est partagé sur l'ensemble de l'hôte, y compris les conteneurs, une écriture depuis un processus affecte les pages mises en cache de ce fichier pour chaque processus et conteneur sur le même noyau.
Le changement fautif dans algif_aead.c définissait req->src = req->dst et enchaînait les pages d'étiquette de la liste scatterlist source dans la liste de sortie via sg_chain() :
/* Optimisation en place de 2017 — commit 72548b093ee3 */
req->src = req->dst; /* source == destination */
sg_chain(dst, n + 1, src_tag); /* pages d'étiquette enchaînées dans dst accessible en écriture */
Lorsque splice() est utilisé pour alimenter un fichier dans la socket, les pages de la liste scatterlist sont adossées au cache de pages, et non à une mémoire anonyme privée. Les enchaîner dans la liste dst accessible en écriture viole l'hypothèse selon laquelle la destination est une mémoire privée accessible en écriture.
authencesnLe modèle authencesn écrit une valeur temporaire de numéro de séquence (seqno_lo, octets 4 à 7 de l'AAD) à dst[assoclen + cryptlen]. Parce que dst contient désormais des pages du cache de pages du fichier épissé, cette écriture atterrit à un décalage contrôlé par l'attaquant dans l'image mémoire du fichier :
/* Écriture temporaire authencesn — décalage déterminé par assoclen + cryptlen */
scatterwalk_map_and_copy(seqno, dst,
req->assoclen + req->cryptlen,
sizeof(seqno), 1); /* écrit dans le cache de pages */
Les 4 octets écrits correspondent à seqno_lo, que l'attaquant contrôle via la charge utile AAD envoyée via sendmsg().
Socket AF_ALG (SOCK_SEQPACKET)
│
│ splice() — fournit des pages adossées à un fichier dans la socket
▼
Optimisation en place algif_aead
│ req->src = req->dst
│ les pages du cache de pages atterrissent dans la liste scatterlist accessible en écriture
▼
Écriture temporaire authencesn
│ écrit seqno_lo à dst[assoclen + cryptlen]
│ = 4 octets choisis par l'attaquant à un décalage de fichier choisi par l'attaquant
▼
Corruption du cache de pages (aucune modification sur disque)
La correction (a664bf3d603d) annule entièrement l'optimisation en place — algif_aead fonctionne désormais toujours hors place, allouant un tampon de destination séparé. Puisque la source et la destination proviennent désormais de mappages différents, les pages du cache de pages dans src ne peuvent jamais être atteintes par le chemin d'écriture de dst.