lkml.org 
[lkml]   [2018]   [Jul]   [1]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 4.4 061/105] Btrfs: fix clone vs chattr NODATASUM race
    Date
    4.4-stable review patch.  If anyone has any objections, please let me know.

    ------------------

    From: Omar Sandoval <osandov@fb.com>

    commit b5c40d598f5408bd0ca22dfffa82f03cd9433f23 upstream.

    In btrfs_clone_files(), we must check the NODATASUM flag while the
    inodes are locked. Otherwise, it's possible that btrfs_ioctl_setflags()
    will change the flags after we check and we can end up with a party
    checksummed file.

    The race window is only a few instructions in size, between the if and
    the locks which is:

    3834 if (S_ISDIR(src->i_mode) || S_ISDIR(inode->i_mode))
    3835 return -EISDIR;

    where the setflags must be run and toggle the NODATASUM flag (provided
    the file size is 0). The clone will block on the inode lock, segflags
    takes the inode lock, changes flags, releases log and clone continues.

    Not impossible but still needs a lot of bad luck to hit unintentionally.

    Fixes: 0e7b824c4ef9 ("Btrfs: don't make a file partly checksummed through file clone")
    CC: stable@vger.kernel.org # 4.4+
    Signed-off-by: Omar Sandoval <osandov@fb.com>
    Reviewed-by: Nikolay Borisov <nborisov@suse.com>
    Reviewed-by: David Sterba <dsterba@suse.com>
    [ update changelog ]
    Signed-off-by: David Sterba <dsterba@suse.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
    [ adjusted for 4.4 ]
    Signed-off-by: Nikolay Borisov <nborisov@suse.com>

    ---
    fs/btrfs/ioctl.c | 12 +++++++-----
    1 file changed, 7 insertions(+), 5 deletions(-)

    --- a/fs/btrfs/ioctl.c
    +++ b/fs/btrfs/ioctl.c
    @@ -3923,11 +3923,6 @@ static noinline long btrfs_ioctl_clone(s
    if (!(src_file.file->f_mode & FMODE_READ))
    goto out_fput;

    - /* don't make the dst file partly checksummed */
    - if ((BTRFS_I(src)->flags & BTRFS_INODE_NODATASUM) !=
    - (BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM))
    - goto out_fput;
    -
    ret = -EISDIR;
    if (S_ISDIR(src->i_mode) || S_ISDIR(inode->i_mode))
    goto out_fput;
    @@ -3942,6 +3937,13 @@ static noinline long btrfs_ioctl_clone(s
    mutex_lock(&src->i_mutex);
    }

    + /* don't make the dst file partly checksummed */
    + if ((BTRFS_I(src)->flags & BTRFS_INODE_NODATASUM) !=
    + (BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM)) {
    + ret = -EINVAL;
    + goto out_unlock;
    + }
    +
    /* determine range to clone */
    ret = -EINVAL;
    if (off + len > src->i_size || off + len < off)

    \
     
     \ /
      Last update: 2018-07-01 20:29    [W:4.220 / U:0.020 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site