
Ruolo Ansible e script Python che rilevano l'esposizione del kernel Linux a CVE-2026-98432 e applicano una regola nftables che scarta i SYN IPv4 in ingresso che trasportano opzioni IP.
Una use-after-free nel codice TCP IPv4 del kernel Linux
(CVE-2026-98432, CVSS 9.8):
le opzioni IPv4 salvate da un SYN in ingresso possono essere liberate mentre un'altra CPU
le sta ancora leggendo per costruire un SYNACK, perché due percorsi di distruzione le liberano
con un semplice kfree() invece di attendere un periodo di grazia RCU.
La correzione upstream è
e3f33b0a1d89
("ipv4: free inet_opt and ireq_opt after an RCU grace period").
Al 2026-10-29 non è stato rilasciato alcun kernel corretto per nessuna serie Ubuntu. Ogni stato interessato sul tracker di Ubuntu riporta "work in progress" o semplicemente vulnerabile, e la pagina non elenca alcuna mitigazione. Questo pacchetto è la mitigazione.
Entrambi i percorsi in race leggono ireq->ireq_opt, le opzioni IPv4 che il kernel ha salvato
dal SYN in ingresso (tcp_v4_save_options()): la costruzione del SYNACK le legge
mentre la distruzione del socket figlio può liberarle, e la migrazione del request-socket
(net.ipv4.tcp_migrate_req=1, o un programma
BPF_SK_REUSEPORT_SELECT_OR_MIGRATE) condivide e poi libera le stesse
opzioni. Quando un SYN non trasporta opzioni IPv4, ireq_opt è NULL: non c'è
nulla da liberare e nulla da leggere. Abbiamo letto il commit di correzione prima di fare affidamento
su questo; entrambe le parti partono da un SYN che trasportava opzioni IPv4.
Quindi il pacchetto installa una regola nftables che scarta i SYN TCP IPv4 in ingresso che trasportano opzioni IP, in una tabella propria così non entra mai in collisione con le regole di Docker, del substrate o della distribuzione:
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"
}
}
Verificato su un kernel reale prima del rilascio: un SYN IPv4 che trasporta opzioni colpisce il contatore e viene scartato; un SYN semplice passa intatto. Il traffico TCP non trasporta quasi mai opzioni IP (diversi tipi di opzione vengono scartati da molte reti per prassi consolidata, secondo la RFC 7126), quindi il costo operativo della regola è prossimo allo zero.
pve,
che la pagina di Ubuntu non copre) riportano unknown: consultare i loro
advisory. La regola in sé proteggerebbe qualsiasi host Linux; le tabelle
dei verdetti sono l'unica parte specifica per Ubuntu.La regola risiede nella memoria del kernel e non viene persistita su disco. Un
pacchetto di mitigazione non deve scrivere nei percorsi di persistenza (unit, cron), e un
file di include di nftables viene caricato solo dove il servizio nftables della
distribuzione è abilitato, cosa che su questi parchi non è uniforme. Quindi: dopo
un riavvio, una rilevazione legge la regola assente (rule_live=0,
persistent=0 su ogni riga di risultato) e la successiva applicazione la ripristina.
Rieseguire l'applicazione dopo i riavvii è il modello operativo, e la riga di risultato
non afferma mai il contrario.
Sola lettura, si organizza in una directory temporanea privata che poi rimuove, e riporta:
uname -r, mappato alla sua versione del pacchetto)
rispetto alle versioni corrette di Ubuntu per release e variante. Nessuna correzione rilasciata
per la release della macchina: no_fix. Un kernel corretto rilasciato ma non
in esecuzione: vulnerable, con restart_needed=1 quando è installato e
in attesa di un riavvio (una correzione installata non viene mai riportata come fixed).fixed con workaround: true sulla
riga di risultato mentre la regola copre un kernel non corretto; semplice fixed
una volta che il kernel in esecuzione è corretto.not_affected per le release che il tracker segnala come non interessate, unknown per release
e distribuzioni che le tabelle non coprono.0 pulito (fixed, not_affected), 2 esposto o
indeciso (no_fix, vulnerable, unknown: mai pulito), 1 l'esecuzione
stessa è fallita, 130 interrotta.syn_options_mitigation/files/samp_common.py è una copia byte per byte di
samp-common 1.0.4 (i confronti di versione dpkg, rpm e apk,
la riga di risultato, il caricamento della configurazione). Il suo sha256 è in
samp.yaml, e tests/test_samp_pack.py fallisce se la copia differisce. Non
modificarlo qui; ri-vendorizzarlo con scripts/vendor.py di samp-common.samp/v<version> (questa:
samp/v1.0.1), firmati con una chiave supportata da hardware. Il substrato
importa un tag firmato, mai un branch.Un passo di script, una riga di risultato. Finché il kernel in esecuzione non è corretto,
carica la regola; una volta che è in esecuzione un kernel corretto, rimuove la regola e
la sua tabella. Non modifica alcun file oltre allo script, alla libreria e alla configurazione che
distribuisce (dichiarati in touches di samp.yaml), quindi la lista di backup della riga di risultato è vuota. Rimuovere la mitigazione a mano è un solo comando:
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
Quando Ubuntu rilascia kernel corretti, incolla le versioni dal tracker
in syn_options_fixed_versions nei valori predefiniti del ruolo (le versioni
in corso di sviluppo sono già presenti in un commento) e rilascia la modifica come successivo
tag firmato; il rilevamento inizia quindi a segnalare vulnerable/restart_needed
rispetto a esse, e l'applicazione rimuove la regola dalle macchine che si riavviano con un
kernel corretto.
python3 -m pytest tests/
Gli unit test simulano ogni comando esterno; il contract test
(tests/test_samp_pack.py, di samp-common) verifica il manifest rispetto al
ruolo, esegue un rilevamento reale da una directory temporanea e vincola la voce di apply
alla regola della riga di risultato singolo e a quella di needrestart.
MIT. Vedi LICENSE.
PR e miglioramenti sono benvenuti -> esegui il fork e invia una merge request.