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 <npig...@kernel.dk>
Signed-off-by: Hannes Frederic Sowa <han...@stressinduktion.org>
---
 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 majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to