Linux ATA/IDE development
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Gary Guo" <gary@garyguo.net>
Cc: cassel@kernel.org, dri-devel@lists.freedesktop.org,
	linux-scsi@vger.kernel.org, linux-pci@vger.kernel.org,
	dlemoal@kernel.org, linux-ide@vger.kernel.org
Subject: Re: [PATCH v4 2/9] scsi: nsp32: don't store pci_device_id
Date: Fri, 24 Jul 2026 22:02:06 +0000	[thread overview]
Message-ID: <20260724220207.3CE731F000E9@smtp.kernel.org> (raw)
In-Reply-To: <20260723-pci_id_fix-v4-2-3580726844e1@garyguo.net>

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-bounds read of the `nsp32_model` array.
- [High] Missing cleanup of PCI resources and MMIO mapping on probe error path, 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` locklessly in the ISR.
- [High] Returning a positive value instead of a negative error code on probe 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 <gary@garyguo.net>

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, struct Scsi_Host *host)
>  		   (nsp32_read2(base, INDEX_REG) >> 8) & 0xff);
>  
>  	mode_reg = nsp32_index_read1(base, CHIP_MODE);
> -	model    = data->pci_devid->driver_data;
> +	model    = 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)
>  	}
>  
>  	data->Pci	  = pdev;
> -	data->pci_devid   = id;
> +	data->model       = 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 probes?

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

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

nsp32_detect() then copies it to the per-device hostdata. If multiple devices
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_drvdata()
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   = pdev->irq;
>  	data->BaseAddress = pci_resource_start(pdev, 0);
>  	data->NumAddress  = 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 {
>  
>  	struct scsi_cmnd *CurrentSC;
>  
> -	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 = data->CurrentSC is fetched locklessly before
acquiring host->host_lock. 

If the EH thread completes the command concurrently, it frees the DMA mapping,
calls scsi_done(), and sets data->CurrentSC = 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.

>  
>  	char info_str[100];

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260723-pci_id_fix-v4-0-3580726844e1@garyguo.net?part=2

  reply	other threads:[~2026-07-24 22:02 UTC|newest]

Thread overview: 22+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-23 22:00 [PATCH v4 0/9] PCI: Fix UAF and TOCTOU related to dynamic ID Gary Guo
2026-07-23 22:00 ` [PATCH v4 1/9] ata: ata_generic: don't store pci_device_id Gary Guo
2026-07-24 22:02   ` sashiko-bot
2026-07-23 22:00 ` [PATCH v4 2/9] scsi: nsp32: " Gary Guo
2026-07-24 22:02   ` sashiko-bot [this message]
2026-07-23 22:00 ` [PATCH v4 3/9] ipack: tpci200: " Gary Guo
2026-07-24 22:02   ` sashiko-bot
2026-07-23 22:00 ` [PATCH v4 4/9] mlxsw: pci: " Gary Guo
2026-07-24 22:02   ` sashiko-bot
2026-07-23 22:00 ` [PATCH v4 5/9] agp/via: Don't rely on address of pci_device_id Gary Guo
2026-07-24 22:02   ` sashiko-bot
2026-07-23 22:00 ` [PATCH v4 6/9] agp/amd-k7: " Gary Guo
2026-07-24 22:02   ` sashiko-bot
2026-07-23 22:00 ` [PATCH v4 7/9] PCI: Make pci_match_one_device() match on ID instead of device Gary Guo
2026-07-24 22:02   ` sashiko-bot
2026-07-24 22:29   ` Bjorn Helgaas
2026-07-23 22:00 ` [PATCH v4 8/9] PCI: Fix dyn_id add TOCTOU Gary Guo
2026-07-24 22:02   ` sashiko-bot
2026-07-24 22:29   ` Bjorn Helgaas
2026-07-23 22:00 ` [PATCH v4 9/9] PCI: Fix UAF when probe runs concurrent to dyn ID removal Gary Guo
2026-07-24 22:02   ` sashiko-bot
2026-07-24 22:30   ` Bjorn Helgaas

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260724220207.3CE731F000E9@smtp.kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=cassel@kernel.org \
    --cc=dlemoal@kernel.org \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=gary@garyguo.net \
    --cc=linux-ide@vger.kernel.org \
    --cc=linux-pci@vger.kernel.org \
    --cc=linux-scsi@vger.kernel.org \
    --cc=sashiko-reviews@lists.linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox