All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jan Kara <jack@suse.cz>
To: Jens Axboe <axboe@kernel.dk>
Cc: <linux-block@vger.kernel.org>, Hou Tao <houtao1@huawei.com>,
	Jan Kara <jack@suse.cz>
Subject: [PATCH 4/6] genhd: Fix use after free in __blkdev_get()
Date: Mon, 26 Feb 2018 13:01:40 +0100	[thread overview]
Message-ID: <20180226120142.25786-5-jack@suse.cz> (raw)
In-Reply-To: <20180226120142.25786-1-jack@suse.cz>

When two blkdev_open() calls race with device removal and recreation,
__blkdev_get() can use looked up gendisk after it is freed:

CPU0				CPU1			CPU2
							del_gendisk(disk);
							  bdev_unhash_inode(inode);
blkdev_open()			blkdev_open()
  bdev = bd_acquire(inode);
    - creates and returns new inode
				  bdev = bd_acquire(inode);
				    - returns the same inode
  __blkdev_get(devt)		  __blkdev_get(devt)
    disk = get_gendisk(devt);
      - got structure of device going away
							<finish device removal>
							<new device gets
							 created under the same
							 device number>
				  disk = get_gendisk(devt);
				    - got new device structure
				  if (!bdev->bd_openers) {
				    does the first open
				  }
    if (!bdev->bd_openers)
      - false
    } else {
      put_disk_and_module(disk)
        - remember this was old device - this was last ref and disk is
          now freed
    }
    disk_unblock_events(disk); -> oops

Fix the problem by making sure we drop reference to disk in
__blkdev_get() only after we are really done with it.

Reported-by: Hou Tao <houtao1@huawei.com>
Tested-by: Hou Tao <houtao1@huawei.com>
Signed-off-by: Jan Kara <jack@suse.cz>
---
 fs/block_dev.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/fs/block_dev.c b/fs/block_dev.c
index 1dbbf847911a..fe41a76769fa 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -1409,6 +1409,7 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)
 	int ret;
 	int partno;
 	int perm = 0;
+	bool first_open = false;
 
 	if (mode & FMODE_READ)
 		perm |= MAY_READ;
@@ -1435,6 +1436,7 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)
 	disk_block_events(disk);
 	mutex_lock_nested(&bdev->bd_mutex, for_part);
 	if (!bdev->bd_openers) {
+		first_open = true;
 		bdev->bd_disk = disk;
 		bdev->bd_queue = disk->queue;
 		bdev->bd_contains = bdev;
@@ -1520,14 +1522,15 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)
 			if (ret)
 				goto out_unlock_bdev;
 		}
-		/* only one opener holds refs to the module and disk */
-		put_disk_and_module(disk);
 	}
 	bdev->bd_openers++;
 	if (for_part)
 		bdev->bd_part_count++;
 	mutex_unlock(&bdev->bd_mutex);
 	disk_unblock_events(disk);
+	/* only one opener holds refs to the module and disk */
+	if (!first_open)
+		put_disk_and_module(disk);
 	return 0;
 
  out_clear:
-- 
2.13.6

  parent reply	other threads:[~2018-02-26 12:01 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-02-26 12:01 [PATCH 0/6 v2] block: Fix races in bdev - gendisk handling Jan Kara
2018-02-26 12:01 ` [PATCH 1/6] genhd: Fix leaked module reference for NVME devices Jan Kara
2018-02-27  0:09   ` Christoph Hellwig
2018-02-26 12:01 ` [PATCH 2/6] genhd: Rename get_disk() to get_disk_and_module() Jan Kara
2018-02-26 12:01 ` [PATCH 3/6] genhd: Add helper put_disk_and_module() Jan Kara
2018-02-26 12:01 ` Jan Kara [this message]
2018-02-26 12:01 ` [PATCH 5/6] genhd: Fix BUG in blkdev_open() Jan Kara
2018-02-26 12:01 ` [PATCH 6/6] blockdev: Avoid two active bdev inodes for one device Jan Kara
2018-02-26 16:04 ` [PATCH 0/6 v2] block: Fix races in bdev - gendisk handling Jens Axboe
2018-02-26 16:43   ` Jan Kara
2018-02-26 16:49     ` Jens Axboe
  -- strict thread matches above, loose matches on Subject: below --
2018-02-06 16:05 [PATCH 0/6] " Jan Kara
2018-02-06 16:05 ` [PATCH 4/6] genhd: Fix use after free in __blkdev_get() Jan Kara
2018-02-13  2:11   ` Hou Tao

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20180226120142.25786-5-jack@suse.cz \
    --to=jack@suse.cz \
    --cc=axboe@kernel.dk \
    --cc=houtao1@huawei.com \
    --cc=linux-block@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.