Patch "btrfs: fix inode list leak during backref walking at find_parent_nodes()" has been added to the 5.4-stable tree

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This is a note to let you know that I've just added the patch titled

    btrfs: fix inode list leak during backref walking at find_parent_nodes()

to the 5.4-stable tree which can be found at:
    http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
     btrfs-fix-inode-list-leak-during-backref-walking-at-.patch
and it can be found in the queue-5.4 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <stable@xxxxxxxxxxxxxxx> know about it.



commit 94f5bb90b0a9d73d2cfe9c85f07dcc09af84f70f
Author: Filipe Manana <fdmanana@xxxxxxxx>
Date:   Tue Nov 1 16:15:38 2022 +0000

    btrfs: fix inode list leak during backref walking at find_parent_nodes()
    
    [ Upstream commit 92876eec382a0f19f33d09d2c939e9ca49038ae5 ]
    
    During backref walking, at find_parent_nodes(), if we are dealing with a
    data extent and we get an error while resolving the indirect backrefs, at
    resolve_indirect_refs(), or in the while loop that iterates over the refs
    in the direct refs rbtree, we end up leaking the inode lists attached to
    the direct refs we have in the direct refs rbtree that were not yet added
    to the refs ulist passed as argument to find_parent_nodes(). Since they
    were not yet added to the refs ulist and prelim_release() does not free
    the lists, on error the caller can only free the lists attached to the
    refs that were added to the refs ulist, all the remaining refs get their
    inode lists never freed, therefore leaking their memory.
    
    Fix this by having prelim_release() always free any attached inode list
    to each ref found in the rbtree, and have find_parent_nodes() set the
    ref's inode list to NULL once it transfers ownership of the inode list
    to a ref added to the refs ulist passed to find_parent_nodes().
    
    Fixes: 86d5f9944252 ("btrfs: convert prelimary reference tracking to use rbtrees")
    Signed-off-by: Filipe Manana <fdmanana@xxxxxxxx>
    Signed-off-by: David Sterba <dsterba@xxxxxxxx>
    Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>

diff --git a/fs/btrfs/backref.c b/fs/btrfs/backref.c
index 4809cc07a885..3cbca2ebdeb0 100644
--- a/fs/btrfs/backref.c
+++ b/fs/btrfs/backref.c
@@ -287,8 +287,10 @@ static void prelim_release(struct preftree *preftree)
 	struct prelim_ref *ref, *next_ref;
 
 	rbtree_postorder_for_each_entry_safe(ref, next_ref,
-					     &preftree->root.rb_root, rbnode)
+					     &preftree->root.rb_root, rbnode) {
+		free_inode_elem_list(ref->inode_list);
 		free_pref(ref);
+	}
 
 	preftree->root = RB_ROOT_CACHED;
 	preftree->count = 0;
@@ -1383,6 +1385,12 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans,
 				if (ret < 0)
 					goto out;
 				ref->inode_list = eie;
+				/*
+				 * We transferred the list ownership to the ref,
+				 * so set to NULL to avoid a double free in case
+				 * an error happens after this.
+				 */
+				eie = NULL;
 			}
 			ret = ulist_add_merge_ptr(refs, ref->parent,
 						  ref->inode_list,
@@ -1408,6 +1416,14 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans,
 				eie->next = ref->inode_list;
 			}
 			eie = NULL;
+			/*
+			 * We have transferred the inode list ownership from
+			 * this ref to the ref we added to the 'refs' ulist.
+			 * So set this ref's inode list to NULL to avoid
+			 * use-after-free when our caller uses it or double
+			 * frees in case an error happens before we return.
+			 */
+			ref->inode_list = NULL;
 		}
 		cond_resched();
 	}



[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux