Re: [PATCH] ext4: fix out-of-bounds issue in ext4_xattr_set_entry

Ojaswin Mujoo
2024-10-01T09:41:55Z

On Sun, Sep 22, 2024 at 02:42:49PM +0800, Qianqiang Liu wrote:
> syzbot has found an out-of-bounds issue in ext4_xattr_set_entry:
>
> ==================================================================
> BUG: KASAN: out-of-bounds in ext4_xattr_set_entry+0x8ce/0x1f60 fs/ext4/xattr.c:1781
> Read of size 18446744073709551572 at addr ffff888036426850 by task syz-executor264/5095
>
> CPU: 0 UID: 0 PID: 5095 Comm: syz-executor264 Not tainted 6.11.0-syzkaller-03917-ga940d9a43e62 #0
> Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2~bpo12+1 04/01/2014
> Call Trace:
> <TASK>
> __dump_stack lib/dump_stack.c:93 [inline]
> dump_stack_lvl+0x241/0x360 lib/dump_stack.c:119
> print_address_description mm/kasan/report.c:377 [inline]
> print_report+0x169/0x550 mm/kasan/report.c:488
> kasan_report+0x143/0x180 mm/kasan/report.c:601
> kasan_check_range+0x282/0x290 mm/kasan/generic.c:189
> __asan_memmove+0x29/0x70 mm/kasan/shadow.c:94
> ext4_xattr_set_entry+0x8ce/0x1f60 fs/ext4/xattr.c:1781
> [...]
> ==================================================================
>
> This issue is caused by a negative size in memmove.
> We need to check for this.
>
> Fixes: dec214d00e0d ("ext4: xattr inode deduplication")
> Reported-by: syzbot+f792df426ff0f5ceb8d1@syzkaller.appspotmail.com
> Closes: https://syzkaller.appspot.com/bug?extid=f792df426ff0f5ceb8d1
> Tested-by: syzbot+f792df426ff0f5ceb8d1@syzkaller.appspotmail.com
> Signed-off-by: Qianqiang Liu <qianqiang.liu@163.com>
> ---
> fs/ext4/xattr.c | 9 ++++++++-
> 1 file changed, 8 insertions(+), 1 deletion(-)
>
> diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c
> index 46ce2f21fef9..336badb46246 100644
> --- a/fs/ext4/xattr.c
> +++ b/fs/ext4/xattr.c
> @@ -1776,7 +1776,14 @@ static int ext4_xattr_set_entry(struct ext4_xattr_info *i,
> } else if (s->not_found) {
> /* Insert new name. */
> size_t size = EXT4_XATTR_LEN(name_len);
> - size_t rest = (void *)last - (void *)here + sizeof(__u32);
> + size_t rest;
> +
> + if (last < here) {
> + ret = -ENOSPC;
> + goto out;
> + } else {
> + rest = (void *)last - (void *)here + sizeof(__u32);
> + }

Hey Qianqiang,

Thanks for the patch. I'm still reviewing this codepath but I do have
some questions around the patch. So I understand that xattrs are
arranged in the following format:

* +------------------+
* | header |
* | entry 1 |
* | entry 2 |
* | entry 3 |
* | four null bytes | <--- last
* | . . . |
* | . . . | <--- here
* | . . . |
* | value 1 |
* | value 3 |
* | value 2 |
* +------------------+

Now, in this error, my understanding is that we are actually ending up
in a case where "here" ie the place where the new xattr entry will go is
beyond the "last" ie the last slot for xattr entry and that is causing
an underflow, something like the above diagram.

My only concern is that why were we not able to detect this in the logic
near the start of the function where we explcity check if we have enough
space?

Perhaps we should be fixing the logic in that if {..} instead
since the comment a few lines above your fix:

/* No failures allowed past this point. */

does suggest that we can't error out below that point, so ideally all
the checks would have been done before that.

I'm still going through the issue, will update here if needed.

Regards,
ojaswin

>
> memmove((void *)here + size, here, rest);
> memset(here, 0, size);
> --
> 2.34.1
>
> --
> Best,
> Qianqiang Liu
>