Re: [PATCH v6 18/27] scsi-multipath: failover handling

John Garry <[email protected]> Wed, 29 Jul 2026 16:29:41 +0100
Newsgroups org.kernel.vger.linux-scsi,dev.linux.lists.sashiko-reviews
Organization Oracle Corporation
Message-ID <[email protected]>
On 29/07/2026 16:14, [email protected] wrote:
> Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
> - [High] List corruption and use-after-free occur due to `bio_list_add_clone()` failing to nullify `master_bio->bi_next`.

master_bio->bi_next as we never create a request for the master_bio

> - [High] A use-after-free crash occurs because `cancel_work_sync()` is missing during `mpath_head` teardown.
> --
> 
> --- Patch [18]: [PATCH v6 18/27] scsi-multipath: failover handling ---
> commit d3d46b0330ddb0dc22577a7546f9765b9e1a4651
> Author: John Garry <[email protected]>
> 
> scsi-multipath: failover handling
>      
> For a scsi command which suffers failover, requeue the master bio of each
> bio attached to its request.
> 
>> diff --git a/drivers/scsi/scsi_multipath.c b/drivers/scsi/scsi_multipath.c
>> index 12750621a7fc0..6ced89576368c 100644
>> --- a/drivers/scsi/scsi_multipath.c
>> +++ b/drivers/scsi/scsi_multipath.c
>> @@ -256,10 +256,49 @@ void scsi_mpath_dev_clear_path(struct scsi_mpath_device *scsi_mpath_dev)
> [ ... ]
>> +static inline void bio_list_add_clone(struct bio_list *bl,
>> +				struct bio *clone)
>> +{
>> +	struct bio *master_bio = clone->bi_private;
>> +
>> +	if (bl->tail)
>> +		bl->tail->bi_next = master_bio;
>> +	else
>> +		bl->head = master_bio;
>> +	bl->tail = master_bio;
>> +	bio_put(clone);
>> +}
> 
> [Severity: High]
> Will this leave the newly appended list element improperly terminated?
> 
> This custom insertion into requeue_list appears to omit the standard
> master_bio->bi_next = NULL assignment for the new list tail.
> 
> If master_bio->bi_next happens to contain a stale pointer when it is added
> here, could iterating the list later result in memory corruption or memory
> being accessed after it has been freed?
> 
> [ ... ]
>> +static void scsi_mpath_clone_end_io(struct bio *clone)
>> +{
>> +	struct bio *master_bio = clone->bi_private;
>> +
>> +	if (clone->bi_status && blk_path_error(clone->bi_status)) {
> [ ... ]
>> +		spin_lock_irqsave(&mpath_head->requeue_lock, flags);
>> +		bio_list_add_clone(&mpath_head->requeue_list, clone);
>> +		spin_unlock_irqrestore(&mpath_head->requeue_lock, flags);
>> +
>> +		mpath_schedule_requeue_work(mpath_head);
> 
> [Severity: High]
> Is it possible for the scheduled requeue work item to run after the
> mpath_head structure has been torn down?

this flush is done at the disk teardown

> 
> If a device hot-unplug overlaps with I/O path errors, requeue_work is
> scheduled here.
> 
> When teardown proceeds to remove the device and drops the last reference,
> it appears scsi_mpath_head_release() frees the scsi_mpath_head structure
> without calling cancel_work_sync() first.
> 
> Could this sequence lead to a delayed kworker executing on deallocated
> memory?
>