From: Yu Kuai yukuai3@huawei.com
hulk inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I60QE9 CVE: NA
--------------------------------
This reverts commit 01b1ec1d028fdd78d0c763578e4b804240283b24.
Official solution will be applied to mainline, and this solution can't fix uaf for 'bd_holder_dir' thoroughly. hence revert this temporary solution. Officail solution will be backported in the next patch.
Signed-off-by: Yu Kuai yukuai3@huawei.com Reviewed-by: Jason Yan yanaijie@huawei.com Signed-off-by: Yongqiang Liu liuyongqiang13@huawei.com --- fs/block_dev.c | 2 -- 1 file changed, 2 deletions(-)
diff --git a/fs/block_dev.c b/fs/block_dev.c index 7e891e08d0ce..9868b21b8ef9 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -1650,7 +1650,6 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part) } } bdev->bd_openers++; - kobject_get(bdev->bd_part->holder_dir); if (for_part) bdev->bd_part_count++; if (mode & FMODE_WRITE) @@ -1926,7 +1925,6 @@ static void __blkdev_put(struct block_device *bdev, fmode_t mode, int for_part) if (for_part) bdev->bd_part_count--;
- kobject_put(bdev->bd_part->holder_dir); if (!--bdev->bd_openers) { WARN_ON_ONCE(bdev->bd_holders); sync_blockdev(bdev);
From: Yu Kuai yukuai3@huawei.com
hulk inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I60QE9 CVE: NA
--------------------------------
Currently, the caller of bd_link_disk_holer() get 'bdev' by blkdev_get_by_dev(), which will look up 'bdev' by inode number 'dev'. Howerver, it's possible that del_gendisk() can be called currently, and 'bd_holder_dir' can be freed before bd_link_disk_holer() access it, thus use after free is triggered.
t1: t2: bdev = blkdev_get_by_dev del_gendisk kobject_put(bd_holder_dir) kobject_free() bd_link_disk_holder
Fix the problem by checking disk is still live and grabbing a reference to 'bd_holder_dir' first in bd_link_disk_holder().
Link: https://lore.kernel.org/all/20221103025541.1875809-3-yukuai1@huaweicloud.com... Signed-off-by: Yu Kuai yukuai3@huawei.com Reviewed-by: Jason Yan yanaijie@huawei.com Signed-off-by: Yongqiang Liu liuyongqiang13@huawei.com --- fs/block_dev.c | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-)
diff --git a/fs/block_dev.c b/fs/block_dev.c index 9868b21b8ef9..f2932e84055d 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -1305,16 +1305,31 @@ int bd_link_disk_holder(struct block_device *bdev, struct gendisk *disk) struct bd_holder_disk *holder; int ret = 0;
- mutex_lock(&bdev->bd_mutex); + /* + * bdev could be deleted beneath us which would implicitly destroy + * the holder directory. Hold on to it. + */ + down_read(&bdev->bd_disk->lookup_sem); + if (!(disk->flags & GENHD_FL_UP)) { + up_read(&bdev->bd_disk->lookup_sem); + return -ENODEV; + } + + kobject_get(bdev->bd_part->holder_dir); + up_read(&bdev->bd_disk->lookup_sem);
+ mutex_lock(&bdev->bd_mutex); WARN_ON_ONCE(!bdev->bd_holder);
/* FIXME: remove the following once add_disk() handles errors */ - if (WARN_ON(!disk->slave_dir || !bdev->bd_part->holder_dir)) + if (WARN_ON(!disk->slave_dir || !bdev->bd_part->holder_dir)) { + kobject_put(bdev->bd_part->holder_dir); goto out_unlock; + }
holder = bd_find_holder_disk(bdev, disk); if (holder) { + kobject_put(bdev->bd_part->holder_dir); holder->refcnt++; goto out_unlock; } @@ -1336,11 +1351,6 @@ int bd_link_disk_holder(struct block_device *bdev, struct gendisk *disk) ret = add_symlink(bdev->bd_part->holder_dir, &disk_to_dev(disk)->kobj); if (ret) goto out_del; - /* - * bdev could be deleted beneath us which would implicitly destroy - * the holder directory. Hold on to it. - */ - kobject_get(bdev->bd_part->holder_dir);
list_add(&holder->list, &bdev->bd_holder_disks); goto out_unlock; @@ -1351,6 +1361,8 @@ int bd_link_disk_holder(struct block_device *bdev, struct gendisk *disk) kfree(holder); out_unlock: mutex_unlock(&bdev->bd_mutex); + if (ret) + kobject_put(bdev->bd_part->holder_dir); return ret; } EXPORT_SYMBOL_GPL(bd_link_disk_holder);