• Rabin Vincent's avatar
    block: protect iterate_bdevs() against concurrent close · 73e7d7ae
    Rabin Vincent authored
    [ Upstream commit af309226 ]
    
    If a block device is closed while iterate_bdevs() is handling it, the
    following NULL pointer dereference occurs because bdev->b_disk is NULL
    in bdev_get_queue(), which is called from blk_get_backing_dev_info() (in
    turn called by the mapping_cap_writeback_dirty() call in
    __filemap_fdatawrite_range()):
    
     BUG: unable to handle kernel NULL pointer dereference at 0000000000000508
     IP: [<ffffffff81314790>] blk_get_backing_dev_info+0x10/0x20
     PGD 9e62067 PUD 9ee8067 PMD 0
     Oops: 0000 [#1] PREEMPT SMP DEBUG_PAGEALLOC
     Modules linked in:
     CPU: 1 PID: 2422 Comm: sync Not tainted 4.5.0-rc7+ #400
     Hardware name: QEMU Standard PC (i440FX + PIIX, 1996)
     task: ffff880009f4d700 ti: ffff880009f5c000 task.ti: ffff880009f5c000
     RIP: 0010:[<ffffffff81314790>]  [<ffffffff81314790>] blk_get_backing_dev_info+0x10/0x20
     RSP: 0018:ffff880009f5fe68  EFLAGS: 00010246
     RAX: 0000000000000000 RBX: ffff88000ec17a38 RCX: ffffffff81a4e940
     RDX: 7fffffffffffffff RSI: 0000000000000000 RDI: ffff88000ec176c0
     RBP: ffff880009f5fe68 R08: 0000000000000000 R09: 0000000000000000
     R10: 0000000000000001 R11: 0000000000000000 R12: ffff88000ec17860
     R13: ffffffff811b25c0 R14: ffff88000ec178e0 R15: ffff88000ec17a38
     FS:  00007faee505d700(0000) GS:ffff88000fb00000(0000) knlGS:0000000000000000
     CS:  0010 DS: 0000 ES: 0000 CR0: 000000008005003b
     CR2: 0000000000000508 CR3: 0000000009e8a000 CR4: 00000000000006e0
     Stack:
      ffff880009f5feb8 ffffffff8112e7f5 0000000000000000 7fffffffffffffff
      0000000000000000 0000000000000000 7fffffffffffffff 0000000000000001
      ffff88000ec178e0 ffff88000ec17860 ffff880009f5fec8 ffffffff8112e81f
     Call Trace:
      [<ffffffff8112e7f5>] __filemap_fdatawrite_range+0x85/0x90
      [<ffffffff8112e81f>] filemap_fdatawrite+0x1f/0x30
      [<ffffffff811b25d6>] fdatawrite_one_bdev+0x16/0x20
      [<ffffffff811bc402>] iterate_bdevs+0xf2/0x130
      [<ffffffff811b2763>] sys_sync+0x63/0x90
      [<ffffffff815d4272>] entry_SYSCALL_64_fastpath+0x12/0x76
     Code: 0f 1f 44 00 00 48 8b 87 f0 00 00 00 55 48 89 e5 <48> 8b 80 08 05 00 00 5d
     RIP  [<ffffffff81314790>] blk_get_backing_dev_info+0x10/0x20
      RSP <ffff880009f5fe68>
     CR2: 0000000000000508
     ---[ end trace 2487336ceb3de62d ]---
    
    The crash is easily reproducible by running the following command, if an
    msleep(100) is inserted before the call to func() in iterate_devs():
    
     while :; do head -c1 /dev/nullb0; done > /dev/null & while :; do sync; done
    
    Fix it by holding the bd_mutex across the func() call and only calling
    func() if the bdev is opened.
    
    Cc: stable@vger.kernel.org
    Fixes: 5c0d6b60 ("vfs: Create function for iterating over block devices")
    Reported-and-tested-by: default avatarWei Fang <fangwei1@huawei.com>
    Signed-off-by: default avatarRabin Vincent <rabinv@axis.com>
    Signed-off-by: default avatarJan Kara <jack@suse.cz>
    Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
    Signed-off-by: default avatarJens Axboe <axboe@fb.com>
    Signed-off-by: default avatarSasha Levin <alexander.levin@verizon.com>
    73e7d7ae
block_dev.c 45.5 KB