• Anand Jain's avatar
    btrfs: btrfs_shrink_device should call commit transaction at the end · 801660b0
    Anand Jain authored
    Test case btrfs/164 reports use-after-free:
    
    [ 6712.084324] general protection fault: 0000 [#1] PREEMPT SMP
    ..
    [ 6712.195423]  btrfs_update_commit_device_size+0x75/0xf0 [btrfs]
    [ 6712.201424]  btrfs_commit_transaction+0x57d/0xa90 [btrfs]
    [ 6712.206999]  btrfs_rm_device+0x627/0x850 [btrfs]
    [ 6712.211800]  btrfs_ioctl+0x2b03/0x3120 [btrfs]
    
    Reason for this is that btrfs_shrink_device adds the resized device to
    the fs_devices::resized_devices after it has called the last commit
    transaction.
    
    So the list fs_devices::resized_devices is not empty when
    btrfs_shrink_device returns.  Now the parent function
    btrfs_rm_device calls:
    
            btrfs_close_bdev(device);
            call_rcu(&device->rcu, free_device_rcu);
    
    and then does the transactio ncommit. It goes through the
    fs_devices::resized_devices in btrfs_update_commit_device_size and
    leads to use-after-free.
    
    Fix this by making sure btrfs_shrink_device calls the last needed
    btrfs_commit_transaction before the return. This is consistent with what
    the grow counterpart does and this makes sure the on-disk state is
    persistent when the function returns.
    Reported-by: default avatarLu Fengqi <lufq.fnst@cn.fujitsu.com>
    Tested-by: default avatarLu Fengqi <lufq.fnst@cn.fujitsu.com>
    Signed-off-by: default avatarAnand Jain <anand.jain@oracle.com>
    Reviewed-by: default avatarDavid Sterba <dsterba@suse.com>
    [ update changelog ]
    Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
    801660b0
volumes.c 198 KB