Commit 75cd4005 authored by Ming Lei's avatar Ming Lei Committed by Jens Axboe
Browse files

ublk: detach gendisk from ublk device if add_disk() fails



Inside ublk_abort_requests(), gendisk is grabbed for aborting all
inflight requests. And ublk_abort_requests() is called when exiting
the uring context or handling timeout.

If add_disk() fails, the gendisk may have been freed when calling
ublk_abort_requests(), so use-after-free can be caused when getting
disk's reference in ublk_abort_requests().

Fixes the bug by detaching gendisk from ublk device if add_disk() fails.

Fixes: bd23f6c2 ("ublk: quiesce request queue when aborting queue")
Signed-off-by: default avatarMing Lei <ming.lei@redhat.com>
Link: https://lore.kernel.org/r/20241225110640.351531-1-ming.lei@redhat.com


Signed-off-by: default avatarJens Axboe <axboe@kernel.dk>
parent 85672ca9
Loading
Loading
Loading
Loading
+17 −9
Original line number Diff line number Diff line
@@ -1618,6 +1618,21 @@ static void ublk_unquiesce_dev(struct ublk_device *ub)
	blk_mq_kick_requeue_list(ub->ub_disk->queue);
}

static struct gendisk *ublk_detach_disk(struct ublk_device *ub)
{
	struct gendisk *disk;

	/* Sync with ublk_abort_queue() by holding the lock */
	spin_lock(&ub->lock);
	disk = ub->ub_disk;
	ub->dev_info.state = UBLK_S_DEV_DEAD;
	ub->dev_info.ublksrv_pid = -1;
	ub->ub_disk = NULL;
	spin_unlock(&ub->lock);

	return disk;
}

static void ublk_stop_dev(struct ublk_device *ub)
{
	struct gendisk *disk;
@@ -1631,14 +1646,7 @@ static void ublk_stop_dev(struct ublk_device *ub)
		ublk_unquiesce_dev(ub);
	}
	del_gendisk(ub->ub_disk);

	/* Sync with ublk_abort_queue() by holding the lock */
	spin_lock(&ub->lock);
	disk = ub->ub_disk;
	ub->dev_info.state = UBLK_S_DEV_DEAD;
	ub->dev_info.ublksrv_pid = -1;
	ub->ub_disk = NULL;
	spin_unlock(&ub->lock);
	disk = ublk_detach_disk(ub);
	put_disk(disk);
 unlock:
	mutex_unlock(&ub->mutex);
@@ -2336,7 +2344,7 @@ static int ublk_ctrl_start_dev(struct ublk_device *ub, struct io_uring_cmd *cmd)

out_put_cdev:
	if (ret) {
		ub->dev_info.state = UBLK_S_DEV_DEAD;
		ublk_detach_disk(ub);
		ublk_put_device(ub);
	}
	if (ret)