Instituto Nacional de ciberseguridad. Sección Incibe
Instituto Nacional de Ciberseguridad. Sección INCIBE-CERT

Vulnerabilidad en kernel de Linux (CVE-2025-22111)

Gravedad:
Pendiente de análisis
Tipo:
No Disponible / Otro tipo
Fecha de publicación:
16/04/2025
Última modificación:
17/04/2025

Descripción

En el kernel de Linux, se ha resuelto la siguiente vulnerabilidad: net: Eliminación del movimiento RTNL para SIOCBRADDIF y SIOCBRDELIF. SIOCBRDELIF se pasa primero a dev_ioctl() y luego a br_ioctl_call(), lo que provoca un movimiento RTNL innecesario y el splat debajo de [0] bajo presión RTNL. Supongamos que el subproceso A intenta desconectar un dispositivo de un puente y el subproceso B intenta eliminar el puente. En dev_ioctl(), el subproceso A aumenta el refcnt del dispositivo puente mediante netdev_hold() y libera RTNL porque el subproceso br_ioctl_call() también vuelve a adquirir RTNL. En la ventana de ejecución, el subproceso B podría adquirir RTNL e intentar eliminar el dispositivo puente. Luego, rtnl_unlock() del subproceso B liberará RTNL y esperará a netdev_put() del subproceso A. Sin embargo, el subproceso A debe mantener RTNL después del desbloqueo en dev_ifsioc(), lo que puede tardar mucho bajo la presión de RTNL, lo que resulta en el splat del subproceso B. Subproceso A (SIOCBRDELIF) Subproceso B (SIOCBRDELBR) ---------------------- ---------------------- sock_ioctl sock_ioctl `- sock_do_ioctl `- br_ioctl_call `- dev_ioctl `- br_ioctl_stub |- rtnl_lock | |- dev_ifsioc ' ' |- dev = __dev_get_by_name(...) |- netdev_hold(dev, ...) . / |- rtnl_unlock ------. | | |- br_ioctl_call `---> |- rtnl_lock Race | | `- br_ioctl_stub |- br_del_bridge Ventana | | | |- dev = __dev_get_by_name(...) | | | Puede tomar mucho tiempo | `- br_dev_delete(dev, ...) | | | bajo presión RTNL | `- unregister_netdevice_queue(dev, ...) | | | | `- rtnl_unlock \ | |- rtnl_lock <-' `- netdev_run_todo | |- ... `- netdev_run_todo | `- rtnl_unlock |- __rtnl_unlock | |- netdev_wait_allrefs_any |- netdev_put(dev, ...) <----------------' Espere la disminución de refcnt y registre splat a continuación Para evitar bloquear SIOCBRDELBR innecesariamente, no llamemos a dev_ioctl() para SIOCBRADDIF y SIOCBRDELIF. En la ruta dev_ioctl(), hacemos lo siguiente: 1. Copiar struct ifreq por get_user_ifreq en sock_do_ioctl() 2. Verificar CAP_NET_ADMIN en dev_ioctl() 3. Llamar a dev_load() en dev_ioctl() 4. Obtener el dev maestro de ifr.ifr_name en dev_ifsioc() 3. se puede hacer por request_module() en br_ioctl_call(), por lo que movemos 1., 2. y 4. a br_ioctl_stub(). Tenga en cuenta que 2. también se verifica más adelante en add_del_if(), pero se realiza mejor antes de RTNL. SIOCBRADDIF y SIOCBRDELIF se han procesado en dev_ioctl() desde la era anterior a Git, y no parece haber una razón específica para procesarlos allí. [0]: unregister_netdevice: esperando a que wpan3 quede libre. Recuento de uso = 2 ref_tracker: wpan3@ffff8880662d8608 tiene 1/1 usuarios en __netdev_tracker_alloc include/linux/netdevice.h:4282 [en línea] netdev_hold include/linux/netdevice.h:4311 [en línea] dev_ifsioc+0xc6a/0x1160 net/core/dev_ioctl.c:624 dev_ioctl+0x255/0x10c0 net/core/dev_ioctl.c:826 sock_do_ioctl+0x1ca/0x260 net/socket.c:1213 sock_ioctl+0x23a/0x6c0 net/socket.c:1318 vfs_ioctl fs/ioctl.c:51 [en línea] __do_sys_ioctl fs/ioctl.c:906 [en línea] __se_sys_ioctl fs/ioctl.c:892 [en línea] __x64_sys_ioctl+0x1a4/0x210 fs/ioctl.c:892 do_syscall_x64 arch/x86/entry/common.c:52 [en línea] do_syscall_64+0xcb/0x250 arch/x86/entry/common.c:83 entry_SYSCALL_64_after_hwframe+0x77/0x7f

Impacto