mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Qu Wenruo <wqu@suse.com>
To: ZhengYuan Huang <gality369@gmail.com>, dsterba@suse.com, clm@fb.com
Cc: linux-btrfs@vger.kernel.org, linux-kernel@vger.kernel.org,
	baijiaju1990@gmail.com, r33s3n6@gmail.com, zzzccc427@gmail.com,
	stable@vger.kernel.org
Subject: Re: [PATCH] btrfs: reject root with mismatched level between root_item and node header
Date: Fri, 13 Mar 2026 07:59:14 +1030	[thread overview]
Message-ID: <ac5058d0-ba4e-4de6-b231-64a29ee2d5e3@suse.com> (raw)
In-Reply-To: <20260312102229.220570-1-gality369@gmail.com>



在 2026/3/12 20:52, ZhengYuan Huang 写道:
[...]
> 
> [FIX]
> Catch the inconsistency in read_tree_root_path(), right after read_tree_block()
> returns root->node and the generation and owner checks have passed. At that
> point level = btrfs_root_level(&root->root_item) is already known, so
> comparing it against btrfs_header_level(root->node) costs nothing. If they
> differ, emit a btrfs_crit() message and return -EUCLEAN to prevent the
> inconsistent btrfs_root object from being installed in the radix-tree cache
> and reaching any caller. read_tree_root_path() is the only place that sees
> both root_item.level and the actual root node simultaneously, making it the
> correct and minimal location for this cross-block consistency check.
> Returning -EUCLEAN is consistent with the existing owner-mismatch check
> directly above and with the general btrfs policy of converting detectable
> corruption into -EUCLEAN rather than crashing later.
> 
> After the fix, btrfs detects the level mismatch at root load time and
> fails with -EUCLEAN instead of crashing later in
> handle_indirect_tree_backref().
> 
> Cc: stable@vger.kernel.org
> Signed-off-by: ZhengYuan Huang <gality369@gmail.com>
> ---
>   fs/btrfs/disk-io.c | 20 ++++++++++++++++++++
>   1 file changed, 20 insertions(+)
> 
> diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
> index 900e462d8ea1..06a8689cbf62 100644
> --- a/fs/btrfs/disk-io.c
> +++ b/fs/btrfs/disk-io.c
> @@ -1067,6 +1067,26 @@ static struct btrfs_root *read_tree_root_path(struct btrfs_root *tree_root,
>   		ret = -EUCLEAN;
>   		goto fail;
>   	}
> +	/*
> +	 * Verify that the root node's on-disk level matches root_item.level.
> +	 * These can diverge when the root item in the root tree was corrupted
> +	 * (e.g. a bit flip changing level) while the actual tree block is
> +	 * already cached in memory at its real level. In that case
> +	 * read_tree_block() returns the cached buffer without re-running
> +	 * btrfs_validate_extent_buffer(), silently bypassing the level check.
> +	 * The mismatch would later cause a null-ptr-deref in backref walking
> +	 * (handle_indirect_tree_backref) when the commit root's real height is
> +	 * lower than what root_item.level claims.
> +	 */
> +	if (unlikely(btrfs_header_level(root->node) != level)) {

Nope, we have btrfs_tree_parent_check structure, which has all the 
needed checks at read time.

The point of using that other than doing it manually here is, if one 
mirror is bad, but the other mirror is good, then we can still grab the 
good copy, but checking it here means if we got the bad mirror first, we 
have no more chance.

And during read of root-node, we have already passed the proper level 
into it.

So the only possibility is, your fuzzing tool is modifying the memory 
after the read check.

If so, it's impossible to fix.

> +		btrfs_crit(fs_info,
> +           "root=%llu block=%llu, root item level mismatch: "
> +           "root_item.level=%d block.level=%u",
> +           btrfs_root_id(root), root->node->start,
> +           level, btrfs_header_level(root->node));
> +		ret = -EUCLEAN;
> +		goto fail;
> +	}
>   	root->commit_root = btrfs_root_node(root);
>   	return root;
>   fail:


  reply	other threads:[~2026-03-12 21:29 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-03-12 10:22 ZhengYuan Huang
2026-03-12 21:29 ` Qu Wenruo [this message]
2026-03-13  2:49   ` ZhengYuan Huang
2026-03-13  3:09     ` Qu Wenruo

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=ac5058d0-ba4e-4de6-b231-64a29ee2d5e3@suse.com \
    --to=wqu@suse.com \
    --cc=baijiaju1990@gmail.com \
    --cc=clm@fb.com \
    --cc=dsterba@suse.com \
    --cc=gality369@gmail.com \
    --cc=linux-btrfs@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=r33s3n6@gmail.com \
    --cc=stable@vger.kernel.org \
    --cc=zzzccc427@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®