Bug 199847

Summary: Invalid pointer dereference in btrfs_root_node() when mounting a crafted btrfs image
Product: File System Reporter: Wen Xu (wen.xu)
Component: btrfsAssignee: BTRFS virtual assignee (fs_btrfs)
Status: RESOLVED CODE_FIX    
Severity: normal CC: dsterba, wen.xu
Priority: P1    
Hardware: All   
OS: Linux   
Kernel Version: 4.17 Subsystem:
Regression: No Bisected commit-id:
Attachments: The (compressed) crafted image which causes crash

Description Wen Xu 2018-05-26 14:44:13 UTC
Created attachment 276213 [details]
The (compressed) crafted image which causes crash

- Overview
Invalid pointer dereference in btrfs_root_node() when mounting a crafted btrfs image

- Reproduce (4.17-rc5)
# mkdir mnt
# mount -t btrfs 7.img mnt

- Kernel Message
[  145.850175] BUG: unable to handle kernel NULL pointer dereference at 0000000000000024
[  145.851740] PGD 0 P4D 0
[  145.852321] Oops: 0000 [#1] SMP KASAN PTI
[  145.853098] Modules linked in: snd_hda_codec_generic snd_hda_intel snd_hda_codec snd_hwdep snd_hda_core snd_pcm snd_timer snd i2c_piix4 soundcore mac_hid ib_iser rdma_cm iw_cm ib_cm ib_core iscsi_tcp libiscsi_tcp libiscsi scsi_transport_iscsi autofs4 raid10 raid456 async_raid6_recov async_memcpy async_pq async_xor async_tx raid1 raid0 multipath linear 8139too qxl drm_kms_helper syscopyarea sysfillrect sysimgblt fb_sys_fops ttm crct10dif_pclmul crc32_pclmul aesni_intel drm aes_x86_64 crypto_simd cryptd 8139cp glue_helper mii pata_acpi floppy
[  145.862209] CPU: 0 PID: 84 Comm: kworker/u4:3 Tainted: G    B             4.17.0-rc5+ #6
[  145.863754] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Ubuntu-1.8.2-1ubuntu1 04/01/2014
[  145.865590] Workqueue: btrfs-endio-meta btrfs_endio_meta_helper
[  145.866735] RIP: 0010:btrfs_root_node+0x36/0x80
[  145.867609] RSP: 0018:ffff8801e407f980 EFLAGS: 00010292
[  145.868630] RAX: 0000000000000000 RBX: 0000000000000024 RCX: ffffffffab725626
[  145.870007] RDX: 0000000000000000 RSI: 0000000000000004 RDI: 0000000000000024
[  145.871388] RBP: ffff8801e407f998 R08: ffffed003ee03ebb R09: ffffed003ee03ebb
[  145.872774] R10: 0000000000000001 R11: ffffed003ee03eba R12: ffff8801ee1d8000
[  145.874146] R13: 0000000000000000 R14: ffff8801f18802c0 R15: 0000000000000000
[  145.875524] FS:  0000000000000000(0000) GS:ffff8801f7000000(0000) knlGS:0000000000000000
[  145.877094] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[  145.878201] CR2: 0000000000000024 CR3: 00000001e2684000 CR4: 00000000000006f0
[  145.879569] Call Trace:
[  145.880062]  check_leaf+0x199/0xb90
[  145.880763]  ? check_dir_item+0x450/0x450
[  145.881552]  ? irq_entries_start+0xdf/0x660
[  145.882373]  ? memcpy+0x45/0x50
[  145.882998]  btrfs_check_leaf_full+0x13/0x20
[  145.883836]  btree_readpage_end_io_hook+0x3b9/0x420
[  145.884801]  ? btree_read_extent_buffer_pages+0x3b0/0x3b0
[  145.885849]  ? bio_free+0x91/0xb0
[  145.886507]  ? __update_load_avg_se.isra.39+0x158/0x3a0
[  145.887522]  end_bio_extent_readpage+0x373/0xac0
[  145.888447]  ? btrfs_create_repair_bio+0x1f0/0x1f0
[  145.889377]  ? end_workqueue_fn+0x84/0xa0
[  145.890158]  bio_endio+0x172/0x220
[  145.890827]  ? kasan_slab_free+0xe/0x10
[  145.891575]  ? btrfs_create_repair_bio+0x1f0/0x1f0
[  145.892516]  end_workqueue_fn+0x8c/0xa0
[  145.893268]  normal_work_helper+0xf6/0x500
[  145.894071]  btrfs_endio_meta_helper+0x12/0x20
[  145.894937]  process_one_work+0x2e5/0x760
[  145.895723]  worker_thread+0x90/0x6e0
[  145.896458]  kthread+0x180/0x1d0
[  145.897099]  ? rescuer_thread+0x770/0x770
[  145.897885]  ? kthread_associate_blkcg+0x150/0x150
[  145.898819]  ret_from_fork+0x35/0x40
[  145.899522] Code: 41 54 53 49 89 fc 4c 89 e7 e8 67 db c6 ff 4d 8b 2c 24 be 04 00 00 00 49 8d 5d 24 48 89 df e8 12 df c6 ff 48 89 df e8 4a da c6 ff <41> 8b 45 24 85 c0 74 36 8d 50 01 f0 41 0f b1 55 24 0f 94 c2 84
[  145.903172] RIP: btrfs_root_node+0x36/0x80 RSP: ffff8801e407f980
[  145.904337] CR2: 0000000000000024
[  145.904987] ---[ end trace 9acf891d58e13270 ]---

- Reason
https://elixir.bootlin.com/linux/v4.17-rc5/source/fs/btrfs/ctree.c#L147

while (1) {
		rcu_read_lock();
		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.
		 */
		if (atomic_inc_not_zero(&eb->refs)) {
			rcu_read_unlock();
			break;
		}
		rcu_read_unlock();
		synchronize_rcu();
	}

eb can be NULL and kernel crashes at eb->refs. I guess potential race condition exists. 

- Credit
Found by Wen Xu and Po-Ning Tseng from SSLab, Gatech.
Comment 2 David Sterba 2019-05-21 12:30:26 UTC
Fixed in 4.19.