[PATCH 2/4] brd: check for open partitions when BLKFLSBUFing a ram disk

From: Hannes Frederic Sowa
Date: Sat Oct 20 2012 - 14:32:55 EST


Users of partitions on ram disks could accidentally flush the block
device with ioctl(BLKFLSBUF) while it is in use. This patch prevents
this from happening.

This patch also adds a call to rescan_partitions after BLKFLSBUFing,
for which a EXPORT_SYMBOL_GPL statement was needed. Otherwise some kind
of use-after-free could happen.

After this change BLKFLSBUFing on partitions of a ram disk is never
possible.

Cc: Nick Piggin <npiggin@xxxxxxxxx>
Signed-off-by: Hannes Frederic Sowa <hannes@xxxxxxxxxxxxxxxxxxx>
---
block/partition-generic.c | 1 +
drivers/block/brd.c | 20 +++++++++++++++++---
2 files changed, 18 insertions(+), 3 deletions(-)

diff --git a/block/partition-generic.c b/block/partition-generic.c
index f1d1451..cd7bc10 100644
--- a/block/partition-generic.c
+++ b/block/partition-generic.c
@@ -528,6 +528,7 @@ rescan:
kfree(state);
return 0;
}
+EXPORT_SYMBOL_GPL(rescan_partitions);

int invalidate_partitions(struct gendisk *disk, struct block_device *bdev)
{
diff --git a/drivers/block/brd.c b/drivers/block/brd.c
index c4965f5..ce1255c 100644
--- a/drivers/block/brd.c
+++ b/drivers/block/brd.c
@@ -385,6 +385,13 @@ static int brd_direct_access(struct block_device *bdev, sector_t sector,
}
#endif

+static int brd_blkdev_in_use(struct block_device *bdev)
+{
+ lockdep_assert_held(&bdev->bd_mutex);
+ return bdev->bd_part_count > 0
+ || bdev->bd_openers > 1;
+}
+
static int brd_ioctl(struct block_device *bdev, fmode_t mode,
unsigned int cmd, unsigned long arg)
{
@@ -399,9 +406,15 @@ static int brd_ioctl(struct block_device *bdev, fmode_t mode,
* release and destroy the ramdisk data.
*/
mutex_lock(&brd_mutex);
+ if (bdget_disk(brd->brd_disk, 0) != bdev) {
+ error = -EBUSY;
+ goto out;
+ }
mutex_lock(&bdev->bd_mutex);
- error = -EBUSY;
- if (bdev->bd_openers <= 1) {
+ error = brd_blkdev_in_use(bdev);
+ if (error) {
+ error = -EBUSY;
+ } else {
/*
* Kill the cache first, so it isn't written back to the
* device.
@@ -411,9 +424,10 @@ static int brd_ioctl(struct block_device *bdev, fmode_t mode,
*/
kill_bdev(bdev);
brd_free_pages(brd);
- error = 0;
+ error = rescan_partitions(brd->brd_disk, bdev);
}
mutex_unlock(&bdev->bd_mutex);
+out:
mutex_unlock(&brd_mutex);

return error;
--
1.7.12.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/