Re: [PATCH v6 16/27] scsi-multipath: clear path when device is blocked
John Garry <[email protected]> Wed, 29 Jul 2026 15:51:41 +0100
| Newsgroups | org.kernel.vger.linux-scsi,dev.linux.lists.sashiko-reviews |
|---|---|
| Organization | Oracle Corporation |
| Message-ID | <[email protected]> |
On 29/07/2026 15:42, [email protected] wrote: > Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: > - [High] Unprotected, lockless access to `sdev->scsi_mpath_dev` in `scsi_device_block()` causes NULL pointer dereferences and Use-After-Free (UAF) bugs when racing with device initialization or teardown. > -- > Same as v5, there should be not races > --- Patch [16]: [PATCH v6 16/27] scsi-multipath: clear path when device is blocked --- > commit 8f07d9f873129f9ecc9b8d3d02fee5bce667c745 > Author: John Garry <[email protected]> > > scsi-multipath: clear path when device is blocked > > Add scsi_mpath_dev_clear_path() to clear a device path when it becomes > blocked. > >> diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c >> index daeb3693fe559..a1ec11050090c 100644 >> --- a/drivers/scsi/scsi_lib.c >> +++ b/drivers/scsi/scsi_lib.c > > [ ... ] > >> @@ -3008,6 +3009,8 @@ static void scsi_device_block(struct scsi_device *sdev, void *data) >> scsi_stop_queue(sdev); >> >> mutex_unlock(&sdev->state_mutex); >> + if ((err == 0) && sdev->scsi_mpath_dev) >> + scsi_mpath_dev_clear_path(sdev->scsi_mpath_dev); > > [Severity: High] > Is it safe to access sdev->scsi_mpath_dev without holding state_mutex? > > When scsi_alloc_sdev() adds a new device to shost->__devices, it becomes > globally visible. Then scsi_mpath_dev_alloc() sets sdev->scsi_mpath_dev but > leaves scsi_mpath_head as NULL while issuing SCSI VPD queries. > > If a concurrent error on the bus triggers scsi_device_block(), it could > read the partially initialized sdev->scsi_mpath_dev here outside of any locks. > > Additionally, if scsi_mpath_dev_alloc() encounters an error and frees > sdev->scsi_mpath_dev, could reading it here cause a use-after-free? > > During teardown, if __scsi_remove_device() is called concurrently with > scsi_device_block(), the teardown thread might set scsi_mpath_head to NULL. > Can this lead to a NULL pointer dereference when evaluating > scsi_mpath_dev_clear_path()? > >> >> WARN_ONCE(err, "%s: failed to block %s in state %d\n", >> __func__, dev_name(&sdev->sdev_gendev), state); > > [ ... ] > >> diff --git a/drivers/scsi/scsi_multipath.c b/drivers/scsi/scsi_multipath.c >> index 0d439cac6447a..b23cd6f12c602 100644 >> --- a/drivers/scsi/scsi_multipath.c >> +++ b/drivers/scsi/scsi_multipath.c > > [ ... ] > >> @@ -238,6 +238,16 @@ static int scsi_multipath_sdev_init(struct scsi_device *sdev) >> return 0; >> } >> >> +void scsi_mpath_dev_clear_path(struct scsi_mpath_device *scsi_mpath_dev) >> +{ >> + struct mpath_device *mpath_device = &scsi_mpath_dev->mpath_device; >> + struct scsi_mpath_head *scsi_mpath_head = scsi_mpath_dev->scsi_mpath_head; >> + struct mpath_head *mpath_head = &scsi_mpath_head->mpath_head; > > [Severity: High] > Does this code dereference a NULL pointer if it races with initialization or > teardown? > > If scsi_mpath_head is NULL due to the races mentioned above, deriving > mpath_head from it will calculate an invalid pointer. > >> + >> + if (mpath_clear_current_path(mpath_device)) > > [Severity: High] > Could calling mpath_clear_current_path() with a partially initialized > mpath_device lead to a NULL pointer dereference? > > If mpath_device->mpath_head is NULL, it will trigger an immediate dereference > in the multipath code: > > lib/multipath.c:mpath_clear_current_path() { > ... > struct mpath_head *mpath_head = mpath_device->mpath_head; > ... > if (mpath_device == > rcu_access_pointer(mpath_head->current_path[node])) { > ... > } > >> + mpath_synchronize(mpath_head); >> +} >