
Rol de Ansible y script de Python que detectan la exposición del kernel de Linux a CVE-2026-98432 y aplican una regla de nftables que descarta los SYN de IPv4 entrantes que llevan opciones IP.
Un use-after-free en el código TCP de IPv4 del kernel de Linux
(CVE-2026-98432, CVSS 9.8):
las opciones IPv4 guardadas de un SYN entrante pueden liberarse mientras otra CPU
todavía las está leyendo para construir un SYNACK, porque dos rutas de destructor las liberan
con un simple kfree() en lugar de esperar un período de gracia de RCU.
La corrección upstream es
e3f33b0a1d89
("ipv4: free inet_opt and ireq_opt after an RCU grace period").
A fecha de 2026-10-29 no se ha publicado ningún kernel corregido para ninguna serie de Ubuntu. Todos los estados afectados en el tracker de Ubuntu indican "work in progress" o simplemente vulnerable, y la página no enumera ninguna mitigación. Este paquete es la mitigación.
Ambas rutas en carrera leen ireq->ireq_opt, las opciones IPv4 que el kernel guardó
del SYN entrante (tcp_v4_save_options()): la construcción del SYNACK las lee
mientras el desmontaje del socket hijo puede liberarlas, y la migración del request-socket
(net.ipv4.tcp_migrate_req=1, o un programa
BPF_SK_REUSEPORT_SELECT_OR_MIGRATE) comparte y luego libera las mismas
opciones. Cuando un SYN no lleva opciones IPv4, ireq_opt es NULL: no hay
nada que liberar ni nada que leer. Leímos el commit de corrección antes de basarnos
en eso; ambas mitades parten de un SYN que llevaba opciones IPv4.
Por lo tanto, el paquete instala una regla de nftables que descarta los SYN TCP de IPv4 entrantes que llevan opciones IP, en una tabla propia para que nunca colisione con las reglas de Docker, del sustrato o de la distribución:
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"
}
}
Verificado en un kernel real antes del lanzamiento: un SYN IPv4 que transporta opciones alcanza el contador y se descarta; un SYN simple pasa intacto. El tráfico TCP casi nunca transporta opciones IP (varios tipos de opciones son descartados por muchas redes de forma habitual, según la RFC 7126), por lo que el coste operativo de la regla es prácticamente nulo.
pve,
que la página de Ubuntu no cubre) informan unknown: consulta sus
avisos. La regla en sí protegería a cualquier host Linux; las tablas de veredicto
son lo único exclusivo de Ubuntu.La regla vive en la memoria del kernel y no se persiste en disco. Un
paquete de mitigación no debe escribir en rutas de persistencia (units, cron), y un
archivo de inclusión de nftables solo se carga donde el servicio nftables de la
distribución está habilitado, lo cual en estas instalaciones no es uniforme. Por lo tanto: tras
un reinicio, una detección lee la regla como ausente (rule_live=0,
persistent=0 en cada línea de resultado) y la siguiente aplicación la restaura.
Volver a ejecutar la aplicación tras los reinicios es el modelo operativo, y la línea
de resultado nunca afirma lo contrario.
De solo lectura, se prepara en un directorio temporal privado que elimina, e informa:
uname -r, mapeado a su versión de paquete)
frente a las versiones corregidas de Ubuntu por release y sabor. Sin corrección publicada
para el release de la máquina: no_fix. Un kernel corregido publicado pero no
en ejecución: vulnerable, con restart_needed=1 cuando está instalado y
esperando un reinicio (una corrección instalada nunca se informa como fixed).fixed con workaround: true en
la línea de resultado mientras la regla cubre un kernel sin corregir; fixed simple
una vez que el kernel en ejecución está corregido.not_affected para los releases que el tracker marca como no afectados, unknown para los releases
y distribuciones que las tablas no cubren.0 limpio (fixed, not_affected), 2 expuesto o
indeciso (no_fix, vulnerable, unknown: nunca limpio), 1 la ejecución
en sí falló, 130 interrumpida.syn_options_mitigation/files/samp_common.py es una copia byte a byte de
samp-common 1.0.4 (las comparaciones de versiones dpkg, rpm y apk,
la línea de resultado, la carga de configuración). Su sha256 está en
samp.yaml, y tests/test_samp_pack.py falla si la copia difiere. Nunca
lo edites aquí; vuelve a incorporarlo con scripts/vendor.py de samp-common.samp/v<version> (este:
samp/v1.0.1), firmados con una clave respaldada por hardware. El sustrato
importa un tag firmado, nunca una rama.Un paso de script, una línea de resultado. Mientras el kernel en ejecución no esté corregido,
carga la regla; una vez que se ejecuta un kernel corregido, elimina la regla y
su tabla. No edita ningún archivo más allá del script, la biblioteca y la configuración que
despliega (declarados en touches de samp.yaml), por lo que la lista de copias de seguridad de la línea de resultado
está vacía. Eliminar la mitigación manualmente es 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
Cuando Ubuntu publique kernels corregidos, pega las versiones del tracker
en syn_options_fixed_versions en los defaults del rol (las versiones en
desarrollo ya están ahí en un comentario) y publica el cambio como la siguiente
etiqueta firmada; la detección entonces comienza a reportar vulnerable/restart_needed
contra ellas, y la aplicación elimina la regla de las máquinas que reinician con un
kernel corregido.
python3 -m pytest tests/
Las pruebas unitarias simulan cada comando externo; la prueba de contrato
(tests/test_samp_pack.py, de samp-common) verifica el manifiesto contra el
rol, ejecuta una detección real desde un directorio temporal y somete la entrada de apply
a las reglas de una sola línea de resultado y de needrestart.
MIT. Consulte LICENSE.
PRs y mejoras son bienvenidos -> por favor haga fork y envíe una merge request.