4.14-stable review patch.  If anyone has any objections, please let me know.

------------------

From: Qu Wenruo <w...@suse.com>

[ Upstream commit 389305b2aa68723c754f88d9dbd268a400e10664 ]

Invalid reloc tree can cause kernel NULL pointer dereference when btrfs
does some cleanup of the reloc roots.

It turns out that fs_info::reloc_ctl can be NULL in
btrfs_recover_relocation() as we allocate relocation control after all
reloc roots have been verified.
So when we hit: note, we haven't called set_reloc_control() thus
fs_info::reloc_ctl is still NULL.

Link: https://bugzilla.kernel.org/show_bug.cgi?id=199833
Reported-by: Xu Wen <wen...@gatech.edu>
Signed-off-by: Qu Wenruo <w...@suse.com>
Tested-by: Gu Jinxiang <g...@cn.fujitsu.com>
Reviewed-by: David Sterba <dste...@suse.com>
Signed-off-by: David Sterba <dste...@suse.com>
Signed-off-by: Sasha Levin <alexander.le...@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gre...@linuxfoundation.org>
---
 fs/btrfs/relocation.c |   23 ++++++++++++-----------
 1 file changed, 12 insertions(+), 11 deletions(-)

--- a/fs/btrfs/relocation.c
+++ b/fs/btrfs/relocation.c
@@ -1334,18 +1334,19 @@ static void __del_reloc_root(struct btrf
        struct mapping_node *node = NULL;
        struct reloc_control *rc = fs_info->reloc_ctl;
 
-       spin_lock(&rc->reloc_root_tree.lock);
-       rb_node = tree_search(&rc->reloc_root_tree.rb_root,
-                             root->node->start);
-       if (rb_node) {
-               node = rb_entry(rb_node, struct mapping_node, rb_node);
-               rb_erase(&node->rb_node, &rc->reloc_root_tree.rb_root);
+       if (rc) {
+               spin_lock(&rc->reloc_root_tree.lock);
+               rb_node = tree_search(&rc->reloc_root_tree.rb_root,
+                                     root->node->start);
+               if (rb_node) {
+                       node = rb_entry(rb_node, struct mapping_node, rb_node);
+                       rb_erase(&node->rb_node, &rc->reloc_root_tree.rb_root);
+               }
+               spin_unlock(&rc->reloc_root_tree.lock);
+               if (!node)
+                       return;
+               BUG_ON((struct btrfs_root *)node->data != root);
        }
-       spin_unlock(&rc->reloc_root_tree.lock);
-
-       if (!node)
-               return;
-       BUG_ON((struct btrfs_root *)node->data != root);
 
        spin_lock(&fs_info->trans_lock);
        list_del_init(&root->root_list);


Reply via email to