[PATCH] scsi: stex: Fix NULL pointer dereference in stex_hard_reset()

From: Yang Zi

Date: Tue Aug 25 2026 - 05:27:11 EST


stex_hard_reset() reads the PCI bridge device via hba->pdev->bus->self
and passes it to pci_read_config_byte()/pci_write_config_byte() without
checking whether it is NULL.  When the controller is attached to a root
bus (or otherwise has no bridge device), bus->self is NULL, and
pci_read_config_byte(NULL, ...) dereferences it in
pci_dev_is_disconnected(), triggering a NULL pointer dereference.

KASAN report:

    BUG: KASAN: null-ptr-deref in pci_dev_is_disconnected include/linux/pci.h:2676 [inline]
    BUG: KASAN: null-ptr-deref in pci_read_config_byte+0x23/0x90 drivers/pci/access.c:562
    Read of size 4 at addr 00000000000000c4 by task scsi_eh_6/2005

    RIP: 0010:pci_dev_is_disconnected include/linux/pci.h:2676 [inline]
    RIP: 0010:pci_read_config_byte+0x23/0x90 drivers/pci/access.c:562
    ...
    stex_hard_reset  drivers/scsi/stex.c:1322 [inline] [stex]
    stex_do_reset+0x3da6/0x6490  drivers/scsi/stex.c:1424 [stex]

Skip the secondary bus reset when there is no bridge device; the rest of
the reset sequence (config space save/restore and the PCI_COMMAND poll)
does not depend on bus->self and still runs.

Signed-off-by: Yang Zi <2959243019@xxxxxx>
---
 drivers/scsi/stex.c | 23 +++++++++++++----------
 1 file changed, 13 insertions(+), 10 deletions(-)

diff --git a/drivers/scsi/stex.c b/drivers/scsi/stex.c
index 6aeeb338633d..f1dff2cc6086 100644
--- a/drivers/scsi/stex.c
+++ b/drivers/scsi/stex.c
@@ -1319,17 +1319,20 @@ static void stex_hard_reset(struct st_hba *hba)
     /* Reset secondary bus. Our controller(MU/ATU) is the only device on
        secondary bus. Consult Intel 80331/3 developer's manual for detail */
     bus = hba->pdev->bus;
-    pci_read_config_byte(bus->self, PCI_BRIDGE_CONTROL, &pci_bctl);
-    pci_bctl |= PCI_BRIDGE_CTL_BUS_RESET;
-    pci_write_config_byte(bus->self, PCI_BRIDGE_CONTROL, pci_bctl);
+    if (bus->self) {
+        pci_read_config_byte(bus->self, PCI_BRIDGE_CONTROL, &pci_bctl);
+        pci_bctl |= PCI_BRIDGE_CTL_BUS_RESET;
+        pci_write_config_byte(bus->self, PCI_BRIDGE_CONTROL, pci_bctl);
 
-    /*
-     * 1 ms may be enough for 8-port controllers. But 16-port controllers
-     * require more time to finish bus reset. Use 100 ms here for safety
-     */
-    msleep(100);
-    pci_bctl &= ~PCI_BRIDGE_CTL_BUS_RESET;
-    pci_write_config_byte(bus->self, PCI_BRIDGE_CONTROL, pci_bctl);
+        /*
+         * 1 ms may be enough for 8-port controllers. But 16-port
+         * controllers require more time to finish bus reset. Use 100 ms
+         * here for safety
+         */
+        msleep(100);
+        pci_bctl &= ~PCI_BRIDGE_CTL_BUS_RESET;
+        pci_write_config_byte(bus->self, PCI_BRIDGE_CONTROL, pci_bctl);
+    }
 
     for (i = 0; i < MU_HARD_RESET_WAIT; i++) {
         pci_read_config_word(hba->pdev, PCI_COMMAND, &pci_cmd);