From: Teng Liu <27rabbitlt@gmail.com>
To: linux-btrfs@vger.kernel.org
Cc: dsterba@suse.com, clm@fb.com, wqu@suse.com,
linux-kernel@vger.kernel.org,
syzbot+3e20d8f3d41bac5dc9a2@syzkaller.appspotmail.com,
Teng Liu <27rabbitlt@gmail.com>
Subject: [PATCH v3] btrfs: validate data reloc tree file extent item members in tree-checker
Date: Mon, 27 Apr 2026 22:24:58 +0200 [thread overview]
Message-ID: <20260427202822.278326-1-27rabbitlt@gmail.com> (raw)
In-Reply-To: <20260426201605.36626-1-27rabbitlt@gmail.com>
get_new_location() uses BUG_ON() to crash the kernel if the file extent
item it looks up has any of offset, compression, encryption, or
other_encoding set. The data reloc inode is only written by relocation's
own paths -- insert_prealloc_file_extent() and
insert_ordered_extent_file_extent() -- which always leave those four
fields at 0 (the data reloc inode is created with BTRFS_INODE_NOCOMPRESS,
and encryption/other_encoding are reserved-and-zero). Observing a
non-zero value therefore means the leaf decoded from disk does not match
what the kernel wrote, i.e. on-disk corruption. A malformed image can
reach this code via balance and panic the kernel.
Move the validation into tree-checker's check_extent_data_item(), where
the constraint is enforced when the leaf is read off disk rather than
after relocation has already started. The data reloc tree has a fixed
root id (BTRFS_DATA_RELOC_TREE_OBJECTID) recorded in the extent buffer
header, so check_extent_data_item() has all the information it needs to
apply this check on its own. Report violations via file_extent_err() and
print the four offending values.
In get_new_location() replace the BUG_ON() with an ASSERT().
The caller in replace_file_extents() already handles non-zero returns from
get_new_location() by breaking out of the loop without aborting the
transaction, so no caller changes are needed.
Suggested-by: Qu Wenruo <wqu@suse.com>
Suggested-by: David Sterba <dsterba@suse.com>
Reported-by: syzbot+3e20d8f3d41bac5dc9a2@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=3e20d8f3d41bac5dc9a2
Signed-off-by: Teng Liu <27rabbitlt@gmail.com>
---
Changes in v3:
- Move the corruption check from relocation.c into tree-checker's
check_extent_data_item(), per Qu and David. The data reloc tree's
fixed objectid is recorded in the extent buffer header, so the
check has all the context it needs at read time.
- Use file_extent_err() and print offset/compression/encryption/
other_encoding values, per Qu.
- Replace the BUG_ON in get_new_location() with ASSERT() rather than
-EUCLEAN, per David.
Changes in v2:
- Pair the -EUCLEAN return with btrfs_print_leaf() and btrfs_err() so
the offending leaf is dumped to dmesg, per Qu's review of v1.
- Expand the changelog to argue why non-zero
compression/encryption/other_encoding in the data reloc inode imply
on-disk corruption.
fs/btrfs/relocation.c | 8 ++++----
fs/btrfs/tree-checker.c | 21 +++++++++++++++++++++
2 files changed, 25 insertions(+), 4 deletions(-)
diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c
index 1c42c5180bdd..527d4dbfe31c 100644
--- a/fs/btrfs/relocation.c
+++ b/fs/btrfs/relocation.c
@@ -835,10 +835,10 @@ static int get_new_location(struct inode *reloc_inode, u64 *new_bytenr,
fi = btrfs_item_ptr(leaf, path->slots[0],
struct btrfs_file_extent_item);
- BUG_ON(btrfs_file_extent_offset(leaf, fi) ||
- btrfs_file_extent_compression(leaf, fi) ||
- btrfs_file_extent_encryption(leaf, fi) ||
- btrfs_file_extent_other_encoding(leaf, fi));
+ ASSERT(!btrfs_file_extent_offset(leaf, fi) &&
+ !btrfs_file_extent_compression(leaf, fi) &&
+ !btrfs_file_extent_encryption(leaf, fi) &&
+ !btrfs_file_extent_other_encoding(leaf, fi));
if (num_bytes != btrfs_file_extent_disk_num_bytes(leaf, fi))
return -EINVAL;
diff --git a/fs/btrfs/tree-checker.c b/fs/btrfs/tree-checker.c
index 1f15d0793a9c..e4864f7a471e 100644
--- a/fs/btrfs/tree-checker.c
+++ b/fs/btrfs/tree-checker.c
@@ -296,6 +296,27 @@ static int check_extent_data_item(struct extent_buffer *leaf,
return 0;
}
+ /*
+ * For the data reloc tree, file extent items are written by
+ * relocation's own paths, which always leave offset, compression,
+ * encryption and other_encoding as 0. Any non-zero value here means
+ * the leaf decoded from disk does not match what the kernel wrote,
+ * i.e. on-disk corruption.
+ */
+ if (unlikely(btrfs_header_owner(leaf) == BTRFS_DATA_RELOC_TREE_OBJECTID &&
+ (btrfs_file_extent_offset(leaf, fi) ||
+ btrfs_file_extent_compression(leaf, fi) ||
+ btrfs_file_extent_encryption(leaf, fi) ||
+ btrfs_file_extent_other_encoding(leaf, fi)))) {
+ file_extent_err(leaf, slot,
+"invalid members for data reloc tree, offset=%llu compress=%u encryption=%u other_encoding=%u",
+ btrfs_file_extent_offset(leaf, fi),
+ btrfs_file_extent_compression(leaf, fi),
+ btrfs_file_extent_encryption(leaf, fi),
+ btrfs_file_extent_other_encoding(leaf, fi));
+ return -EUCLEAN;
+ }
+
/* Regular or preallocated extent has fixed item size */
if (unlikely(item_size != sizeof(*fi))) {
file_extent_err(leaf, slot,
--
2.54.0
next prev parent reply other threads:[~2026-04-27 20:28 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-04-25 6:10 [PATCH] btrfs: replace BUG_ON() with error return in get_new_location() Teng Liu
2026-04-25 8:06 ` Qu Wenruo
2026-04-26 20:16 ` [PATCH v2] " Teng Liu
2026-04-27 1:19 ` Qu Wenruo
2026-04-27 13:50 ` David Sterba
2026-04-27 20:24 ` Teng Liu [this message]
2026-04-27 22:15 ` [PATCH v3] btrfs: validate data reloc tree file extent item members in tree-checker Qu Wenruo
2026-04-28 0:44 ` Qu Wenruo
2026-04-28 15:29 ` David Sterba
2026-04-28 9:03 ` Johannes Thumshirn
2026-05-03 15:35 ` Teng Liu
2026-05-03 22:36 ` Qu Wenruo
2026-05-13 11:35 ` [PATCH v4] btrfs: validate data reloc tree file extent item members Teng Liu
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=20260427202822.278326-1-27rabbitlt@gmail.com \
--to=27rabbitlt@gmail.com \
--cc=clm@fb.com \
--cc=dsterba@suse.com \
--cc=linux-btrfs@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=syzbot+3e20d8f3d41bac5dc9a2@syzkaller.appspotmail.com \
--cc=wqu@suse.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.