CVE-2026-99207 in Linux
Resumen
por VulDB • 2026-10-28
En el kernel de Linux, se ha resuelto la siguiente vulnerabilidad:
scsi: target: Deshabilitar las interrupciones mientras se mantiene delayed_cmd_lock
target_do_delayed_work() toma dev->delayed_cmd_lock con un spin_lock() simple. Se ejecuta desde system_percpu_wq, por lo que las interrupciones permanecen habilitadas mientras se mantiene el bloqueo. Cada otra adquisición de ese bloqueo utiliza spin_lock_irqsave(): target_handle_task_attr() y transport_complete_ordered_sync() en target_core_transport.c, y target_non_ordered_release() en target_core_device.c.
Eso era seguro mientras todos los llamadores de transport_complete_task_attr() se ejecutaban en un contexto de proceso: target_complete_ok_work() desde target_completion_wq, transport_complete_qf() desde dev->qf_work_queue, y transport_generic_request_failure() desde las rutas de envío y ejecución.
Desde el commit 06933066d88a ("scsi: target: Add support for completing commands from backend context") esto ya no es cierto. Con complete_type=1 en una fabric que establece direct_compl_supp, target_complete() ejecuta target_complete_ok_work() de forma inline en el contexto de finalización del backend, lo cual target_complete_cmd_with_sense() documenta como "Puede ser llamado desde un contexto de interrupción". Para iblock esto es bio end_io.
target_complete_ok_work() comienza con transport_complete_task_attr(), que toma delayed_cmd_lock de dos maneras:
- Cada comando ORDERED se coloca en dev->delayed_cmd_list por target_handle_task_attr() y se despacha desde allí mediante target_do_delayed_work(), lo cual lo marca como SCF_TASK_ORDERED_SYNC. Por tanto, su finalización pasa a través de transport_complete_ordered_sync().
- Un comando SIMPLE que termina mientras hay un comando ORDERED pendiente reduce la última referencia al dev->non_ordered eliminado, y percpu_ref_put() ejecuta entonces target_non_ordered_release() en el contexto de finalización.
Ambos toman el bloqueo y, si hay comandos esperando, llaman a schedule_work(&dev->delayed_cmd_work), lo que los pone en cola en system_percpu_wq, es decir, en la CPU que tomó la finalización. Las finalizaciones posteriores para la misma cola también se entregan típicamente allí, por lo que una llegada mientras el trabajo mantiene el bloqueo gira sobre él indefinidamente.
Alcanzar esto requiere complete_type=1, que no es el valor predeterminado (vhost-scsi, la única fabric con direct_compl_supp, tiene como valor predeterminado TARGET_QUEUE_COMPL), un backend cuya E/S finaliza desde un contexto de interrupción y comandos ORDERED del iniciador. Los invitados Linux virtio_scsi envían solo VIRTIO_SCSI_S_SIMPLE y nunca toman la ruta ordenada; cualquier invitado que use el atributo de tarea ORDERED, lo cual vhost-scsi acepta, sí lo hace.
target_do_delayed_work() es un elemento de trabajo (work item) y siempre se ejecuta en contexto de proceso, por lo que spin_lock_irq() es suficiente.
Encontrada mediante inspección; no hay informe en tiempo de ejecución. Un único comando ORDERED pasa por ambas adquisiciones, por lo que con CONFIG_PROVE_LOCKING la primera completada a través de finalización directa debería producir un informe de estado inconsistente del bloqueo en delayed_cmd_lock (hardirq o softirq, dependiendo de dónde complete el backend).
If you want to get best quality of vulnerability data, you may have to visit VulDB.