From: Christoph Hellwig hch@lst.de
[ Upstream commit 08fc1ab6d748ab1a690fd483f41e2938984ce353 ]
We need to hold the whole device bd_mutex to protect against other thread concurrently deleting out partition before we get to it, and thus causing a use after free.
Fixes: cddae808aeb7 ("block: pass a hd_struct to delete_partition") Reported-by: syzbot+6448f3c229bc52b82f69@syzkaller.appspotmail.com Signed-off-by: Christoph Hellwig hch@lst.de Signed-off-by: Jens Axboe axboe@kernel.dk Signed-off-by: Sasha Levin sashal@kernel.org --- block/partitions/core.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-)
diff --git a/block/partitions/core.c b/block/partitions/core.c index 78951e33b2d7c..534e11285a8d4 100644 --- a/block/partitions/core.c +++ b/block/partitions/core.c @@ -524,19 +524,20 @@ int bdev_add_partition(struct block_device *bdev, int partno, int bdev_del_partition(struct block_device *bdev, int partno) { struct block_device *bdevp; - struct hd_struct *part; - int ret = 0; - - part = disk_get_part(bdev->bd_disk, partno); - if (!part) - return -ENXIO; + struct hd_struct *part = NULL; + int ret;
- ret = -ENOMEM; - bdevp = bdget(part_devt(part)); + bdevp = bdget_disk(bdev->bd_disk, partno); if (!bdevp) - goto out_put_part; + return -ENOMEM;
mutex_lock(&bdevp->bd_mutex); + mutex_lock_nested(&bdev->bd_mutex, 1); + + ret = -ENXIO; + part = disk_get_part(bdev->bd_disk, partno); + if (!part) + goto out_unlock;
ret = -EBUSY; if (bdevp->bd_openers) @@ -545,16 +546,14 @@ int bdev_del_partition(struct block_device *bdev, int partno) sync_blockdev(bdevp); invalidate_bdev(bdevp);
- mutex_lock_nested(&bdev->bd_mutex, 1); delete_partition(bdev->bd_disk, part); - mutex_unlock(&bdev->bd_mutex); - ret = 0; out_unlock: + mutex_unlock(&bdev->bd_mutex); mutex_unlock(&bdevp->bd_mutex); bdput(bdevp); -out_put_part: - disk_put_part(part); + if (part) + disk_put_part(part); return ret; }