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 |
在 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 --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); }