Patch "ext4: fix use-after-free in ext4_xattr_set_entry" has been added to the 5.15-stable tree

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This is a note to let you know that I've just added the patch titled

    ext4: fix use-after-free in ext4_xattr_set_entry

to the 5.15-stable tree which can be found at:
    http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
     ext4-fix-use-after-free-in-ext4_xattr_set_entry.patch
and it can be found in the queue-5.15 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <stable@xxxxxxxxxxxxxxx> know about it.



commit 19663aea6ffb8fceab2f77fdc15d6a9bb564cb8b
Author: Baokun Li <libaokun1@xxxxxxxxxx>
Date:   Thu Jun 16 10:13:56 2022 +0800

    ext4: fix use-after-free in ext4_xattr_set_entry
    
    [ Upstream commit 67d7d8ad99beccd9fe92d585b87f1760dc9018e3 ]
    
    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@xxxxxxxxxx
    Reported-by: Hulk Robot <hulkci@xxxxxxxxxx>
    Signed-off-by: Baokun Li <libaokun1@xxxxxxxxxx>
    Reviewed-by: Ritesh Harjani (IBM) <ritesh.list@xxxxxxxxx>
    Reviewed-by: Jan Kara <jack@xxxxxxx>
    Link: https://lore.kernel.org/r/20220616021358.2504451-3-libaokun1@xxxxxxxxxx
    Signed-off-by: Theodore Ts'o <tytso@xxxxxxx>
    Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>

diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c
index 042325349098..c3c3194f3ee1 100644
--- a/fs/ext4/xattr.c
+++ b/fs/ext4/xattr.c
@@ -2176,8 +2176,9 @@ int ext4_xattr_ibody_find(struct inode *inode, struct ext4_xattr_info *i,
 	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);
@@ -2205,8 +2206,9 @@ int ext4_xattr_ibody_set(handle_t *handle, struct inode *inode,
 	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;



[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux