Skip to content
cvekernelext4out-of-bounds-write

Linux kernel ext4 slab out-of-bounds write

3 min read

Overview

A setxattr operation (after mounting a crafted image) can cause a slab-out-of-bounds write vulnerability.

Target

Linux Kernel Ext4 filesystem. The bug affects fs/ext4/xattr.c in the Linux kernel before 5.2 (fixed as CID-345c0dbf3a30).

Linux Version Availablity
5.0.21 True
5.3.11 False
5.4.0 mount fail

Bug type: slab-out-of-bounds.

Reproduce

gcc -o poc poc_2019_19319.c
mkdir mnt
mount poc_2019_19319.img ./mnt
cp poc ./mnt/
cd mnt
./poc

Root cause

fs/ext4/xattr.c:1706 (link)

static int ext4_xattr_set_entry(struct ext4_xattr_info *i,
				struct ext4_xattr_search *s,
				handle_t *handle, struct inode *inode,
				bool is_block)
{
	struct ext4_xattr_entry *last, *next;
	struct ext4_xattr_entry *here = s->here;
	size_t min_offs = s->end - s->base, name_len = strlen(i->name);
	int in_inode = i->in_inode;
	struct inode *old_ea_inode = NULL;
	struct inode *new_ea_inode = NULL;
	size_t old_size, new_size;
	int ret;
 
	/* Space used by old and new values. */
	old_size = (!s->not_found && !here->e_value_inum) ?
[1]			EXT4_XATTR_SIZE(le32_to_cpu(here->e_value_size)) : 0;
	new_size = (i->value && !in_inode) ? EXT4_XATTR_SIZE(i->value_len) : 0;
 
	...
 
	/* No failures allowed past this point. */
 
	if (!s->not_found && here->e_value_size && !here->e_value_inum) {
		/* Remove the old value. */
		void *first_val = s->base + min_offs;
		size_t offs = le16_to_cpu(here->e_value_offs);
		void *val = s->base + offs;
 
		memmove(first_val + old_size, first_val, val - first_val);
[2]		memset(first_val, 0, old_size);
		min_offs += old_size;
    ...

In [1], old_size is set to a huge value, and memset is then called with that old_size in [2].

Debugger / KASAN

Debugger view — the local variable old_size appears as 0x1000004:

─────────────────────────────────────────────────────────── arguments ────
memset (
   QWORD var_0 = 0xffff8880674ebbd8 → 0x74737973565dbd3e → 0x74737973565dbd3e,
   int var_1 = 0x0000000000000000 → 0x0000000000000000,
   size_t var_2 = 0x0000000001000004 → 0x0000000001000004
)
───────────────────────────────────── source:fs/ext4/xattr.c+1706 ────
 → 1706	 		memset(first_val, 0, old_size);
───────────────────────────────────────────────────────── trace ────
[#0] 0xffffffff81a28fb2 → ext4_xattr_set_entry(...)
[#1] 0xffffffff81a2b42a → ext4_xattr_block_set(...)
[#2] 0xffffffff81a3268f → ext4_xattr_set_handle(...)
[#3] 0xffffffff81a333e9 → ext4_xattr_set(...)
[#4] 0xffffffff8172502f → __vfs_setxattr(...)
[#5] 0xffffffff81727761 → __vfs_setxattr_noperm(...)
[#6] 0xffffffff81727aad → vfs_setxattr(...)
[#7] 0xffffffff81727d13 → setxattr(...)
[#8] 0xffffffff81727f36 → path_setxattr(...)
[#9] 0xffffffff8172803b → __do_sys_setxattr(...)

KASAN log (trimmed to the relevant frames):

[  611.826655] ==================================================================
[  611.827411] BUG: KASAN: use-after-free in ext4_xattr_set_entry+0x1b67/0x3550
[  611.827411] Write of size 16777220 at addr ffff888069becbd8 by task poc/1971
[  611.827411] CPU: 1 PID: 1971 Comm: poc Not tainted 5.0.21 #1
[  611.827411] Call Trace:
[  611.827411]  dump_stack+0xae/0x14b
[  611.827411]  kasan_report+0x149/0x18d
[  611.827411]  memset+0x1f/0x40
[  611.827411]  ext4_xattr_set_entry+0x1b67/0x3550
[  611.827411]  ext4_xattr_block_set+0x80a/0x3a00
[  611.827411]  ext4_xattr_set_handle+0xe5f/0x18a0
[  611.827411]  ext4_xattr_set+0x1b9/0x330
[  611.827411]  __vfs_setxattr+0x7f/0xb0
[  611.827411]  __vfs_setxattr_noperm+0xe1/0x370
[  611.827411]  vfs_setxattr+0xbd/0xd0
[  611.827411]  setxattr+0x253/0x320
[  611.827411]  path_setxattr+0x156/0x1a0
[  611.827411]  __x64_sys_setxattr+0xbb/0x150
[  611.827411]  do_syscall_64+0x12b/0x440
[  611.827411]  entry_SYSCALL_64_after_hwframe+0x44/0xa9
[  611.827411] ==================================================================
[  611.872754] BUG: unable to handle kernel paging request at ffff888069c62000
[  611.872754] Oops: 0003 [#1] SMP KASAN NOPTI
[  611.872754] RIP: 0010:memset_orig+0x46/0xb0
[  611.872754] RDX: 0000000001000004 RSI: 0000000000000000 RDI: ffff888069c61fd8
[  611.872754] ---[ end trace 1f7f1665adedcbc6 ]---
Segmentation fault

Details

CVSS 6.5 (CVSS:3.1/AV:L/AC:L/PR:H/UI:R/S:U/C:H/I:H/A:H), CWE-416, published 2019-11-27, last modified 2024-11-21.

Attribution

Found as part of the Best of the Best (BoB) 8th bobfuzzer team project — a five-person team that ported the JANUS file-system fuzzer. This is team work, not sole authorship.

References