[PATCH] scsi: qla4xxx: Fix NULL pointer dereference in qla4xxx_abort_active_cmds()
Yang Zi <[email protected]>
| Newsgroups | org.kernel.vger.linux-scsi,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
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 <[email protected]> --- 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);