From: Zhang Cen <rollkingzzc@gmail.com>
To: Zhang Cen <rollkingzzc@gmail.com>, Chris Mason <clm@fb.com>,
David Sterba <dsterba@suse.com>
Cc: linux-btrfs@vger.kernel.org, Qu Wenruo <wqu@suse.com>,
zerocling0077@gmail.com, 2045gemini@gmail.com
Subject: [PATCH v3] btrfs: validate root ref names in tree-checker
Date: Sun, 10 May 2026 23:03:22 +0800 [thread overview]
Message-ID: <20260510150322.3778139-1-rollkingzzc@gmail.com> (raw)
In-Reply-To: <20260510074943.2644335-1-rollkingzzc@gmail.com>
ROOT_REF and ROOT_BACKREF items contain a struct btrfs_root_ref followed
by the subvolume name. Several readers assume that this layout is already
valid and then use the on-disk name length directly. A corrupted item can
therefore make those readers address bytes outside the item, and
BTRFS_IOC_GET_SUBVOL_INFO can copy too many bytes into its fixed-size UAPI
name buffer.
Validate ROOT_REF and ROOT_BACKREF items in tree-checker before any reader
uses them. Reject items smaller than struct btrfs_root_ref, reject records
whose name_len does not exactly describe the remaining item payload, and
reject names longer than BTRFS_SUBVOL_NAME_MAX.
For BTRFS_IOC_GET_SUBVOL_INFO, copy only the validated on-disk name_len and
keep a local BTRFS_VOL_NAME_MAX guard for the fixed ioctl output field.
Terminate the copied name explicitly.
Sanitizer validation reported:
BUG: KASAN: slab-out-of-bounds in read_extent_buffer()
Write of size 505 at addr ffff88810936d608
Call trace:
read_extent_buffer()
btrfs_ioctl_get_subvol_info()
Signed-off-by: Zhang Cen <rollkingzzc@gmail.com>
---
Changes since v2:
- Regenerate the mail-ready patch without the nested mbox wrapper.
- No code changes beyond the v2 fix.
fs/btrfs/ioctl.c | 17 +++++++++++++----
fs/btrfs/tree-checker.c | 39 +++++++++++++++++++++++++++++++++++++++
2 files changed, 52 insertions(+), 4 deletions(-)
diff --git aa/fs/btrfs/ioctl.c bb/fs/btrfs/ioctl.c
index a39460bf68a7..b43d33eaea07 100644
--- aa/fs/btrfs/ioctl.c
+++ bb/fs/btrfs/ioctl.c
@@ -1956,7 +1956,8 @@ static int btrfs_ioctl_get_subvol_info(struct inode *inode, void __user *argp)
struct btrfs_root_ref *rref;
struct extent_buffer *leaf;
unsigned long item_off;
- unsigned long item_len;
+ u32 item_size;
+ u16 name_len;
int slot;
int ret = 0;
@@ -2034,14 +2035,21 @@ static int btrfs_ioctl_get_subvol_info(struct inode *inode, void __user *argp)
subvol_info->parent_id = key.offset;
rref = btrfs_item_ptr(leaf, slot, struct btrfs_root_ref);
+ item_size = btrfs_item_size(leaf, slot);
+ name_len = btrfs_root_ref_name_len(leaf, rref);
+ if (name_len > item_size - sizeof(*rref) ||
+ name_len > BTRFS_VOL_NAME_MAX) {
+ ret = -EUCLEAN;
+ goto out;
+ }
+
subvol_info->dirid = btrfs_root_ref_dirid(leaf, rref);
- item_off = btrfs_item_ptr_offset(leaf, slot)
- + sizeof(struct btrfs_root_ref);
- item_len = btrfs_item_size(leaf, slot)
- - sizeof(struct btrfs_root_ref);
+ item_off = btrfs_item_ptr_offset(leaf, slot) +
+ sizeof(*rref);
read_extent_buffer(leaf, subvol_info->name,
- item_off, item_len);
+ item_off, name_len);
+ subvol_info->name[name_len] = '\0';
} else {
ret = -ENOENT;
goto out;
diff --git aa/fs/btrfs/tree-checker.c bb/fs/btrfs/tree-checker.c
index 1f15d0793a9c..41417b2df32d 100644
--- aa/fs/btrfs/tree-checker.c
+++ bb/fs/btrfs/tree-checker.c
@@ -1371,6 +1371,38 @@ static int check_root_item(struct extent_buffer *leaf, struct btrfs_key *key,
return 0;
}
+static int check_root_ref(struct extent_buffer *leaf, struct btrfs_key *key,
+ int slot)
+{
+ struct btrfs_root_ref *rref;
+ u32 item_size = btrfs_item_size(leaf, slot);
+ u32 name_len;
+
+ if (unlikely(item_size < sizeof(*rref))) {
+ generic_err(leaf, slot,
+ "invalid root ref item size for key type %u, have %u expect >= %zu",
+ key->type, item_size, sizeof(*rref));
+ return -EUCLEAN;
+ }
+
+ rref = btrfs_item_ptr(leaf, slot, struct btrfs_root_ref);
+ name_len = btrfs_root_ref_name_len(leaf, rref);
+ if (unlikely(name_len > BTRFS_SUBVOL_NAME_MAX)) {
+ generic_err(leaf, slot,
+ "root ref name too long for key type %u, have %u max %u",
+ key->type, name_len, BTRFS_SUBVOL_NAME_MAX);
+ return -EUCLEAN;
+ }
+ if (unlikely(item_size != sizeof(*rref) + name_len)) {
+ generic_err(leaf, slot,
+ "invalid root ref item size for key type %u, have %u expect %zu",
+ key->type, item_size, sizeof(*rref) + name_len);
+ return -EUCLEAN;
+ }
+
+ return 0;
+}
+
__printf(3,4)
__cold
static void extent_err(const struct extent_buffer *eb, int slot,
@@ -2226,6 +2258,10 @@ static enum btrfs_tree_block_status check_leaf_item(struct extent_buffer *leaf,
case BTRFS_ROOT_ITEM_KEY:
ret = check_root_item(leaf, key, slot);
break;
+ case BTRFS_ROOT_REF_KEY:
+ case BTRFS_ROOT_BACKREF_KEY:
+ ret = check_root_ref(leaf, key, slot);
+ break;
case BTRFS_EXTENT_ITEM_KEY:
case BTRFS_METADATA_ITEM_KEY:
ret = check_extent_item(leaf, key, slot, prev_key);
--
2.43.0
next prev parent reply other threads:[~2026-05-10 15:03 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-05-10 7:49 [PATCH] btrfs: validate ROOT_BACKREF name before copying subvolume info Zhang Cen
2026-05-10 8:18 ` Qu Wenruo
[not found] ` <qu-root-backref-20260510-161800@local>
2026-05-10 14:37 ` Zhang Cen
2026-05-10 14:42 ` [PATCH v2] btrfs: validate root ref names in tree-checker Zhang Cen
2026-05-10 14:46 ` Cen Zhang
2026-05-10 15:03 ` Zhang Cen [this message]
2026-05-10 22:12 ` [PATCH v3] " Qu Wenruo
-- strict thread matches above, loose matches on Subject: below --
2026-05-10 15:28 Zhang Cen
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=20260510150322.3778139-1-rollkingzzc@gmail.com \
--to=rollkingzzc@gmail.com \
--cc=2045gemini@gmail.com \
--cc=clm@fb.com \
--cc=dsterba@suse.com \
--cc=linux-btrfs@vger.kernel.org \
--cc=wqu@suse.com \
--cc=zerocling0077@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 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.