Re: [PATCH v5 24/27] scsi: sd: support multipath disk

John Garry <[email protected]>
Newsgroups org.kernel.vger.linux-scsi,dev.linux.lists.sashiko-reviews
Organization Oracle Corporation
Message-ID <[email protected]>
On 27/07/2026 16:20, [email protected] wrote:
> Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
> 
> New issues:
> - [High] Concurrent path removal and addition causes a TOCTOU race that overwrites and frees the shared `mpath_head->disk`.
> - [High] Uncancelled `remove_work` triggers a Use-After-Free if a re-attached multipath disk fails probing.
> - [Medium] Missing `put_device()` on the `sd_mpath_add_disk()` error path permanently leaks `struct scsi_disk`.
> 
> Pre-existing issues:
> - [High] Direct `kfree(sdkp)` in the `sd_large_pool_create()` error path causes a use-after-free because the device is already registered in sysfs.
> --
> 
> --- Patch [24]: [PATCH v5 24/27] scsi: sd: support multipath disk ---
> commit 6b75fe218921318a27f170eca853c70058afe60d
> Author: John Garry <[email protected]>
> Subject: scsi: sd: support multipath disk
> 
> Add support to attach a multipath disk.
> 
> We still allocate the gendisk per path, and this is required for the
> per-path submission. However, those gendisks are marked as hidden. Those
> disks are named sdX:Y, where X is the multipath disk index and Y is the
> per-path index.
> 
>> diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
>> index 36c745cbb2619..f044b2dfaa9fd 100644
>> --- a/drivers/scsi/sd.c
>> +++ b/drivers/scsi/sd.c
> 
> [ ... ]
> 
>> @@ -4035,13 +4138,259 @@ static const struct attribute_group sd_mpath_disk_attr_group = {
>> +static int sd_mpath_probe(struct scsi_disk *sdkp)
>> +{
> [ ... ]
>> +	mpath_head->parent = &sd_mpath_disk->dev;
>> +	mpath_head->drv_module = THIS_MODULE;
>> +	mpath_head->disk_groups = sd_mpath_disk_attr_groups;
>> +	error = mpath_alloc_head_disk(mpath_head, &lim,
>> +				dev_to_node(dma_dev));
>> +	if (error)
>> +		goto out_free_disk;
>> +	disk = mpath_head->disk;
> 
> [ ... ]
> 
>> +static void sd_mpath_remove(struct scsi_disk *sdkp)
>> +{
> [ ... ]
>> +	mutex_lock(&sd_mpath_disks_lock);
>> +	sd_mpath_disk->disk_count--;
>> +	if (!sd_mpath_disk->disk_count && mpath_can_remove_head(mpath_head)) {
>> +		list_del_init(&sd_mpath_disk->entry);
>> +		remove = true;
>> +	}
>> +	mutex_unlock(&sd_mpath_disks_lock);
>> +	mpath_remove_sysfs_link(mpath_device);
>> +	mpath_device->disk = NULL;
>> +
>> +	if (remove) {
>> +		device_del(&sd_mpath_disk->dev);
>> +		mpath_remove_disk(mpath_head);
> 
> [Severity: High]
> Does this create a TOCTOU race that overwrites and frees the shared
> mpath_head->disk?
> 
> If sd_mpath_remove() and sd_mpath_probe() run concurrently for the same
> scsi_mpath_head (e.g., during hotplug/hot-unplug events):

If sd_mpath_probe() finds mpath_head->mpath_disk is non-NULL in 
mpath_alloc_head_disk(), it will error. Only after 
sd_mpath_disk_release() -> mpath_put_disk() is mpath_head->disk set to NULL.

> 
> The removal path drops the sd_mpath_disks_lock before tearing down
> mpath_head->disk here. A concurrent probe can then allocate and assign a new
> disk to mpath_head->disk in sd_mpath_probe().
> 
> When the removal thread resumes, it deletes and frees the new disk while the
> probe thread proceeds to use it, causing a use-after-free.
> 
>> +	}
>> +	sd_mpath_put_disk(sd_mpath_disk);
>> +}
> 
> [ ... ]
> 
>> +static void sd_mpath_fail_probe(struct scsi_disk *sdkp)
>> +{
> [ ... ]
>> +	mutex_lock(&sd_mpath_disks_lock);
>> +	sd_mpath_disk->disk_count--;
>> +	if (!sd_mpath_disk->disk_count) {
>> +		list_del_init(&sd_mpath_disk->entry);
>> +		remove = true;
>> +	}
>> +	mutex_unlock(&sd_mpath_disks_lock);
>> +	mpath_device->disk = NULL;
>> +
>> +	if (remove) {
>> +		device_del(&sd_mpath_disk->dev);
>> +		mpath_remove_disk(mpath_head);
>> +	}
>> +	sd_mpath_put_disk(sd_mpath_disk);
> 
> [Severity: High]
> Can an uncancelled remove_work trigger a use-after-free here if a re-attached
> multipath disk fails probing?
> 
> A delayed removal is scheduled when the last path is removed. A new path is
> then rapidly probed, incrementing the disk count, but fails midway through
> sd_probe().
> 
> This cleanup function decrements the count back to 0 and frees sd_mpath_disk
> and scsi_mpath_head, but it does NOT cancel the pending remove_work (which
> would normally be cancelled later in sd_mpath_add_disk()). The scheduled work
> will subsequently execute on freed memory.

I'll fix it

> 
>> +}
> 
> [ ... ]
> 
>> @@ -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 isn't a bug introduced by this patch, but does the direct kfree(sdkp) in
> the sd_large_pool_create() error path cause a use-after-free because the
> device is already registered in sysfs?
> 
> After device_add(&sdkp->disk_dev) succeeds earlier in sd_probe(), the device
> is exposed to sysfs. If sd_large_pool_create() fails, the code branches to
> out_free_index which directly calls kfree(sdkp) without unregistering the
> sysfs device, leaving dangling pointers in the sysfs tree.
> 
>>   		}
>>   	}
> 
> [ ... ]
> 
>> @@ -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: Medium]
> Will this error path leak the struct scsi_disk?
> 
> A failure in sd_mpath_add_disk() triggers the error handling path which calls
> device_del() but misses the corresponding put_device().
> 
> Because the kobject reference is never dropped, scsi_disk_release() is never
> invoked, permanently leaking the memory.

this all needs to be fixed in mkp- scsi treee

> 
>> +		}
>> +	}
>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.