CVE-2026-45855
Publication date:
27/05/2026
In the Linux kernel, the following vulnerability has been resolved:<br />
<br />
ata: libata-scsi: avoid Non-NCQ command starvation<br />
<br />
When a non-NCQ command is issued while NCQ commands are being executed,<br />
ata_scsi_qc_issue() indicates to the SCSI layer that the command issuing<br />
should be deferred by returning SCSI_MLQUEUE_XXX_BUSY. This command<br />
deferring is correct and as mandated by the ACS specifications since<br />
NCQ and non-NCQ commands cannot be mixed.<br />
<br />
However, in the case of a host adapter using multiple submission queues,<br />
when the target device is under a constant load of NCQ commands, there<br />
are no guarantees that requeueing the non-NCQ command will be executed<br />
later and it may be deferred again repeatedly as other submission queues<br />
can constantly issue NCQ commands from different CPUs ahead of the<br />
non-NCQ command. This can lead to very long delays for the execution of<br />
non-NCQ commands, and even complete starvation for these commands in the<br />
worst case scenario.<br />
<br />
Since the block layer and the SCSI layer do not distinguish between<br />
queueable (NCQ) and non queueable (non-NCQ) commands, libata-scsi SAT<br />
implementation must ensure forward progress for non-NCQ commands in the<br />
presence of NCQ command traffic. This is similar to what SAS HBAs with a<br />
hardware/firmware based SAT implementation do.<br />
<br />
Implement such forward progress guarantee by limiting requeueing of<br />
non-NCQ commands from ata_scsi_qc_issue(): when a non-NCQ command is<br />
received and NCQ commands are in-flight, do not force a requeue of the<br />
non-NCQ command by returning SCSI_MLQUEUE_XXX_BUSY and instead return 0<br />
to indicate that the command was accepted but hold on to the qc using<br />
the new deferred_qc field of struct ata_port.<br />
<br />
This deferred qc will be issued using the work item deferred_qc_work<br />
running the function ata_scsi_deferred_qc_work() once all in-flight<br />
commands complete, which is checked with the port qc_defer() callback<br />
return value indicating that no further delay is necessary. This check<br />
is done using the helper function ata_scsi_schedule_deferred_qc() which<br />
is called from ata_scsi_qc_complete(). This thus excludes this mechanism<br />
from all internal non-NCQ commands issued by ATA EH.<br />
<br />
When a port deferred_qc is non NULL, that is, the port has a command<br />
waiting for the device queue to drain, the issuing of all incoming<br />
commands (both NCQ and non-NCQ) is deferred using the regular busy<br />
mechanism. This simplifies the code and also avoids potential denial of<br />
service problems if a user issues too many non-NCQ commands.<br />
<br />
Finally, whenever ata EH is scheduled, regardless of the reason, a<br />
deferred qc is always requeued so that it can be retried once EH<br />
completes. This is done by calling the function<br />
ata_scsi_requeue_deferred_qc() from ata_eh_set_pending(). This avoids<br />
the need for any special processing for the deferred qc in case of NCQ<br />
error, link or device reset, or device timeout.
Severity CVSS v4.0: Pending analysis
Last modification:
27/05/2026