
Rôle Ansible et script Python qui détectent l'exposition du noyau Linux à CVE-2026-98432 et appliquent une règle nftables supprimant les SYN IPv4 entrants portant des options IP.
Un use-after-free dans le code TCP IPv4 du noyau Linux
(CVE-2026-98432, CVSS 9.8) :
les options IPv4 sauvegardées à partir d'un SYN entrant peuvent être libérées alors qu'un autre CPU
les lit encore pour construire un SYNACK, car deux chemins de destructeur les libèrent
avec un simple kfree() au lieu d'attendre une période de grâce RCU.
Le correctif amont est
e3f33b0a1d89
("ipv4: free inet_opt and ireq_opt after an RCU grace period").
Au 2026-10-29, aucun noyau corrigé n'est publié pour aucune série Ubuntu. Chaque statut affecté sur le tracker d'Ubuntu indique « work in progress » ou simplement vulnérable, et la page ne liste aucune atténuation. Ce pack est l'atténuation.
Les deux chemins en course lisent ireq->ireq_opt, les options IPv4 que le noyau a sauvegardées
à partir du SYN entrant (tcp_v4_save_options()) : la construction du SYNACK les lit
tandis que la destruction du socket enfant peut les libérer, et la migration du request-socket
(net.ipv4.tcp_migrate_req=1, ou un programme
BPF_SK_REUSEPORT_SELECT_OR_MIGRATE) partage puis libère les mêmes
options. Lorsqu'un SYN ne transporte aucune option IPv4, ireq_opt vaut NULL : il n'y a
rien à libérer et rien à lire. Nous avons lu le commit de correction avant de nous appuyer
sur ce point ; les deux moitiés partent d'un SYN qui transportait des options IPv4.
Le pack installe donc une règle nftables qui supprime les SYN TCP IPv4 entrants transportant des options IP, dans une table qui lui est propre afin qu'elle n'entre jamais en collision avec les règles de Docker, du substrat ou de la distribution :
table inet samp_cve_2026_98432 {
chain prerouting {
type filter hook prerouting priority -300; policy accept;
ip hdrlength > 5 tcp flags & (syn | ack) == syn counter drop \
comment "CVE-2026-98432: drop inbound IPv4 SYN carrying IP options"
}
}
Vérifié sur un noyau réel avant publication : un SYN IPv4 portant des options atteint le compteur et est abandonné ; un SYN simple passe sans être touché. Le trafic TCP ne porte presque jamais d'options IP (plusieurs types d'options sont abandonnés par de nombreux réseaux par principe, conformément à la RFC 7126), le coût opérationnel de la règle est donc proche de zéro.
pve,
que la page d'Ubuntu ne couvre pas) rapportent unknown : consultez leurs
avis. La règle elle-même protégerait n'importe quel hôte Linux ; les tableaux
de verdict sont ce qui est propre à Ubuntu.La règle réside dans la mémoire du noyau et n'est pas persistée sur le disque. Un
pack d'atténuation ne doit pas écrire dans les chemins de persistance (units, cron), et un
fichier d'inclusion nftables n'est chargé que là où le service nftables de la distribution
est activé, ce qui, sur ces parcs, n'est pas uniformément le cas. Donc : après
un redémarrage, une détection lit la règle comme absente (rule_live=0,
persistent=0 sur chaque ligne de résultat) et l'application suivante la restaure.
Relancer l'application après les redémarrages est le modèle opérationnel, et la ligne
de résultat ne prétend jamais le contraire.
En lecture seule, se met en scène dans un répertoire temporaire privé qu'elle supprime, et rapporte :
uname -r, mis en correspondance avec sa version de paquet)
par rapport aux versions corrigées d'Ubuntu par release et par variante. Aucun correctif publié
pour la release de la machine : no_fix. Un noyau corrigé publié mais non
en cours d'exécution : vulnerable, avec restart_needed=1 lorsqu'il est installé et
en attente d'un redémarrage (un correctif installé n'est jamais rapporté comme fixed).fixed avec workaround: true sur
la ligne de résultat tant que la règle couvre un noyau non corrigé ; fixed simple
une fois le noyau en cours d'exécution corrigé.not_affected pour les releases que le tracker déclare non concernées, unknown pour les releases
et distributions que les tableaux ne couvrent pas.0 propre (fixed, not_affected), 2 exposé ou
indéterminé (no_fix, vulnerable, unknown : jamais propre), 1 l'exécution
elle-même a échoué, 130 interrompue.syn_options_mitigation/files/samp_common.py est une copie octet pour octet de
samp-common 1.0.4 (les comparaisons de versions dpkg, rpm et apk,
la ligne de résultat, le chargement de la configuration). Son sha256 figure dans
samp.yaml, et tests/test_samp_pack.py échoue si la copie diffère. Ne
le modifiez jamais ici ; réintégrez-le avec le scripts/vendor.py de samp-common.samp/v<version> (celle-ci :
samp/v1.0.1), signés avec une clé adossée à du matériel. Le substrat
importe un tag signé, jamais une branche.Une étape de script, une ligne de résultat. Tant que le noyau en cours d'exécution n'est pas corrigé, elle
charge la règle ; une fois un noyau corrigé en cours d'exécution, elle supprime la règle et
sa table. Elle ne modifie aucun fichier au-delà du script, de la bibliothèque et de la configuration qu'elle
déploie (déclarés dans touches de samp.yaml), la liste de sauvegarde de la ligne de résultat est donc vide. Supprimer l'atténuation à la main se fait en une seule commande :
nft delete table inet samp_cve_2026_98432
ansible-playbook -i inventory play.yml # a play that runs the role
python3 syn_options_mitigator.py --config syn_options_config.yaml # detect
sudo python3 syn_options_mitigator.py --config syn_options_config.yaml --apply
Lorsque Ubuntu publie des noyaux corrigés, collez les versions depuis le tracker
dans syn_options_fixed_versions dans les valeurs par défaut du rôle (les versions
en cours de développement s'y trouvent déjà dans un commentaire) et publiez la modification sous la forme du prochain
tag signé ; la détection commence alors à signaler vulnerable/restart_needed
par rapport à celles-ci, et l'application supprime la règle des machines qui redémarrent sur un
noyau corrigé.
python3 -m pytest tests/
Les tests unitaires simulent chaque commande externe ; le test de contrat
(tests/test_samp_pack.py, celui de samp-common) vérifie le manifeste par rapport au
rôle, exécute une détection réelle depuis un répertoire temporaire et soumet l'entrée apply
aux règles de la ligne de résultat unique et de needrestart.