Re: [PATCH v4 2/9] scsi: nsp32: don't store pci_device_id

[email protected] Fri, 24 Jul 2026 22:02:06 +0000
Newsgroups org.kernel.vger.linux-ide,org.freedesktop.lists.dri-devel,org.kernel.vger.linux-pci,org.kernel.vger.linux-scsi
Message-ID <[email protected]>
Thank you for your contribution! Sashiko AI review found 5 potential issue(=
s) to consider:

Pre-existing issues:
- [High] Unvalidated `driver_data` from dynamic PCI IDs causes an out-of-bo=
unds read of the `nsp32_model` array.
- [High] Missing cleanup of PCI resources and MMIO mapping on probe error p=
ath, and missing disable on removal.
- [High] Unprotected global `nsp32_data_base` causes race conditions during=
 concurrent device probes.
- [High] Time-of-Check to Time-of-Use (TOCTOU) race fetching `CurrentSC` lo=
cklessly in the ISR.
- [High] Returning a positive value instead of a negative error code on pro=
be failure tricks the PCI core into assuming success, causing a subsequent =
NULL pointer dereference.
--

--- Patch [2]: [PATCH v4 2/9] scsi: nsp32: don't store pci_device_id ---
commit d3fbc37c7e8ddff13dd3c674aa1a8a1d1f511010
Author: Gary Guo <[email protected]>

scsi: nsp32: don't store pci_device_id

pci_device_id is not guaranteed to live longer than probe due to presence
of dynamic ID. All information apart from driver_data can be easily
retrieved from pci_dev, so just store driver_data.

> diff --git a/drivers/scsi/nsp32.c b/drivers/scsi/nsp32.c
> index e893d56772417..9c9281222a0ac 100644
> --- a/drivers/scsi/nsp32.c
> +++ b/drivers/scsi/nsp32.c
> @@ -1470,7 +1470,7 @@ static int nsp32_show_info(struct seq_file *m, stru=
ct Scsi_Host *host)
>  		   (nsp32_read2(base, INDEX_REG) >> 8) & 0xff);
> =20
>  	mode_reg =3D nsp32_index_read1(base, CHIP_MODE);
> -	model    =3D data->pci_devid->driver_data;
> +	model    =3D data->model;

[Severity: High]
This isn't a bug introduced by this patch, but does this unvalidated model
value (derived from id->driver_data via sysfs new_id) cause an out-of-bounds
read of the fixed-size nsp32_model array?

If a large value for driver_data is supplied, this happens just below when
reading the procfs file:

nsp32_show_info():
    seq_printf(m, "OEM:                   %ld, %s\n",
           (mode_reg & (OEM0|OEM1)), nsp32_model[model]);

The same out-of-bounds read also appears in nsp32_probe() during logging.

[ ... ]

> @@ -3340,7 +3340,7 @@ static int nsp32_probe(struct pci_dev *pdev, const =
struct pci_device_id *id)
>  	}
> =20
>  	data->Pci	  =3D pdev;
> -	data->pci_devid   =3D id;
> +	data->model       =3D id->driver_data;

[Severity: High]
This is a pre-existing issue, but does the lockless use of the global
nsp32_data_base struct cause race conditions during concurrent device probe=
s?

nsp32_probe() writes device-specific resources to this shared global struct:

nsp32_probe():
    nsp32_hw_data *data =3D &nsp32_data_base;
    ...
    data->Pci =3D pdev;
    data->model =3D id->driver_data;
    data->MmioAddress =3D pci_ioremap_bar(pdev, 1);

nsp32_detect() then copies it to the per-device hostdata. If multiple devic=
es
are probed concurrently (e.g., async probe or hotplug), threads might race =
to
overwrite these fields, causing devices to steal each other's MMIO mappings.

[Severity: High]
This is another pre-existing issue, but doesn't the error path of
nsp32_probe() fail to clean up PCI resources?

If nsp32_detect() fails, nsp32_probe() returns the error without unmapping
data->MmioAddress or calling pci_disable_device(). Also, on the normal
removal path, nsp32_release() unmaps the IO but entirely skips
pci_disable_device().

[Severity: High]
This is also a pre-existing issue, but does nsp32_detect() returning 1
instead of a negative error code on failure cause issues with the PCI core?

nsp32_probe() propagates this positive value, which the PCI core treats as
success in local_pci_probe(), binding the device even though pci_set_drvdat=
a()
was skipped. When the device is later unbound, nsp32_remove() retrieves a
NULL driver data pointer and passes it to scsi_remove_host(), triggering a
NULL pointer dereference.

>  	data->IrqNumber   =3D pdev->irq;
>  	data->BaseAddress =3D pci_resource_start(pdev, 0);
>  	data->NumAddress  =3D pci_resource_len  (pdev, 0);
> diff --git a/drivers/scsi/nsp32.h b/drivers/scsi/nsp32.h
> index 924889f8bd37e..9e65771cb5928 100644
> --- a/drivers/scsi/nsp32.h
> +++ b/drivers/scsi/nsp32.h
> @@ -564,10 +564,10 @@ typedef struct _nsp32_hw_data {
> =20
>  	struct scsi_cmnd *CurrentSC;
> =20
> -	struct pci_dev             *Pci;
> -	const struct pci_device_id *pci_devid;
> -	struct Scsi_Host           *Host;
> -	spinlock_t                  Lock;
> +	struct pci_dev    *Pci;
> +	int                model;
> +	struct Scsi_Host  *Host;
> +	spinlock_t         Lock;

[Severity: High]
This isn't a bug introduced by this patch, but is there a Time-of-Check to
Time-of-Use (TOCTOU) race condition when fetching CurrentSC in the ISR?

In do_nsp32_isr(), SCpnt =3D data->CurrentSC is fetched locklessly before
acquiring host->host_lock.=20

If the EH thread completes the command concurrently, it frees the DMA mappi=
ng,
calls scsi_done(), and sets data->CurrentSC =3D NULL. The ISR thread might
subsequently acquire the lock and use the stale pre-fetched SCpnt pointer
to modify its result and call nsp32_scsi_done() again, potentially causing a
use-after-free and double completion.

> =20
>  	char info_str[100];

--=20
Sashiko AI review =C2=B7 https://sashiko.dev/#/patchset/20260723-pci_id_fix=
[email protected]?part=3D2