lkml.org 
[lkml]   [2022]   [Aug]   [23]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 4.19 189/287] ext4: fix use-after-free in ext4_xattr_set_entry
    Date
    From: Baokun Li <libaokun1@huawei.com>

    commit 67d7d8ad99beccd9fe92d585b87f1760dc9018e3 upstream.

    Hulk Robot reported a issue:
    ==================================================================
    BUG: KASAN: use-after-free in ext4_xattr_set_entry+0x18ab/0x3500
    Write of size 4105 at addr ffff8881675ef5f4 by task syz-executor.0/7092

    CPU: 1 PID: 7092 Comm: syz-executor.0 Not tainted 4.19.90-dirty #17
    Call Trace:
    [...]
    memcpy+0x34/0x50 mm/kasan/kasan.c:303
    ext4_xattr_set_entry+0x18ab/0x3500 fs/ext4/xattr.c:1747
    ext4_xattr_ibody_inline_set+0x86/0x2a0 fs/ext4/xattr.c:2205
    ext4_xattr_set_handle+0x940/0x1300 fs/ext4/xattr.c:2386
    ext4_xattr_set+0x1da/0x300 fs/ext4/xattr.c:2498
    __vfs_setxattr+0x112/0x170 fs/xattr.c:149
    __vfs_setxattr_noperm+0x11b/0x2a0 fs/xattr.c:180
    __vfs_setxattr_locked+0x17b/0x250 fs/xattr.c:238
    vfs_setxattr+0xed/0x270 fs/xattr.c:255
    setxattr+0x235/0x330 fs/xattr.c:520
    path_setxattr+0x176/0x190 fs/xattr.c:539
    __do_sys_lsetxattr fs/xattr.c:561 [inline]
    __se_sys_lsetxattr fs/xattr.c:557 [inline]
    __x64_sys_lsetxattr+0xc2/0x160 fs/xattr.c:557
    do_syscall_64+0xdf/0x530 arch/x86/entry/common.c:298
    entry_SYSCALL_64_after_hwframe+0x44/0xa9
    RIP: 0033:0x459fe9
    RSP: 002b:00007fa5e54b4c08 EFLAGS: 00000246 ORIG_RAX: 00000000000000bd
    RAX: ffffffffffffffda RBX: 000000000051bf60 RCX: 0000000000459fe9
    RDX: 00000000200003c0 RSI: 0000000020000180 RDI: 0000000020000140
    RBP: 000000000051bf60 R08: 0000000000000001 R09: 0000000000000000
    R10: 0000000000001009 R11: 0000000000000246 R12: 0000000000000000
    R13: 00007ffc73c93fc0 R14: 000000000051bf60 R15: 00007fa5e54b4d80
    [...]
    ==================================================================

    Above issue may happen as follows:
    -------------------------------------
    ext4_xattr_set
    ext4_xattr_set_handle
    ext4_xattr_ibody_find
    >> s->end < s->base
    >> no EXT4_STATE_XATTR
    >> xattr_check_inode is not executed
    ext4_xattr_ibody_set
    ext4_xattr_set_entry
    >> size_t min_offs = s->end - s->base
    >> UAF in memcpy

    we can easily reproduce this problem with the following commands:
    mkfs.ext4 -F /dev/sda
    mount -o debug_want_extra_isize=128 /dev/sda /mnt
    touch /mnt/file
    setfattr -n user.cat -v `seq -s z 4096|tr -d '[:digit:]'` /mnt/file

    In ext4_xattr_ibody_find, we have the following assignment logic:
    header = IHDR(inode, raw_inode)
    = raw_inode + EXT4_GOOD_OLD_INODE_SIZE + i_extra_isize
    is->s.base = IFIRST(header)
    = header + sizeof(struct ext4_xattr_ibody_header)
    is->s.end = raw_inode + s_inode_size

    In ext4_xattr_set_entry
    min_offs = s->end - s->base
    = s_inode_size - EXT4_GOOD_OLD_INODE_SIZE - i_extra_isize -
    sizeof(struct ext4_xattr_ibody_header)
    last = s->first
    free = min_offs - ((void *)last - s->base) - sizeof(__u32)
    = s_inode_size - EXT4_GOOD_OLD_INODE_SIZE - i_extra_isize -
    sizeof(struct ext4_xattr_ibody_header) - sizeof(__u32)

    In the calculation formula, all values except s_inode_size and
    i_extra_size are fixed values. When i_extra_size is the maximum value
    s_inode_size - EXT4_GOOD_OLD_INODE_SIZE, min_offs is -4 and free is -8.
    The value overflows. As a result, the preceding issue is triggered when
    memcpy is executed.

    Therefore, when finding xattr or setting xattr, check whether
    there is space for storing xattr in the inode to resolve this issue.

    Cc: stable@kernel.org
    Reported-by: Hulk Robot <hulkci@huawei.com>
    Signed-off-by: Baokun Li <libaokun1@huawei.com>
    Reviewed-by: Ritesh Harjani (IBM) <ritesh.list@gmail.com>
    Reviewed-by: Jan Kara <jack@suse.cz>
    Link: https://lore.kernel.org/r/20220616021358.2504451-3-libaokun1@huawei.com
    Signed-off-by: Theodore Ts'o <tytso@mit.edu>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
    ---
    fs/ext4/xattr.c | 6 ++++--
    1 file changed, 4 insertions(+), 2 deletions(-)

    --- a/fs/ext4/xattr.c
    +++ b/fs/ext4/xattr.c
    @@ -2188,8 +2188,9 @@ int ext4_xattr_ibody_find(struct inode *
    struct ext4_inode *raw_inode;
    int error;

    - if (EXT4_I(inode)->i_extra_isize == 0)
    + if (!EXT4_INODE_HAS_XATTR_SPACE(inode))
    return 0;
    +
    raw_inode = ext4_raw_inode(&is->iloc);
    header = IHDR(inode, raw_inode);
    is->s.base = is->s.first = IFIRST(header);
    @@ -2217,8 +2218,9 @@ int ext4_xattr_ibody_inline_set(handle_t
    struct ext4_xattr_search *s = &is->s;
    int error;

    - if (EXT4_I(inode)->i_extra_isize == 0)
    + if (!EXT4_INODE_HAS_XATTR_SPACE(inode))
    return -ENOSPC;
    +
    error = ext4_xattr_set_entry(i, s, handle, inode, false /* is_block */);
    if (error)
    return error;

    \
     
     \ /
      Last update: 2022-08-23 12:55    [W:4.090 / U:0.060 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site