diff mbox series

btrfs: fix use-after-free on rbtree that tracks inodes for auto defrag

Message ID 743f120462032370c7ae8ff899bfd8dbfb0ed006.1726486545.git.fdmanana@suse.com (mailing list archive)
State New, archived
Headers show
Series btrfs: fix use-after-free on rbtree that tracks inodes for auto defrag | expand

Commit Message

Filipe Manana Sept. 16, 2024, 11:37 a.m. UTC
From: Filipe Manana <fdmanana@suse.com>

When cleaning up defrag inodes at btrfs_cleanup_defrag_inodes(), called
during remount and unmount, we are freeing every node from the rbtree
that tracks inodes for auto defrag using
rbtree_postorder_for_each_entry_safe(), which doesn't modify the tree
itself. So once we unlock the lock that protects the rbtree, we have a
tree pointing to a root that was freed (and a root pointing to freed
nodes, and their children pointing to other freed nodes, and so on).
This makes further access to the tree result in a use-after-free with
unpredictable results.

Fix this by initializing the rbtree to an empty root after the call to
rbtree_postorder_for_each_entry_safe() and before unlocking.

Fixes: 276940915f23 ("btrfs: clear defragmented inodes using postorder in btrfs_cleanup_defrag_inodes()")
Signed-off-by: Filipe Manana <fdmanana@suse.com>
---
 fs/btrfs/defrag.c | 2 ++
 1 file changed, 2 insertions(+)

Comments

Qu Wenruo Sept. 16, 2024, 9:46 p.m. UTC | #1
在 2024/9/16 21:07, fdmanana@kernel.org 写道:
> From: Filipe Manana <fdmanana@suse.com>
>
> When cleaning up defrag inodes at btrfs_cleanup_defrag_inodes(), called
> during remount and unmount, we are freeing every node from the rbtree
> that tracks inodes for auto defrag using
> rbtree_postorder_for_each_entry_safe(), which doesn't modify the tree
> itself. So once we unlock the lock that protects the rbtree, we have a
> tree pointing to a root that was freed (and a root pointing to freed
> nodes, and their children pointing to other freed nodes, and so on).
> This makes further access to the tree result in a use-after-free with
> unpredictable results.
>
> Fix this by initializing the rbtree to an empty root after the call to
> rbtree_postorder_for_each_entry_safe() and before unlocking.
>
> Fixes: 276940915f23 ("btrfs: clear defragmented inodes using postorder in btrfs_cleanup_defrag_inodes()")
> Signed-off-by: Filipe Manana <fdmanana@suse.com>

Reviewed-by: Qu Wenruo <wqu@suse.com>

Thanks,
Qu
> ---
>   fs/btrfs/defrag.c | 2 ++
>   1 file changed, 2 insertions(+)
>
> diff --git a/fs/btrfs/defrag.c b/fs/btrfs/defrag.c
> index acf1f39e45d0..b95ef44c326b 100644
> --- a/fs/btrfs/defrag.c
> +++ b/fs/btrfs/defrag.c
> @@ -213,6 +213,8 @@ void btrfs_cleanup_defrag_inodes(struct btrfs_fs_info *fs_info)
>   					     &fs_info->defrag_inodes, rb_node)
>   		kmem_cache_free(btrfs_inode_defrag_cachep, defrag);
>
> +	fs_info->defrag_inodes = RB_ROOT;
> +
>   	spin_unlock(&fs_info->defrag_inodes_lock);
>   }
>
diff mbox series

Patch

diff --git a/fs/btrfs/defrag.c b/fs/btrfs/defrag.c
index acf1f39e45d0..b95ef44c326b 100644
--- a/fs/btrfs/defrag.c
+++ b/fs/btrfs/defrag.c
@@ -213,6 +213,8 @@  void btrfs_cleanup_defrag_inodes(struct btrfs_fs_info *fs_info)
 					     &fs_info->defrag_inodes, rb_node)
 		kmem_cache_free(btrfs_inode_defrag_cachep, defrag);
 
+	fs_info->defrag_inodes = RB_ROOT;
+
 	spin_unlock(&fs_info->defrag_inodes_lock);
 }