fs/btrfs/backref.c | 6 ++++++ 1 file changed, 6 insertions(+)
handle_indirect_tree_backref() walks up the tree from @cur, storing the
reference returned by btrfs_get_fs_root() in lower->root when the top
of the searched path is reached, and dropping it once a node already in
the backref cache is found. If the walk instead reaches
BTRFS_MAX_LEVEL without hitting either of those two exits, the
reference is neither stored nor dropped and is leaked on return.
Drop the reference and return -EUCLEAN if the walk reaches
BTRFS_MAX_LEVEL without finding the root of the tree.
Fixes: 1b60d2ec982a ("btrfs: backref: rename and move handle_one_tree_block()")
Cc: stable@vger.kernel.org
Signed-off-by: Wentao Liang <vulab@iscas.ac.cn>
---
fs/btrfs/backref.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/fs/btrfs/backref.c b/fs/btrfs/backref.c
index 273924ca912c..e889fbec4fe1 100644
--- a/fs/btrfs/backref.c
+++ b/fs/btrfs/backref.c
@@ -3426,6 +3426,12 @@ static int handle_indirect_tree_backref(struct btrfs_trans_handle *trans,
lower = upper;
upper = NULL;
}
+ /* We walked up to BTRFS_MAX_LEVEL without reaching the tree root. */
+ if (level == BTRFS_MAX_LEVEL) {
+ btrfs_put_root(root);
+ ret = -EUCLEAN;
+ goto out;
+ }
out:
btrfs_release_path(path);
return ret;
--
2.34.1
On Wed, Sep 16, 2026 at 05:13:19PM +0000, Wentao Liang wrote:
> handle_indirect_tree_backref() walks up the tree from @cur, storing the
> reference returned by btrfs_get_fs_root() in lower->root when the top
> of the searched path is reached, and dropping it once a node already in
> the backref cache is found. If the walk instead reaches
> BTRFS_MAX_LEVEL without hitting either of those two exits, the
> reference is neither stored nor dropped and is leaked on return.
Are you able to reproduce this bug? If so, can you include that
information in the commit message.
>
> Drop the reference and return -EUCLEAN if the walk reaches
> BTRFS_MAX_LEVEL without finding the root of the tree.
>
> Fixes: 1b60d2ec982a ("btrfs: backref: rename and move handle_one_tree_block()")
> Cc: stable@vger.kernel.org
> Signed-off-by: Wentao Liang <vulab@iscas.ac.cn>
> ---
> fs/btrfs/backref.c | 6 ++++++
> 1 file changed, 6 insertions(+)
>
> diff --git a/fs/btrfs/backref.c b/fs/btrfs/backref.c
> index 273924ca912c..e889fbec4fe1 100644
> --- a/fs/btrfs/backref.c
> +++ b/fs/btrfs/backref.c
> @@ -3426,6 +3426,12 @@ static int handle_indirect_tree_backref(struct btrfs_trans_handle *trans,
> lower = upper;
> upper = NULL;
> }
> + /* We walked up to BTRFS_MAX_LEVEL without reaching the tree root. */
> + if (level == BTRFS_MAX_LEVEL) {
> + btrfs_put_root(root);
> + ret = -EUCLEAN;
> + goto out;
> + }
> out:
> btrfs_release_path(path);
> return ret;
> --
> 2.34.1
>
On Fri, Sep 18, 2026 at 12:13:42PM -0700, Boris Burkov wrote: > On Wed, Sep 16, 2026 at 05:13:19PM +0000, Wentao Liang wrote: > > handle_indirect_tree_backref() walks up the tree from @cur, storing the > > reference returned by btrfs_get_fs_root() in lower->root when the top > > of the searched path is reached, and dropping it once a node already in > > the backref cache is found. If the walk instead reaches > > BTRFS_MAX_LEVEL without hitting either of those two exits, the > > reference is neither stored nor dropped and is leaked on return. > > Are you able to reproduce this bug? If so, can you include that > information in the commit message. A filesystem with a tree of maximum height consumes a lot of metadata space and in practice it's difficult to create one. For completeness the check could be there, we have other impossible condition checks elsewhere too.
© 2016 - 2026 Red Hat, Inc.