From: Christoph Hellwig hch@lst.de
mainline inclusion from mainline-v5.13-rc1 commit c76f48eb5c084b1e15c931ae8cc1826cd771d70d category: bugfix bugzilla: 55097 CVE: NA
--------------------------------
There is nothing preventing an ioctl from trying do delete partition concurrenly with del_gendisk, so take open_mutex to serialize against that.
Signed-off-by: Christoph Hellwig hch@lst.de Link: https://lore.kernel.org/r/20210406062303.811835-6-hch@lst.de Signed-off-by: Jens Axboe axboe@kernel.dk Conflicts: block/genhd.c block/partitions/core.c [Yufen: linux-4.19 have not extract blk_drop_partitions().] Signed-off-by: Yufen Yu yuyufen@huawei.com Reviewed-by: Jason Yan yanaijie@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- block/genhd.c | 11 +++++++++++ 1 file changed, 11 insertions(+)
diff --git a/block/genhd.c b/block/genhd.c index 026d3f41c85a1..686a54698aa02 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -756,6 +756,7 @@ void del_gendisk(struct gendisk *disk) { struct disk_part_iter piter; struct hd_struct *part; + struct block_device *bdev;
blk_integrity_del(disk); disk_del_events(disk); @@ -765,6 +766,14 @@ void del_gendisk(struct gendisk *disk) * disk is marked as dead (GENHD_FL_UP cleared). */ down_write(&disk->lookup_sem); + + /* + * If bdev is null, that menas memory allocate fail. Then + * add_partitions can also fail. + */ + bdev = bdget_disk(disk, 0); + if (bdev) + mutex_lock(&bdev->bd_mutex); /* invalidate stuff */ disk_part_iter_init(&piter, disk, DISK_PITER_INCL_EMPTY | DISK_PITER_REVERSE); @@ -774,6 +783,8 @@ void del_gendisk(struct gendisk *disk) delete_partition(disk, part->partno); } disk_part_iter_exit(&piter); + if (bdev) + mutex_unlock(&bdev->bd_mutex);
invalidate_partition(disk, 0); bdev_unhash_inode(disk_devt(disk));
From: Yufen Yu yuyufen@huawei.com
hulk inclusion category: feature bugzilla: 55097 CVE: NA
-------------------------------------------------
For now, there is no mechanism that can provent ioctl to call add_partition after del_gendisk() have called delete_partition(). Then, invalid symlinks file may be created into /sys/class/block.
We try to fix this problem by setting GENHD_FL_UP early in del_gendisk() and check the flag before adding partitions likely that do in mainline kernel. Since all of them are cover by bdev->bd_mutex, either add_partition success but will delete by del_gendisk(), or add_partition will fail return as GENHD_FL_UP have been cleared.
Signed-off-by: Yufen Yu yuyufen@huawei.com Reviewed-by: Jason Yan yanaijie@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- block/genhd.c | 2 +- block/ioctl.c | 4 ++++ block/partition-generic.c | 3 +++ 3 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/block/genhd.c b/block/genhd.c index 686a54698aa02..408cda8af4eba 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -774,6 +774,7 @@ void del_gendisk(struct gendisk *disk) bdev = bdget_disk(disk, 0); if (bdev) mutex_lock(&bdev->bd_mutex); + disk->flags &= ~GENHD_FL_UP; /* invalidate stuff */ disk_part_iter_init(&piter, disk, DISK_PITER_INCL_EMPTY | DISK_PITER_REVERSE); @@ -789,7 +790,6 @@ void del_gendisk(struct gendisk *disk) invalidate_partition(disk, 0); bdev_unhash_inode(disk_devt(disk)); set_capacity(disk, 0); - disk->flags &= ~GENHD_FL_UP; up_write(&disk->lookup_sem);
if (!(disk->flags & GENHD_FL_HIDDEN)) diff --git a/block/ioctl.c b/block/ioctl.c index 899ffd50a7c6b..3bcfc8dc32fad 100644 --- a/block/ioctl.c +++ b/block/ioctl.c @@ -50,6 +50,10 @@ static int blkpg_ioctl(struct block_device *bdev, struct blkpg_ioctl_arg __user return -EINVAL;
mutex_lock(&bdev->bd_mutex); + if (!(disk->flags & GENHD_FL_UP)) { + mutex_unlock(&bdev->bd_mutex); + return -ENXIO; + }
/* overlap? */ disk_part_iter_init(&piter, disk, diff --git a/block/partition-generic.c b/block/partition-generic.c index 63b82df5bbb40..ddaa5d41139c6 100644 --- a/block/partition-generic.c +++ b/block/partition-generic.c @@ -525,6 +525,9 @@ int rescan_partitions(struct gendisk *disk, struct block_device *bdev) struct parsed_partitions *state = NULL; struct hd_struct *part; int p, highest, res; + + if (!(disk->flags & GENHD_FL_UP)) + return -ENXIO; rescan: if (state && !IS_ERR(state)) { free_partitions(state);