Skip to content
cvekernelbtrfsnull-pointer-dereference

Linux kernel btrfs NULL pointer dereference

3 min read

Overview

On mounting a crafted btrfs image, the kernel takes a NULL-pointer dereference in btrfs_verify_dev_extents (the loop list entry inside find_device).

Target

Tested on Linux Kernel 5.0.21 BTRFS filesystem (source).

(It can need the CONFIG_BTRFS_FS=m option.)

CVE-2019-18885 affects fs/btrfs/volumes.c in the Linux kernel before 5.1 (fixed as CID-09ba3bc9dd15).

Reproduce

A crafted image is attached in the upstream writeup.

mkdir ./mnt
mount -t btrfs ./poc_2019_18885.img ./mnt

Root cause

fs/btrfs/volumes.c:430

static struct btrfs_device *find_device(struct btrfs_fs_devices *fs_devices,
		u64 devid, const u8 *uuid)
{
	struct btrfs_device *dev;
 
[1]	list_for_each_entry(dev, &fs_devices->devices, dev_list) {
		if (dev->devid == devid &&
		    (!uuid || !memcmp(dev->uuid, uuid, BTRFS_UUID_SIZE))) {
			return dev;
		}
	}
	return NULL;
}

In the list_for_each_entry loop ([1]), the &fs_devices->devices list entry can be NULL.

Debugger / KASAN

Debugger view. The instruction cmp BYTE PTR [rdx+rbx*1], 0x0 tries to read the address 0xdffffc0000000000 + 0x13 (a KASAN shadow access on a NULL-derived pointer):

─────────────────────────────────────────────────────────── registers ────
$rax   : 0x0000000000000000  →  0x0000000000000000
$rbx   : 0xdffffc0000000000  →  0xdffffc0000000000
$rcx   : 0x0000000000000098  →  0x0000000000000098
$rdx   : 0x0000000000000013  →  0x0000000000000013
$rip   : 0xffffffff81def0e8  →  0x0890850f001a3c80  →  0x0890850f001a3c80
...
───────────────────────────────────────────────────────── code:x86:64 ────
 → 0xffffffff81def0e8 <btrfs_verify_dev_extents+1912> cmp    BYTE PTR [rdx+rbx*1], 0x0
─────────────────────────────────────── source:fs/btrfs/volumes.c+430 ────
 →  430	 	list_for_each_entry(dev, &fs_devices->devices, dev_list) {
─────────────────────────────────────────────────────────────── trace ────
[#0] 0xffffffff81def0e8 → find_device(uuid=<optimized out>, devid=<optimized out>, fs_devices=<optimized out>)
[#1] 0xffffffff81def0e8 → verify_one_dev_extent(...)
[#2] 0xffffffff81def0e8 → btrfs_verify_dev_extents(fs_info=<optimized out>)
[#3] 0xffffffff81d243f0 → open_ctree(...)
[#4] 0xffffffff81c7c5d4 → btrfs_fill_super(...)
[#5] 0xffffffff81c7c5d4 → btrfs_mount_root(...)
[#6] 0xffffffff816979d9 → mount_fs(...)
...

KASAN / GPF log (trimmed to the relevant frames):

[  196.879172] kasan: CONFIG_KASAN_INLINE enabled
[  196.881094] kasan: GPF could be caused by NULL-ptr deref or user memory access
[  196.883004] general protection fault: 0000 [#1] SMP KASAN NOPTI
[  196.883474] CPU: 0 PID: 1989 Comm: mount Not tainted 5.0.21 #1
[  196.883474] RIP: 0010:btrfs_verify_dev_extents+0x778/0x1140
[  196.883474] RAX: 0000000000000000 RBX: dffffc0000000000 RCX: 0000000000000098
[  196.883474] RDX: 0000000000000013 RSI: 0000000000000001 RDI: ffff888069afa348
[  196.883474] Call Trace:
[  196.883474]  open_ctree+0x4cd0/0x7ada
...
[  196.883474]  btrfs_mount_root+0xe24/0x14c0
...
[  196.883474]  mount_fs+0xb9/0x370
[  196.883474]  vfs_kern_mount.part.28+0xb9/0x400
[  196.883474]  btrfs_mount+0x3c5/0x1fd9
...
[  196.883474]  do_mount+0xef4/0x2d40
[  196.883474]  ksys_mount+0x7b/0xd0
[  196.883474]  __x64_sys_mount+0xb5/0x150
[  196.883474]  do_syscall_64+0x12b/0x440
[  196.883474]  entry_SYSCALL_64_after_hwframe+0x44/0xa9
[  196.934565] ---[ end trace b2518a0a4d2b3ae0 ]---

Details

CVSS 5.5 (CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H), CWE-476, published 2019-11-14, 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