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:
committed by
Greg Kroah-Hartman
parent
ccdc8fd86f
commit
7d680f2f76
@@ -1599,6 +1599,21 @@ static void ublk_unquiesce_dev(struct ublk_device *ub)
|
|||||||
blk_mq_kick_requeue_list(ub->ub_disk->queue);
|
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)
|
static void ublk_stop_dev(struct ublk_device *ub)
|
||||||
{
|
{
|
||||||
struct gendisk *disk;
|
struct gendisk *disk;
|
||||||
@@ -1612,14 +1627,7 @@ static void ublk_stop_dev(struct ublk_device *ub)
|
|||||||
ublk_unquiesce_dev(ub);
|
ublk_unquiesce_dev(ub);
|
||||||
}
|
}
|
||||||
del_gendisk(ub->ub_disk);
|
del_gendisk(ub->ub_disk);
|
||||||
|
disk = ublk_detach_disk(ub);
|
||||||
/* 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);
|
|
||||||
put_disk(disk);
|
put_disk(disk);
|
||||||
unlock:
|
unlock:
|
||||||
mutex_unlock(&ub->mutex);
|
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:
|
out_put_cdev:
|
||||||
if (ret) {
|
if (ret) {
|
||||||
ub->dev_info.state = UBLK_S_DEV_DEAD;
|
ublk_detach_disk(ub);
|
||||||
ublk_put_device(ub);
|
ublk_put_device(ub);
|
||||||
}
|
}
|
||||||
if (ret)
|
if (ret)
|
||||||
|
|||||||
Reference in New Issue
Block a user