• Jan Kara's avatar
    genhd: Fix use after free in __blkdev_get() · 89736653
    Jan Kara authored
    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: default avatarHou Tao <houtao1@huawei.com>
    Tested-by: default avatarHou Tao <houtao1@huawei.com>
    Signed-off-by: default avatarJan Kara <jack@suse.cz>
    Signed-off-by: default avatarJens Axboe <axboe@kernel.dk>
    89736653
block_dev.c 53 KB