summaryrefslogtreecommitdiff
path: root/drivers/block
diff options
context:
space:
mode:
authorMing Lei <ming.lei@redhat.com>2024-12-25 19:06:40 +0800
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2025-01-02 10:34:20 +0100
commit7d680f2f76a3417fdfc3946da7471e81464f7b41 (patch)
treeb1ec11aeaa74eb56dfa95852db5279927e1c8a22 /drivers/block
parentccdc8fd86fc7b34630bc1ce2da26537219f8b473 (diff)
downloadlinux-7d680f2f76a3417fdfc3946da7471e81464f7b41.tar.gz
linux-7d680f2f76a3417fdfc3946da7471e81464f7b41.tar.bz2
linux-7d680f2f76a3417fdfc3946da7471e81464f7b41.zip
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: bd23f6c2c2d0 ("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>
Diffstat (limited to 'drivers/block')
-rw-r--r--drivers/block/ublk_drv.c26
1 files changed, 17 insertions, 9 deletions
diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c
index 90bc605ff6c2..458ac54e7b20 100644
--- a/drivers/block/ublk_drv.c
+++ b/drivers/block/ublk_drv.c
@@ -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)