Linux Btrfs filesystem development
 help / color / mirror / Atom feed
* [PATCH] btrfs: reject names longer than BTRFS_NAME_LEN in btrfs_get_name()
@ 2026-06-07 12:14 Weiming Shi
  2026-06-07 20:23 ` Miquel Sabaté Solà
  2026-06-07 22:21 ` Qu Wenruo
  0 siblings, 2 replies; 4+ messages in thread
From: Weiming Shi @ 2026-06-07 12:14 UTC (permalink / raw)
  To: linux-btrfs; +Cc: dsterba, josef, clm, xmei5, Weiming Shi

btrfs_get_name() reads the name length straight from the on-disk
inode_ref (or root_ref) and copies that many bytes into the caller's
buffer with no upper bound. The caller (exportfs_get_name()) supplies a
fixed NAME_MAX + 1 byte stack buffer, but name_len is a __le16 read from
the leaf and the tree-checker only bounds it to the item size, not to
BTRFS_NAME_LEN. A crafted leaf with name_len = 4096 therefore overflows
the 256-byte buffer with attacker-controlled bytes. It is reachable from
a mounted untrusted btrfs image via open_by_handle_at(), and on btrfs
filesystems exported over NFS.

 BUG: KASAN: stack-out-of-bounds in read_extent_buffer (fs/btrfs/extent_io.c:3742)
 Write of size 633 at addr ffffc90006c9fc40 by task exploit/5192
  read_extent_buffer (fs/btrfs/extent_io.c:3742)
  btrfs_get_name (fs/btrfs/export.c:289)
  reconnect_path (fs/exportfs/expfs.c:222)
  exportfs_decode_fh_raw (fs/exportfs/expfs.c:473)
  do_handle_open (fs/fhandle.c:230)
  do_syscall_64 (arch/x86/entry/syscall_64.c:94)
 Kernel panic - not syncing: stack-protector: Kernel stack is corrupted

Reject any name_len greater than BTRFS_NAME_LEN before the copy. Such a
name is never valid on disk, so this only rejects corrupted leaves and
leaves valid names unchanged.

Fixes: 2ede0daf0154 ("Btrfs: handle NFS lookups properly")
Reported-by: Xiang Mei <xmei5@asu.edu>
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Weiming Shi <bestswngs@gmail.com>
---
 fs/btrfs/export.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/fs/btrfs/export.c b/fs/btrfs/export.c
index c403117ac..a54c6e8b3 100644
--- a/fs/btrfs/export.c
+++ b/fs/btrfs/export.c
@@ -285,6 +285,16 @@ static int btrfs_get_name(struct dentry *parent, char *name,
 		name_len = btrfs_inode_ref_name_len(leaf, iref);
 	}
 
+	/* The caller's buffer is only NAME_MAX + 1 bytes. */
+	if (name_len > BTRFS_NAME_LEN) {
+		btrfs_err(fs_info,
+			  "corrupt name length %d for inode %llu in root %llu, max %d",
+			  name_len, btrfs_ino(BTRFS_I(inode)),
+			  btrfs_root_id(BTRFS_I(inode)->root), BTRFS_NAME_LEN);
+		btrfs_free_path(path);
+		return -EUCLEAN;
+	}
+
 	read_extent_buffer(leaf, name, name_ptr, name_len);
 	btrfs_free_path(path);
 
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH] btrfs: reject names longer than BTRFS_NAME_LEN in btrfs_get_name()
  2026-06-07 12:14 [PATCH] btrfs: reject names longer than BTRFS_NAME_LEN in btrfs_get_name() Weiming Shi
@ 2026-06-07 20:23 ` Miquel Sabaté Solà
  2026-06-07 22:21 ` Qu Wenruo
  1 sibling, 0 replies; 4+ messages in thread
From: Miquel Sabaté Solà @ 2026-06-07 20:23 UTC (permalink / raw)
  To: Weiming Shi; +Cc: linux-btrfs, dsterba, josef, clm, xmei5

[-- Attachment #1: Type: text/plain, Size: 2429 bytes --]

Hi,

Weiming Shi @ 2026-06-07 05:14 -07:

> btrfs_get_name() reads the name length straight from the on-disk
> inode_ref (or root_ref) and copies that many bytes into the caller's
> buffer with no upper bound. The caller (exportfs_get_name()) supplies a
> fixed NAME_MAX + 1 byte stack buffer, but name_len is a __le16 read from
> the leaf and the tree-checker only bounds it to the item size, not to
> BTRFS_NAME_LEN. A crafted leaf with name_len = 4096 therefore overflows
> the 256-byte buffer with attacker-controlled bytes. It is reachable from
> a mounted untrusted btrfs image via open_by_handle_at(), and on btrfs
> filesystems exported over NFS.
>
>  BUG: KASAN: stack-out-of-bounds in read_extent_buffer (fs/btrfs/extent_io.c:3742)
>  Write of size 633 at addr ffffc90006c9fc40 by task exploit/5192
>   read_extent_buffer (fs/btrfs/extent_io.c:3742)
>   btrfs_get_name (fs/btrfs/export.c:289)
>   reconnect_path (fs/exportfs/expfs.c:222)
>   exportfs_decode_fh_raw (fs/exportfs/expfs.c:473)
>   do_handle_open (fs/fhandle.c:230)
>   do_syscall_64 (arch/x86/entry/syscall_64.c:94)
>  Kernel panic - not syncing: stack-protector: Kernel stack is corrupted
>
> Reject any name_len greater than BTRFS_NAME_LEN before the copy. Such a
> name is never valid on disk, so this only rejects corrupted leaves and
> leaves valid names unchanged.
>
> Fixes: 2ede0daf0154 ("Btrfs: handle NFS lookups properly")
> Reported-by: Xiang Mei <xmei5@asu.edu>
> Assisted-by: Claude:claude-opus-4-8
> Signed-off-by: Weiming Shi <bestswngs@gmail.com>
> ---
>  fs/btrfs/export.c | 10 ++++++++++
>  1 file changed, 10 insertions(+)
>
> diff --git a/fs/btrfs/export.c b/fs/btrfs/export.c
> index c403117ac..a54c6e8b3 100644
> --- a/fs/btrfs/export.c
> +++ b/fs/btrfs/export.c
> @@ -285,6 +285,16 @@ static int btrfs_get_name(struct dentry *parent, char *name,
>  		name_len = btrfs_inode_ref_name_len(leaf, iref);
>  	}
>
> +	/* The caller's buffer is only NAME_MAX + 1 bytes. */
> +	if (name_len > BTRFS_NAME_LEN) {
> +		btrfs_err(fs_info,
> +			  "corrupt name length %d for inode %llu in root %llu, max %d",
> +			  name_len, btrfs_ino(BTRFS_I(inode)),
> +			  btrfs_root_id(BTRFS_I(inode)->root), BTRFS_NAME_LEN);
> +		btrfs_free_path(path);

Nitpicking: this is not necessary as 'path' is declared with a cleanup
attribute.

> +		return -EUCLEAN;
> +	}
> +
>  	read_extent_buffer(leaf, name, name_ptr, name_len);
>  	btrfs_free_path(path);

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 897 bytes --]

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] btrfs: reject names longer than BTRFS_NAME_LEN in btrfs_get_name()
  2026-06-07 12:14 [PATCH] btrfs: reject names longer than BTRFS_NAME_LEN in btrfs_get_name() Weiming Shi
  2026-06-07 20:23 ` Miquel Sabaté Solà
@ 2026-06-07 22:21 ` Qu Wenruo
  2026-06-08  9:58   ` Weiming Shi
  1 sibling, 1 reply; 4+ messages in thread
From: Qu Wenruo @ 2026-06-07 22:21 UTC (permalink / raw)
  To: Weiming Shi, linux-btrfs; +Cc: dsterba, josef, clm, xmei5



在 2026/6/7 21:44, Weiming Shi 写道:
> btrfs_get_name() reads the name length straight from the on-disk
> inode_ref (or root_ref) and copies that many bytes into the caller's
> buffer with no upper bound. The caller (exportfs_get_name()) supplies a
> fixed NAME_MAX + 1 byte stack buffer, but name_len is a __le16 read from
> the leaf and the tree-checker only bounds it to the item size, not to
> BTRFS_NAME_LEN. A crafted leaf with name_len = 4096 therefore overflows
> the 256-byte buffer with attacker-controlled bytes. It is reachable from
> a mounted untrusted btrfs image via open_by_handle_at(), and on btrfs
> filesystems exported over NFS.
> 
>   BUG: KASAN: stack-out-of-bounds in read_extent_buffer (fs/btrfs/extent_io.c:3742)
>   Write of size 633 at addr ffffc90006c9fc40 by task exploit/5192
>    read_extent_buffer (fs/btrfs/extent_io.c:3742)
>    btrfs_get_name (fs/btrfs/export.c:289)
>    reconnect_path (fs/exportfs/expfs.c:222)
>    exportfs_decode_fh_raw (fs/exportfs/expfs.c:473)
>    do_handle_open (fs/fhandle.c:230)
>    do_syscall_64 (arch/x86/entry/syscall_64.c:94)
>   Kernel panic - not syncing: stack-protector: Kernel stack is corrupted
> 
> Reject any name_len greater than BTRFS_NAME_LEN before the copy. Such a
> name is never valid on disk, so this only rejects corrupted leaves and
> leaves valid names unchanged.
> 
> Fixes: 2ede0daf0154 ("Btrfs: handle NFS lookups properly")
> Reported-by: Xiang Mei <xmei5@asu.edu>
> Assisted-by: Claude:claude-opus-4-8
> Signed-off-by: Weiming Shi <bestswngs@gmail.com>
> ---
>   fs/btrfs/export.c | 10 ++++++++++
>   1 file changed, 10 insertions(+)
> 
> diff --git a/fs/btrfs/export.c b/fs/btrfs/export.c
> index c403117ac..a54c6e8b3 100644
> --- a/fs/btrfs/export.c
> +++ b/fs/btrfs/export.c
> @@ -285,6 +285,16 @@ static int btrfs_get_name(struct dentry *parent, char *name,
>   		name_len = btrfs_inode_ref_name_len(leaf, iref);
>   	}
>   
> +	/* The caller's buffer is only NAME_MAX + 1 bytes. */
> +	if (name_len > BTRFS_NAME_LEN) {

We do not play the whac-a-mole game by add random checks ad-hoc.

Do the proper ROOT_REF_KEY and INODE_REF_KEY verification inside 
tree-checker.

> +		btrfs_err(fs_info,
> +			  "corrupt name length %d for inode %llu in root %llu, max %d",
> +			  name_len, btrfs_ino(BTRFS_I(inode)),
> +			  btrfs_root_id(BTRFS_I(inode)->root), BTRFS_NAME_LEN);
> +		btrfs_free_path(path);
> +		return -EUCLEAN;
> +	}
> +
>   	read_extent_buffer(leaf, name, name_ptr, name_len);
>   	btrfs_free_path(path);
>   


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] btrfs: reject names longer than BTRFS_NAME_LEN in btrfs_get_name()
  2026-06-07 22:21 ` Qu Wenruo
@ 2026-06-08  9:58   ` Weiming Shi
  0 siblings, 0 replies; 4+ messages in thread
From: Weiming Shi @ 2026-06-08  9:58 UTC (permalink / raw)
  To: Qu Wenruo; +Cc: linux-btrfs, dsterba, josef, clm, xmei5

On 26-06-08 07:51, Qu Wenruo wrote:
> 
> 
> 在 2026/6/7 21:44, Weiming Shi 写道:
> > btrfs_get_name() reads the name length straight from the on-disk
> > inode_ref (or root_ref) and copies that many bytes into the caller's
> > buffer with no upper bound. The caller (exportfs_get_name()) supplies a
> > fixed NAME_MAX + 1 byte stack buffer, but name_len is a __le16 read from
> > the leaf and the tree-checker only bounds it to the item size, not to
> > BTRFS_NAME_LEN. A crafted leaf with name_len = 4096 therefore overflows
> > the 256-byte buffer with attacker-controlled bytes. It is reachable from
> > a mounted untrusted btrfs image via open_by_handle_at(), and on btrfs
> > filesystems exported over NFS.
> > 
> >   BUG: KASAN: stack-out-of-bounds in read_extent_buffer (fs/btrfs/extent_io.c:3742)
> >   Write of size 633 at addr ffffc90006c9fc40 by task exploit/5192
> >    read_extent_buffer (fs/btrfs/extent_io.c:3742)
> >    btrfs_get_name (fs/btrfs/export.c:289)
> >    reconnect_path (fs/exportfs/expfs.c:222)
> >    exportfs_decode_fh_raw (fs/exportfs/expfs.c:473)
> >    do_handle_open (fs/fhandle.c:230)
> >    do_syscall_64 (arch/x86/entry/syscall_64.c:94)
> >   Kernel panic - not syncing: stack-protector: Kernel stack is corrupted
> > 
> > Reject any name_len greater than BTRFS_NAME_LEN before the copy. Such a
> > name is never valid on disk, so this only rejects corrupted leaves and
> > leaves valid names unchanged.
> > 
> > Fixes: 2ede0daf0154 ("Btrfs: handle NFS lookups properly")
> > Reported-by: Xiang Mei <xmei5@asu.edu>
> > Assisted-by: Claude:claude-opus-4-8
> > Signed-off-by: Weiming Shi <bestswngs@gmail.com>
> > ---
> >   fs/btrfs/export.c | 10 ++++++++++
> >   1 file changed, 10 insertions(+)
> > 
> > diff --git a/fs/btrfs/export.c b/fs/btrfs/export.c
> > index c403117ac..a54c6e8b3 100644
> > --- a/fs/btrfs/export.c
> > +++ b/fs/btrfs/export.c
> > @@ -285,6 +285,16 @@ static int btrfs_get_name(struct dentry *parent, char *name,
> >   		name_len = btrfs_inode_ref_name_len(leaf, iref);
> >   	}
> > +	/* The caller's buffer is only NAME_MAX + 1 bytes. */
> > +	if (name_len > BTRFS_NAME_LEN) {
> 
> We do not play the whac-a-mole game by add random checks ad-hoc.
> 
> Do the proper ROOT_REF_KEY and INODE_REF_KEY verification inside
> tree-checker.
> 
> > +		btrfs_err(fs_info,
> > +			  "corrupt name length %d for inode %llu in root %llu, max %d",
> > +			  name_len, btrfs_ino(BTRFS_I(inode)),
> > +			  btrfs_root_id(BTRFS_I(inode)->root), BTRFS_NAME_LEN);
> > +		btrfs_free_path(path);
> > +		return -EUCLEAN;
> > +	}
> > +
> >   	read_extent_buffer(leaf, name, name_ptr, name_len);
> >   	btrfs_free_path(path);
> 

Thanks for the review. v2 sent.


^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2026-06-08  9:58 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-07 12:14 [PATCH] btrfs: reject names longer than BTRFS_NAME_LEN in btrfs_get_name() Weiming Shi
2026-06-07 20:23 ` Miquel Sabaté Solà
2026-06-07 22:21 ` Qu Wenruo
2026-06-08  9:58   ` Weiming Shi

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox