]> www.infradead.org Git - nvme.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)
committerJens Axboe <axboe@kernel.dk>
Thu, 26 Dec 2024 13:42:55 +0000 (06:42 -0700)
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>
drivers/block/ublk_drv.c

index d4aed12dd436be4cdc1d70894ba657503dcf0d94..934ab9332c80abea9ab10bdc2928284f758338e4 100644 (file)
@@ -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)