]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
ublk: detach gendisk from ublk device if add_disk() fails
authorMing Lei <ming.lei@redhat.com>
Wed, 25 Dec 2024 11:06:40 +0000 (19:06 +0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 2 Jan 2025 09:34:20 +0000 (10:34 +0100)
[ 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>
drivers/block/ublk_drv.c

index 90bc605ff6c299550ddf6665f54e9c602a34623b..458ac54e7b201e140a8c569e940639eb093bca8a 100644 (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)