CVE-2026-89860 in Linux
Summary
by MITRE • 09/16/2026
In the Linux kernel, the following vulnerability has been resolved:
scsi: qla2xxx: Initialize NVMe abort_work once at submission
qla_nvme_fcp_abort() and qla_nvme_ls_abort() ran INIT_WORK() on priv->abort_work immediately before schedule_work(). INIT_WORK() reinitializes the work_struct, resetting its list head and clearing the pending bit. If an abort is issued more than once for the same command (for example, concurrent transport teardown and a timeout-driven abort), the second INIT_WORK() reinitializes a work item that is already queued, which can corrupt the workqueue list and lead to crashes or a looping worker.
Initialize priv->abort_work once at command submission, next to the existing per-command spin_lock_init(&priv->cmd_lock), and leave only schedule_work() in the abort paths. schedule_work() already does nothing when the work item is still pending, so a repeated abort no longer disturbs an in-flight work item. The command is not returned to the transport until the final kref_put()/release callback runs after abort_work has completed, so the work item is idle before priv is reused and the single submission-time INIT_WORK() is safe.
If you want to get best quality of vulnerability data, you may have to visit VulDB.
Analysis
by VulDB Data Team • 09/16/2026
The Linux kernel SCSI subsystem contains a critical concurrency vulnerability within the qla2xxx driver that affects NVMe over Fabrics command handling. The flaw originates in the functions qla_nvme_fcp_abort and qla_nvme_ls_abort, which are responsible for aborting pending I/O commands. In the vulnerable implementation, these functions invoked INIT_WORK on the priv->abort_work structure immediately before calling schedule_work to execute the abort routine. This design choice introduces a race condition because INIT_WORK not only initializes the work_struct but also reinitializes it by resetting its list head and clearing any pending status bits. When an abort is triggered multiple times for the same command, such as when concurrent transport teardown operations overlap with timeout-driven aborts, the second invocation of INIT_WORK acts upon a work item that may already be queued in the kernel's workqueue infrastructure.
This double initialization corrupts the internal data structures of the Linux workqueue subsystem. Specifically, reinitializing a work_struct that is currently pending or executing can lead to list corruption within the global worker pool. The consequences of this memory and state corruption are severe, potentially resulting in system crashes, kernel panics, or infinite loops within the worker threads as they attempt to process malformed queue entries. This represents a significant stability risk for systems relying on high-performance NVMe storage over Fibre Channel networks managed by QLogic adapters, where rapid command teardowns and timeouts can occur frequently under load.
From a vulnerability classification perspective, this issue aligns with CWE-362, which describes concurrent execution using shared resources with insufficient synchronization. The root cause is the lack of proper state management for asynchronous work items in a multi-threaded environment. Furthermore, from an offensive security standpoint utilizing the MITRE ATT&CK framework, this flaw could be leveraged by local attackers to achieve Denial of Service against the system through resource exhaustion or kernel instability. While not directly exploitable for arbitrary code execution without additional conditions, the resulting crash provides a reliable mechanism for disrupting service availability and potentially destabilizing the host operating environment.
The resolution involves restructuring how the abort work item is managed within the driver's private command structure. Instead of initializing the work item on every abort attempt, priv->abort_work is now initialized exactly once at the time of command submission. This initialization occurs alongside the existing per-command spin_lock_init call for cmd_lock, ensuring that the synchronization primitives are set up correctly before any asynchronous operations begin. The abort paths in qla_nvme_fcp_abort and qla_nvme_ls_abort were modified to remove the INIT_WORK calls entirely, leaving only schedule_work to trigger execution. This change is safe because schedule_work inherently checks if a work item is already pending; if it is, the function returns without re-queuing or modifying the existing entry.
This architectural adjustment ensures that repeated abort requests do not interfere with an in-flight work item. The command structure remains locked and valid until the final reference count decrement via kref_put triggers the release callback. This callback executes only after abort_work has fully completed, guaranteeing that the work item is idle before the private memory region is reused for a new command. By decoupling initialization from execution logic, the driver eliminates the race condition entirely. System administrators and developers should ensure that kernel updates incorporating this fix are applied to maintain stability in environments utilizing QLogic qla2xxx adapters with NVMe over Fabrics configurations.