[PATCH] scsi: qla4xxx: Fix NULL pointer dereference in qla4xxx_abort_active_cmds()

From: Yang Zi

Date: Tue Aug 25 2026 - 05:12:14 EST


qla4xxx_probe_adapter()'s failure path first calls scsi_remove_host(),
which drops the SCSI host's tag set reference and frees tag_set.tags via
scsi_mq_free_tags() -> blk_mq_free_tag_set().  It then falls through to
qla4xxx_free_adapter(), which calls qla4xxx_abort_active_cmds().  That
function walks ha->host->can_queue entries and, for each one, calls
qla4xxx_del_from_active_array() -> scsi_host_find_tag(), which
dereferences shost->tag_set.tags -- now NULL -- resulting in a NULL
pointer dereference.

KASAN report:

    BUG: KASAN: null-ptr-deref in scsi_host_find_tag include/scsi/scsi_tcq.h:33 [inline] [qla4xxx]
    BUG: KASAN: null-ptr-deref in qla4xxx_del_from_active_array drivers/scsi/qla4xxx/ql4_os.c:9095 [inline] [qla4xxx]
    BUG: KASAN: null-ptr-deref in qla4xxx_abort_active_cmds+0x10b/0x610 drivers/scsi/qla4xxx/ql4_os.c:4816 [qla4xxx]

Guard qla4xxx_abort_active_cmds() so that it returns early when the SCSI
host has not been set up yet or its tag set has already been released:
in both cases there are no outstanding commands left to abort, and
scsi_host_find_tag() must not dereference a NULL tag_set.tags pointer.
This covers both the failed-probe cleanup path and the normal
qla4xxx_remove_adapter() path.

This patch addresses two reports with the same root cause (tracking IDs
115 and 139).

Signed-off-by: Yang Zi <2959243019@xxxxxx>
---
 drivers/scsi/qla4xxx/ql4_os.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c
index d598ab4126f8..2277f48fede8 100644
--- a/drivers/scsi/qla4xxx/ql4_os.c
+++ b/drivers/scsi/qla4xxx/ql4_os.c
@@ -4811,6 +4811,15 @@ static void qla4xxx_abort_active_cmds(struct scsi_qla_host *ha, int res)
     int i;
     unsigned long flags;
 
+    /*
+     * The SCSI host may not be fully set up yet, or its tag set may
+     * already have been released by scsi_remove_host().  In either case
+     * there are no outstanding commands to abort, and scsi_host_find_tag()
+     * would dereference a NULL tag_set.tags pointer.
+     */
+    if (!ha->host || !ha->host->tag_set.tags)
+        return;
+
     spin_lock_irqsave(&ha->hardware_lock, flags);
     for (i = 0; i < ha->host->can_queue; i++) {
         srb = qla4xxx_del_from_active_array(ha, i);