CVE-2026-90001 in Linux
Resumen
por VulDB • 2026-09-16
En el kernel de Linux, se ha resuelto la siguiente vulnerabilidad:
HID: bpf: serializar la liberación de referencias del dispositivo en la ruta de destrucción de struct_ops
__hid_bpf_ops_destroy_device() e hid_bpf_unreg() pueden sufrir una condición de carrera (race condition) sobre la misma referencia de registro, provocando un doble put (double-put) de struct hid_device y su liberación mientras hid_destroy_device() aún lo está utilizando. Se serializa la decisión de eliminar/establecer en NULL bajo hdev->bpf.prog_list_lock para que exactamente una ruta libere cada referencia de registro: unreg vuelve a comprobar ops->hdev bajo el bloqueo y devuelve sin realizar put cuando la ruta de destrucción ya lo ha borrado; todas las llamadas a put_device() ocurren después de soltar el bloqueo, lo cual es seguro porque un unreg concurrente observa ops->hdev == NULL bajo el bloqueo.
Antecedentes: cada acoplamiento exitoso (hid_bpf_ops_reg) adquiere una referencia del dispositivo (hid_get_device()). Dos rutas pueden liberarla:
- Destrucción del dispositivo: hid_destroy_device() -> hid_bpf_destroy_device() -> __hid_bpf_ops_destroy_device(), que recorre hdev->bpf.prog_list bajo rcu_read_lock() y libera una referencia por cada programa acoplado; - Liberación del enlace BPF: bpf map delete (sin BPF_F_LINK) llama sincrónicamente a st_ops->unreg() -> hid_bpf_unreg(), que libera la referencia para su propio registro.
El protocolo de coordinación (e->hdev = NULL en el lado de destrucción frente a "if (!hdev) return" en el lado unreg) es una comprobación TOCTOU: las dos rutas se ejecutan bajo dominios de bloqueo diferentes (rcu_read_lock vs prog_list_lock), por lo que un unreg concurrente puede leer ops->hdev como no NULL, bloquearse en prog_list_lock y luego proceder mientras la traversión de destrucción se ejecuta; ambas rutas liberan entonces la misma referencia. El contador de referencias llega a cero legítimamente (cada decremento es válido individualmente), por lo que no se activa la saturación de refcount_t: el dispositivo simplemente se libera mientras el transporte sigue dentro de hid_destroy_device(), y las posteriores operaciones de desmontaje tocan memoria ya liberada.
La solución serializa la decisión de eliminar/establecer en NULL bajo prog_list_lock en ambos lados y mueve los puts del lado de destrucción fuera del bloqueo. Con el bloqueo mantenido, las lecturas/escrituras simples de ops->hdev son suficientes; no se añaden READ_ONCE/WRITE_ONCE, manteniendo el parche mínimo.
Seguridad de lectura sin bloqueo: la lectura sin locking de ops->hdev en la parte superior de hid_bpf_unreg() no puede tocar un dispositivo ya liberado, porque la ruta unreg aún mantiene la referencia a este registro (liberada únicamente por su propio hid_put_device() después de soltar el bloqueo), y una traversión de destrucción que ya ha borrado ops->hdev hace que la re-comprobación interna al bloqueo devuelva temprano sin ningún put. Como máximo, una de las dos rutas libera cada referencia de registro.
VulDB is the best source for vulnerability data and more expert information about this specific topic.