Re: [PATCH v6 24/27] scsi: sd: support multipath disk
[email protected] Wed, 29 Jul 2026 17:01:40 +0000
| Newsgroups | org.kernel.vger.linux-scsi |
|---|---|
| Message-ID | <[email protected]> |
Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider: New issues: - [High] Missing `put_device()` in the `sd_mpath_add_disk()` error path permanently leaks the `sdkp` structure. - [High] Inverted device teardown order causes double `device_del()` and sysfs warnings. - [High] Cyclic kobject reference between `sd_mpath_disk` and its child gendisk guarantees both are permanently leaked on removal. - [Medium] Ignored return value of `scsi_mpath_get_head()` leads to potential kref underflow and use-after-free. Pre-existing issues: - [High] `kfree()` is called on an active kobject when `sd_large_pool_create()` fails, leading to UAF / Sysfs Corruption. -- --- Patch [24]: [PATCH v6 24/27] scsi: sd: support multipath disk --- commit 1896d58c043437e813525b463ccbb2249c843f33 Author: John Garry <[email protected]> scsi: sd: support multipath disk This commit adds support for attaching a multipath disk in the SCSI sd subsystem. It allocates gendisks per-path but marks them as hidden, and maintains a global list of sd_mpath_disks to match with scsi_devices. > --- a/drivers/scsi/sd.c > +++ b/drivers/scsi/sd.c > @@ -115,12 +115,30 @@ static mempool_t *sd_large_page_pool; > static atomic_t sd_large_page_pool_users = ATOMIC_INIT(0); > static struct lock_class_key sd_bio_compl_lkclass; > #ifdef CONFIG_SCSI_MULTIPATH > +static LIST_HEAD(sd_mpath_disks_list); > +static DEFINE_MUTEX(sd_mpath_disks_lock); > + > struct sd_mpath_disk { > + struct device dev; > + int disk_index; > + int disk_count; > + struct list_head entry; > struct scsi_mpath_head *scsi_mpath_head; > }; > > static void sd_mpath_disk_release(struct device *dev) > { > + struct sd_mpath_disk *sd_mpath_disk = > + container_of(dev, struct sd_mpath_disk, dev); > + struct scsi_mpath_head *scsi_mpath_head = > + sd_mpath_disk->scsi_mpath_head; > + struct mpath_head *mpath_head = &scsi_mpath_head->mpath_head; > + > + mpath_put_disk(mpath_head); [Severity: High] Does this create an unbreakable cyclic kobject reference? The child disk is created as a child of sd_mpath_disk->dev, meaning it holds a reference to the parent. If the child's reference is only dropped via mpath_put_disk() inside the parent's release function (sd_mpath_disk_release), the parent's release function will never execute because the child still holds a reference to it. Will this permanently leak both the sd_mpath_disk and the multipath gendisk on removal? [ ... ] > @@ -4035,13 +4138,259 @@ static const struct attribute_group sd_mpath_disk_attr_group = { > .attrs = sd_mpath_disk_attrs, > }; > > +static int sd_mpath_probe(struct scsi_disk *sdkp) > +{ [ ... ] > + device_initialize(&sd_mpath_disk->dev); > + sd_mpath_disk->dev.class = &sd_mpath_disk_class; > + > + /* undone in sd_mpath_disk_release() */ > + scsi_mpath_get_head(scsi_mpath_head); [Severity: Medium] Is it safe to ignore the return value here? In sd_mpath_probe(), scsi_mpath_get_head() is called but its return value is discarded. Since scsi_mpath_get_head() explicitly uses kref_get_unless_zero() and can return -ENXIO, could a failure lead to a refcount underflow and a use-after-free during the release path? [ ... ] > +static void sd_mpath_remove(struct scsi_disk *sdkp) > +{ [ ... ] > + if (remove) { > + device_del(&sd_mpath_disk->dev); > + mpath_remove_disk(mpath_head); > + } > + sd_mpath_put_disk(sd_mpath_disk); > +} [Severity: High] Is this device teardown order inverted? In sd_mpath_remove() and the related sd_mpath_remove_head(), the parent device (sd_mpath_disk->dev) is deleted via device_del() before the child gendisk is removed via mpath_remove_disk(). Does this cause double device_del() operations or sysfs hierarchy corruption, since the device model requires children to be unregistered before their parents? [ ... ] > +static void sd_mpath_fail_probe(struct scsi_disk *sdkp) > +{ [ ... ] > + if (remove) { > + device_del(&sd_mpath_disk->dev); > + mpath_remove_disk(mpath_head); > + } > + sd_mpath_put_disk(sd_mpath_disk); > +} [Severity: High] Does the same inverted teardown order apply here in sd_mpath_fail_probe()? Deleting the parent device before the child gendisk violates the device model requirements and can trigger sysfs warnings. [ ... ] > @@ -4158,11 +4515,18 @@ static int sd_probe(struct scsi_device *sdp) > sd_revalidate_disk(gd); > if (sdp->sector_size > PAGE_SIZE) { > if (sd_large_pool_create()) { > + sd_mpath_fail_probe(sdkp); > error = -ENOMEM; > goto out_free_index; > } > } [Severity: High] This is a pre-existing issue, but does jumping to out_free_index here leak the active kobject? In sd_probe(), device_add(&sdkp->disk_dev) has already succeeded earlier in the function. When sd_large_pool_create() fails, it jumps to out_free_index and eventually calls kfree(sdkp). Should this error path use device_del() and put_device() instead to prevent sysfs corruption and a use-after-free on the active kobject? [ ... ] > @@ -4177,6 +4541,7 @@ static int sd_probe(struct scsi_device *sdp) [ ... ] > error = device_add_disk(dev, gd, NULL); > if (error) { > + sd_mpath_fail_probe(sdkp); > device_unregister(&sdkp->disk_dev); > put_disk(gd); > if (sdp->sector_size > PAGE_SIZE) > @@ -4184,6 +4549,19 @@ static int sd_probe(struct scsi_device *sdp) > goto out; > } > > + if (sdp->scsi_mpath_dev) { > + error = sd_mpath_add_disk(sdkp); > + if (error) { > + sd_mpath_fail_probe(sdkp); > + device_del(&sdkp->disk_dev); > + del_gendisk(sdkp->disk); > + > + put_disk(sdkp->disk); > + if (sdp->sector_size > PAGE_SIZE) > + sd_large_pool_destroy(); > + goto out; > + } > + } [Severity: High] Does this error path leak the sdkp structure? In sd_probe(), if sd_mpath_add_disk() fails, the code manually calls device_del() and del_gendisk() but entirely omits put_device(&sdkp->disk_dev). Because the initial reference count set by device_initialize() is never decremented to zero, will this permanently leak the scsi_disk structure and its associated resources? -- Sashiko AI review ยท https://sashiko.dev/#/patchset/[email protected]?part=24