summaryrefslogtreecommitdiff
path: root/block/partitions
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@lst.de>2020-09-01 12:59:41 +0300
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2020-09-09 20:14:20 +0300
commit692d0626557451c4b557397f20b7394b612d0289 (patch)
treee8950482115f375068561e75840572dfc40cd0ce /block/partitions
parentbbb1dc4431b0c37eca621a2d618c8d3c1276e5a9 (diff)
downloadlinux-692d0626557451c4b557397f20b7394b612d0289.tar.xz
block: fix locking in bdev_del_partition
[ 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>
Diffstat (limited to 'block/partitions')
-rw-r--r--block/partitions/core.c27
1 files changed, 13 insertions, 14 deletions
diff --git a/block/partitions/core.c b/block/partitions/core.c
index 78951e33b2d7..534e11285a8d 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;
}