diff mbox series

block: fix locking in bdev_del_partition

Message ID 20200901095941.2626957-1-hch@lst.de
State New, archived
Headers show
Series block: fix locking in bdev_del_partition | expand

Commit Message

Christoph Hellwig Sept. 1, 2020, 9:59 a.m. UTC
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>
---
 block/partitions/core.c | 27 +++++++++++++--------------
 1 file changed, 13 insertions(+), 14 deletions(-)

Comments

Jens Axboe Sept. 1, 2020, 2:35 p.m. UTC | #1
On 9/1/20 3:59 AM, Christoph Hellwig wrote:
> 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.

Applied, fixed up an extra space while doing so.
diff mbox series

Patch

diff --git a/block/partitions/core.c b/block/partitions/core.c
index e62a98a8eeb750..effaa8fd2ee486 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;
 }