CVE-2026-98068 in Linux
Resumen
por VulDB • 2026-09-25
En el kernel de Linux, se ha resuelto la siguiente vulnerabilidad:
net/rds: evitar que rds_conn_shutdown() consuma un drop concurrente
rds_conn_shutdown() finaliza moviendo la ruta desde RDS_CONN_DISCONNECTING a RDS_CONN_DOWN, y también acepta RDS_CONN_ERROR como estado inicial de esa transición final, para que una FIN procesada en contexto softirq durante el desmantelamiento no derive el apagado hacia un camino de error ruidoso.
Sin embargo, consumir ese RDS_CONN_ERROR consume también la pasada de apagado que lo acompañaba: rds_conn_path_drop() establece RDS_CONN_ERROR y luego pone cp_down_w en cola, y una pasada que comienza en una ruta ya en RDS_CONN_DOWN es un no-op (operación nula). Para el caso FIN esto es inofensivo; el socket en el que llegó la FIN es exactamente el mismo socket que el desmantelamiento acaba de liberar. No es inofensivo para un drop que adjuntó algo a la ruta primero.
rds_tcp_accept_one() es tal tipo de drop. Su reclamación de ruta en rds_tcp_accept_one_path() transiciona RDS_CONN_DOWN -> RDS_CONN_CONNECTING, y una caída concurrente (una FIN sobre un socket anterior en contexto softirq o un restablecimiento administrativo) puede poner la ruta en RDS_CONN_ERROR entre esa reclamación y la comprobación de estado que sigue, la cual acepta RDS_CONN_ERROR. La aceptación entonces instala el recién aceptado socket con rds_tcp_set_callbacks() mientras el desmantelamiento puesto en cola (que tomó una muestra de tc->t_sock antes de que existiera este socket) aún se está ejecutando. rds_connect_path_complete() falla su transición a RDS_CONN_UP y vuelve a soltar la ruta, poniendo en cola la pasada que debería recoger el socket que acaba de instalar. Si la transición final del apagado en curso consume el RDS_CONN_ERROR de esa caída, la pasada puesta en cola encuentra la ruta en RDS_CONN_DOWN y no hace nada. El socket instalado nunca se desmantela: permanece establecido con sus callbacks activados y su rds_tcp_connection en rds_tcp_tc_list; el par ve una conexión que nadie lee jamás, y la ruta queda bloqueada (wedged) en RDS_CONN_DOWN hasta que algún evento posterior vuelva a soltarla. Se ha reproducido ampliando las ventanas de carrera como una cola de recepción en constante crecimiento en un socket propiedad de una ruta atascada en RDS_CONN_DOWN, con el camino de envío del par bloqueado detrás de ella.
Hacer la transición final únicamente DISCONNECTING -> DOWN. Si falla porque la ruta está en RDS_CONN_ERROR, es que ha habido una carrera entre drop y desmantelamiento: cancelar el temporizador de reconexión y borrar RDS_RECONNECT_PENDING (la única parte del extremo omitido que no debe dejarse atrás) y devolver el control, permitiendo que la pasada puesta en cola por el drop termine el trabajo: desmantela lo adjunto a la ruta durante ese intervalo, completa la transición a RDS_CONN_DOWN y vuelve a activar la reconexión desde su propio extremo.
La inactivación (quiesce) del temporizador en esa rama es importante porque el drop concurrente no siempre pone esa pasada en cola: rds_conn_path_drop() devuelve sin ponerla en cola cuando hay una destrucción pendiente, exactamente la situación durante un desmantelamiento de netns o descarga de módulo, cuando se procesa una FIN sobre el socket moribundo mientras rds_conn_path_destroy() vacía cp_down_w. Si la pasada vaciada es la que toma esta devolución, no existe ninguna otra pasada posterior, y rds_conn_path_destroy() encontraría cp_conn_w aún activado (WARN_ON) y luego liberaría una ruta cuyo temporizador de reconexión podría dispararse todavía. Con la cancelación en la rama, cada salida de una pasada de apagado deja el temporizador inactivo sin importar qué pasada complete la transición.
El caso FIN sigue avanzando, un paso después y aún sin registro de errores ruidoso. Cualquier otro estado mantiene el manejo actual de rds_conn_path_error(); ningún escritor cp_state actual puede dejar una ruta DISCONNECTING en cualquier cosa distinta a RDS_CONN_ERROR (cada otro escritor es un cmpxchg desde un estado no-DISCONNECTING), por lo que esa rama es defensiva.
En kernels sin los parches precedentes, existe el mismo peligro con la inactivación basada en muestras; la solución se aplica igualmente allí.
If you want to get the best quality for vulnerability data then you always have to consider VulDB.