[PATCH v3 2/2] btrfs: fix the unsafe access in btrfs_lookup_first_ordered_range()
From: Qu Wenruo <hidden>
Date: 2021-05-18 07:09:53
Subsystem:
btrfs file system, filesystems (vfs and infrastructure), the rest · Maintainers:
Chris Mason, David Sterba, Alexander Viro, Christian Brauner, Linus Torvalds
Please fold this fix into patch "btrfs: introduce btrfs_lookup_first_ordered_range()". [BUG] David reported a failure in generic/521 which btrfs_lookup_first_ordered_range() got a poisoned pointer: run fstests generic/521 at 2021-05-14 00:33:06 general protection fault, probably for non-canonical address 0x6b6b6b6b6b6b6a9b: 0000 [#1] PREEMPT SMP CPU: 0 PID: 20046 Comm: fsx Not tainted 5.13.0-rc1-default+ #1463 RIP: 0010:btrfs_lookup_first_ordered_range+0x46/0x140 [btrfs] RAX: 6b6b6b6b6b6b6b6b RBX: 6b6b6b6b6b6b6b6b RCX: ffffffffffffffff RDX: 6b6b6b6b6b6b6b6b RSI: ffffffffc01b3e09 RDI: ffff93c444e397d0 Call Trace: btrfs_invalidatepage+0xd3/0x390 [btrfs] truncate_cleanup_page+0xda/0x170 truncate_inode_pages_range+0x131/0x5a0 ? trace_btrfs_space_reservation+0x33/0xf0 [btrfs] ? lock_acquire+0xa0/0x150 ? unmap_mapping_pages+0x4d/0x130 ? do_raw_spin_unlock+0x4b/0xa0 ? unmap_mapping_pages+0x5e/0x130 btrfs_punch_hole_lock_range+0xc5/0x130 [btrfs] btrfs_zero_range+0x1d7/0x4b0 [btrfs] btrfs_fallocate+0x6b4/0x890 [btrfs] ? __x64_sys_fallocate+0x3e/0x70 ? __do_sys_newfstatat+0x40/0x70 vfs_fallocate+0x12e/0x420 __x64_sys_fallocate+0x3e/0x70 do_syscall_64+0x3f/0xb0 entry_SYSCALL_64_after_hwframe+0x44/0xae [CAUSE] Although I can't reproduce, according to the line number, it's in the btree search code, and just lines before that, I use some copied code from tree_search(): struct rb_node *node = tree->tree.rb_node; But that assignment is out of spinlock, which is not safe to access, thus lead to above poisoned pointer. Unlike tree_search(), which callers have already hold the spinlock. [FIX] Fix it by only assign @node after we have hold the spinlock. Signed-off-by: Qu Wenruo <redacted> --- fs/btrfs/ordered-data.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/fs/btrfs/ordered-data.c b/fs/btrfs/ordered-data.c
index 4fa377da40e4..b1b377ad99a0 100644
--- a/fs/btrfs/ordered-data.c
+++ b/fs/btrfs/ordered-data.c@@ -943,13 +943,14 @@ struct btrfs_ordered_extent *btrfs_lookup_first_ordered_range( struct btrfs_inode *inode, u64 file_offset, u64 len) { struct btrfs_ordered_inode_tree *tree = &inode->ordered_tree; - struct rb_node *node = tree->tree.rb_node; + struct rb_node *node; struct rb_node *cur; struct rb_node *prev; struct rb_node *next; struct btrfs_ordered_extent *entry = NULL; spin_lock_irq(&tree->lock); + node = tree->tree.rb_node; /* * Here we don't want to use tree_search() which will use tree->last * and screw up the search order.
--
2.31.1