Overview
Mounting a crafted image can cause a NULL-pointer dereference. It can be triggered not only locally (mounting a btrfs image in a local shell) but also remotely (mounting a corrupted USB or other storage carrying a crafted btrfs image).
Target
Linux Kernel 5.0.21 btrfs filesystem. The bug affects btrfs_root_node in fs/btrfs/ctree.c in the Linux kernel through 5.3.12.
Bug type: NULL-Pointer-Dereference.
Reproduce
mkdir ./mount
mount poc_2019_19036.img ./mntRoot cause
struct extent_buffer *btrfs_root_node(struct btrfs_root *root)
{
struct extent_buffer *eb;
while (1) {
rcu_read_lock();
[1] eb = rcu_dereference(root->node);
/*
* RCU really hurts here, we could free up the root node because
* it was COWed but we may not get the new root node yet so do
* the inc_not_zero dance and if it doesn't work then
* synchronize_rcu and try again.
*/
[2] if (atomic_inc_not_zero(&eb->refs)) {
rcu_read_aunlock();
break;
}
rcu_read_unlock();
synchronize_rcu();
}
return eb;
}In [1], rcu_dereference(root->node) returns 0. It is then used in [2] (eb is 0, so eb->refs equals 0x00 + 0x24).
Debugger / KASAN
Debugger view — $r15 (struct extent_buffer *eb, the return value of rcu_dereference(root->node)) appears to be 0:
───────────────────────────────────────────────────────────── trace ────
[#0] 0xffffffff81c8c6a4 → atomic_fetch_add_unless(...)
[#1] 0xffffffff81c8c6a4 → atomic_add_unless(...)
[#2] 0xffffffff81c8c6a4 → btrfs_root_node(root=<optimized out>)
[#3] 0xffffffff81c8c925 → btrfs_read_lock_root_node(root=0xffff888069bcc400)
[#4] 0xffffffff81c9be94 → btrfs_search_slot_get_root(...)
[#5] 0xffffffff81c9be94 → btrfs_search_slot(...)
[#6] 0xffffffff81cf73ae → btrfs_find_root(...)
[#7] 0xffffffff81d19e54 → btrfs_read_tree_root(...)
[#8] 0xffffffff81d1a049 → btrfs_read_fs_root(...)
[#9] 0xffffffff81d1a338 → btrfs_get_fs_root(...)
KASAN log (trimmed to the relevant frames):
[ 166.370019] ==================================================================
[ 166.370195] BUG: KASAN: null-ptr-deref in btrfs_root_node+0x119/0x300
[ 166.370195] Read of size 4 at addr 0000000000000024 by task kworker/u4:4/174
[ 166.370195] CPU: 0 PID: 174 Comm: kworker/u4:4 Not tainted 5.0.21 #1
[ 166.370195] Workqueue: btrfs-endio-meta btrfs_endio_meta_helper
[ 166.370195] Call Trace:
[ 166.370195] dump_stack+0xae/0x14b
[ 166.370195] kasan_report+0x171/0x18d
[ 166.370195] btrfs_root_node+0x119/0x300
[ 166.370195] btrfs_read_lock_root_node+0x35/0x60
[ 166.370195] btrfs_search_slot+0x10c4/0x2190
[ 166.370195] btrfs_find_root+0xbe/0xb20
[ 166.370195] btrfs_read_tree_root+0x144/0x330
[ 166.370195] btrfs_read_fs_root+0x9/0xb0
[ 166.370195] btrfs_get_fs_root+0x248/0x810
[ 166.370195] check_leaf+0x31e/0x17e0
[ 166.370195] btree_readpage_end_io_hook+0x5a2/0x7d0
[ 166.370195] end_bio_extent_readpage+0x525/0x10e0
[ 166.370195] bio_endio+0x36a/0x680
[ 166.370195] normal_work_helper+0x24a/0xf30
[ 166.370195] process_one_work+0x90a/0x1690
[ 166.370195] worker_thread+0x191/0x1200
[ 166.370195] kthread+0x2e4/0x3a0
[ 166.370195] ret_from_fork+0x35/0x40
[ 166.370195] ==================================================================
...
[ 166.414228] RIP: 0010:btrfs_root_node+0x12a/0x300
[ 166.414228] R13: 0000000000000024 R14: dffffc0000000000 R15: 0000000000000000
[ 166.453905] ---[ end trace 43259c89f26aad18 ]---
A crafted image can force rcu_dereference(root->node) to return 0, which can be dangerous in other functions too.
Details
CVSS 5.5 (CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H), CWE-476, published 2019-11-21, 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.