Message ID | 20220325063929.1773899-12-hch@lst.de (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | [01/14] nbd: use the correct block_device in nbd_bdev_reset | expand |
On 2022/03/25 15:39, Christoph Hellwig wrote: > Ensure that the lo_device which is stored in the gendisk private > data is valid until the gendisk is freed. Currently the loop driver > uses a lot of effort to make sure a device is not freed when it is > still in use, but to to fix a potential deadlock this will be relaxed > a bit soon. This patch breaks blk_cleanup_disk() into blk_cleanup_queue() and put_disk() on loop_remove() side only. But there is blk_cleanup_disk() in the error path of loop_add() side. Don't we need to rewrite the error path of loop_add() side, for put_disk() from blk_cleanup_disk() from loop_add() calls kfree() via lo_free_disk() but out_cleanup_disk: label falls through to blk_mq_free_tag_set() (which seems to be UAF read) and kfree() (which seems to be double kfree()) ?
On 2022/03/25 19:42, Tetsuo Handa wrote: > On 2022/03/25 15:39, Christoph Hellwig wrote: >> Ensure that the lo_device which is stored in the gendisk private >> data is valid until the gendisk is freed. Currently the loop driver >> uses a lot of effort to make sure a device is not freed when it is >> still in use, but to to fix a potential deadlock this will be relaxed >> a bit soon. > > This patch breaks blk_cleanup_disk() into blk_cleanup_queue() and put_disk() on > loop_remove() side only. But there is blk_cleanup_disk() in the error path of > loop_add() side. Don't we need to rewrite the error path of loop_add() side, for > put_disk() from blk_cleanup_disk() from loop_add() calls kfree() via lo_free_disk() > but out_cleanup_disk: label falls through to blk_mq_free_tag_set() (which seems to > be UAF read) and kfree() (which seems to be double kfree()) ? > Ah, since set_bit(GD_ADDED, &disk->state) is not called unless device_add_disk() from add_disk() succeeds, disk->fops->free_disk will not be called unless add_disk() succeeds. Thus, it is OK for the error path of loop_add(). Tricky call...
diff --git a/drivers/block/loop.c b/drivers/block/loop.c index a5dd259958ee2..b3170e8cdbe95 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -1765,6 +1765,14 @@ static void lo_release(struct gendisk *disk, fmode_t mode) mutex_unlock(&lo->lo_mutex); } +static void lo_free_disk(struct gendisk *disk) +{ + struct loop_device *lo = disk->private_data; + + mutex_destroy(&lo->lo_mutex); + kfree(lo); +} + static const struct block_device_operations lo_fops = { .owner = THIS_MODULE, .open = lo_open, @@ -1773,6 +1781,7 @@ static const struct block_device_operations lo_fops = { #ifdef CONFIG_COMPAT .compat_ioctl = lo_compat_ioctl, #endif + .free_disk = lo_free_disk, }; /* @@ -2064,15 +2073,14 @@ static void loop_remove(struct loop_device *lo) { /* Make this loop device unreachable from pathname. */ del_gendisk(lo->lo_disk); - blk_cleanup_disk(lo->lo_disk); + blk_cleanup_queue(lo->lo_disk->queue); blk_mq_free_tag_set(&lo->tag_set); mutex_lock(&loop_ctl_mutex); idr_remove(&loop_index_idr, lo->lo_number); mutex_unlock(&loop_ctl_mutex); - /* There is no route which can find this loop device. */ - mutex_destroy(&lo->lo_mutex); - kfree(lo); + + put_disk(lo->lo_disk); } static void loop_probe(dev_t dev)