diff options
author | Christoph Hellwig <hch@lst.de> | 2020-09-01 12:59:41 +0300 |
---|---|---|
committer | Jens Axboe <axboe@kernel.dk> | 2020-09-01 17:35:35 +0300 |
commit | 08fc1ab6d748ab1a690fd483f41e2938984ce353 (patch) | |
tree | 7e141849aad3fc830215030bb9cf0cbe081a80f1 /block/partitions/core.c | |
parent | cafe01ef8fcb248583038e1be071383530fe355a (diff) | |
download | linux-08fc1ab6d748ab1a690fd483f41e2938984ce353.tar.xz |
block: fix locking in bdev_del_partition
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>
Diffstat (limited to 'block/partitions/core.c')
-rw-r--r-- | block/partitions/core.c | 27 |
1 files changed, 13 insertions, 14 deletions
diff --git a/block/partitions/core.c b/block/partitions/core.c index 5a18c8edabbc..5b4869c08fb3 100644 --- a/block/partitions/core.c +++ b/block/partitions/core.c @@ -532,19 +532,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) @@ -553,16 +554,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; } |