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

[ Upstream commit 75cd4005da5492129917a4a4ee45e81660556104 ]

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: bd23f6c2c2 ("ublk: quiesce request queue when aborting queue")
Signed-off-by: Ming Lei <ming.lei@redhat.com>
Link: https://lore.kernel.org/r/20241225110640.351531-1-ming.lei@redhat.com
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
Ming Lei
2024-12-25 19:06:40 +08:00
committed by Greg Kroah-Hartman
parent ccdc8fd86f
commit 7d680f2f76

View File

@@ -1599,6 +1599,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;
@@ -1612,14 +1627,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);
@@ -2295,7 +2303,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)