* [PATCH] fs: btrfs: fix btrfs_ioctl_space_info() slot_count TOCTOU which can lead to info-leak
@ 2026-03-22 6:39 Yochai Eisenrich
2026-03-23 14:26 ` David Sterba
2026-03-23 22:34 ` [PATCH] fs: btrfs: fix btrfs_ioctl_space_info() slot_count Teng Liu
0 siblings, 2 replies; 5+ messages in thread
From: Yochai Eisenrich @ 2026-03-22 6:39 UTC (permalink / raw)
To: Chris Mason
Cc: Yochai Eisenrich, David Sterba, security, linux-btrfs,
Yochai Eisenrich
From: Yochai Eisenrich <yochaie@sweet.security>
btrfs_ioctl_space_info() has a TOCTOU race between two passes over the
block group RAID type lists. The first pass counts entries to determine
the allocation size, then the second pass fills the buffer. The
groups_sem rwlock is released between passes, allowing concurrent block
group removal to reduce the entry count.
When the second pass fills fewer entries than the first pass counted,
copy_to_user() copies the full alloc_size bytes including trailing
uninitialized kmalloc bytes to userspace.
Fix by copying only total_spaces entries (the actually-filled count from
the second pass) instead of alloc_size bytes, and switch to kzalloc so
any future copy size mismatch cannot leak heap data.
Fixes: 7fde62bffb57 ("Btrfs: buffer results in the space_info ioctl")
Signed-off-by: Yochai Eisenrich <echelonh@gmail.com>
---
fs/btrfs/ioctl.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index d75d31b606e4..93c5ea91f401 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -2897,7 +2897,7 @@ static long btrfs_ioctl_space_info(struct btrfs_fs_info *fs_info,
return -ENOMEM;
space_args.total_spaces = 0;
- dest = kmalloc(alloc_size, GFP_KERNEL);
+ dest = kzalloc(alloc_size, GFP_KERNEL);
if (!dest)
return -ENOMEM;
dest_orig = dest;
@@ -2953,7 +2953,8 @@ static long btrfs_ioctl_space_info(struct btrfs_fs_info *fs_info,
user_dest = (struct btrfs_ioctl_space_info __user *)
(arg + sizeof(struct btrfs_ioctl_space_args));
- if (copy_to_user(user_dest, dest_orig, alloc_size))
+ if (copy_to_user(user_dest, dest_orig,
+ space_args.total_spaces * sizeof(*dest_orig)))
return -EFAULT;
out:
--
2.53.0
^ permalink raw reply related [flat|nested] 5+ messages in thread* Re: [PATCH] fs: btrfs: fix btrfs_ioctl_space_info() slot_count TOCTOU which can lead to info-leak
2026-03-22 6:39 [PATCH] fs: btrfs: fix btrfs_ioctl_space_info() slot_count TOCTOU which can lead to info-leak Yochai Eisenrich
@ 2026-03-23 14:26 ` David Sterba
2026-03-23 15:03 ` Yochai E
2026-03-23 22:34 ` [PATCH] fs: btrfs: fix btrfs_ioctl_space_info() slot_count Teng Liu
1 sibling, 1 reply; 5+ messages in thread
From: David Sterba @ 2026-03-23 14:26 UTC (permalink / raw)
To: Yochai Eisenrich
Cc: Chris Mason, Yochai Eisenrich, David Sterba, security,
linux-btrfs
On Sun, Mar 22, 2026 at 08:39:35AM +0200, Yochai Eisenrich wrote:
> From: Yochai Eisenrich <yochaie@sweet.security>
>
> btrfs_ioctl_space_info() has a TOCTOU race between two passes over the
> block group RAID type lists. The first pass counts entries to determine
> the allocation size, then the second pass fills the buffer. The
> groups_sem rwlock is released between passes, allowing concurrent block
> group removal to reduce the entry count.
>
> When the second pass fills fewer entries than the first pass counted,
> copy_to_user() copies the full alloc_size bytes including trailing
> uninitialized kmalloc bytes to userspace.
This sounds correct.
> Fix by copying only total_spaces entries (the actually-filled count from
> the second pass) instead of alloc_size bytes, and switch to kzalloc so
> any future copy size mismatch cannot leak heap data.
Trying to hit this race looks very hard though, reducing number of block
group types is quite rare.
The change to kzalloc looks like best fix, for all ioctls that are
exposed to userspace. Copying the exact number makes sense. The other
case (copying too much) has been fixed in 51788b1bdd0d68 ("btrfs:
prevent heap corruption in btrfs_ioctl_space_info()").
>
> Fixes: 7fde62bffb57 ("Btrfs: buffer results in the space_info ioctl")
>
> Signed-off-by: Yochai Eisenrich <echelonh@gmail.com>
Added to for-next, thanks.
^ permalink raw reply [flat|nested] 5+ messages in thread* Re: [PATCH] fs: btrfs: fix btrfs_ioctl_space_info() slot_count TOCTOU which can lead to info-leak
2026-03-23 14:26 ` David Sterba
@ 2026-03-23 15:03 ` Yochai E
2026-03-23 18:54 ` David Sterba
0 siblings, 1 reply; 5+ messages in thread
From: Yochai E @ 2026-03-23 15:03 UTC (permalink / raw)
To: dsterba; +Cc: Chris Mason, Yochai Eisenrich, David Sterba, security,
linux-btrfs
On Mon, Mar 23, 2026 at 4:26 PM David Sterba <dsterba@suse.cz> wrote:
>
> On Sun, Mar 22, 2026 at 08:39:35AM +0200, Yochai Eisenrich wrote:
> > From: Yochai Eisenrich <yochaie@sweet.security>
> >
> > btrfs_ioctl_space_info() has a TOCTOU race between two passes over the
> > block group RAID type lists. The first pass counts entries to determine
> > the allocation size, then the second pass fills the buffer. The
> > groups_sem rwlock is released between passes, allowing concurrent block
> > group removal to reduce the entry count.
> >
> > When the second pass fills fewer entries than the first pass counted,
> > copy_to_user() copies the full alloc_size bytes including trailing
> > uninitialized kmalloc bytes to userspace.
>
> This sounds correct.
>
> > Fix by copying only total_spaces entries (the actually-filled count from
> > the second pass) instead of alloc_size bytes, and switch to kzalloc so
> > any future copy size mismatch cannot leak heap data.
>
> Trying to hit this race looks very hard though, reducing number of block
> group types is quite rare.
I agree that this may not be your btrfs typical behavior, but I wouldn't
have raised the issue if I wasn't able to prove it. I can send the PoC
code your way if you're interested - it leaks kernel data. A malicious
user can utilize a fresh btrfs disk over e.g. zram to trigger the issue.
> The change to kzalloc looks like best fix, for all ioctls that are
> exposed to userspace. Copying the exact number makes sense. The other
> case (copying too much) has been fixed in 51788b1bdd0d68 ("btrfs:
> prevent heap corruption in btrfs_ioctl_space_info()").
Just to make sure we're on the same page:
1. Following the above, do you approve of the copy_to_user fix I
suggested?
2. I think it makes sense to treat other ioctl kmallocs in a different
patch, no?
> >
> > Fixes: 7fde62bffb57 ("Btrfs: buffer results in the space_info ioctl")
> >
> > Signed-off-by: Yochai Eisenrich <echelonh@gmail.com>
>
> Added to for-next, thanks.
^ permalink raw reply [flat|nested] 5+ messages in thread* Re: [PATCH] fs: btrfs: fix btrfs_ioctl_space_info() slot_count TOCTOU which can lead to info-leak
2026-03-23 15:03 ` Yochai E
@ 2026-03-23 18:54 ` David Sterba
0 siblings, 0 replies; 5+ messages in thread
From: David Sterba @ 2026-03-23 18:54 UTC (permalink / raw)
To: Yochai E
Cc: dsterba, Chris Mason, Yochai Eisenrich, David Sterba, security,
linux-btrfs
On Mon, Mar 23, 2026 at 05:03:47PM +0200, Yochai E wrote:
> On Mon, Mar 23, 2026 at 4:26 PM David Sterba <dsterba@suse.cz> wrote:
> >
> > On Sun, Mar 22, 2026 at 08:39:35AM +0200, Yochai Eisenrich wrote:
> > > From: Yochai Eisenrich <yochaie@sweet.security>
> > >
> > > btrfs_ioctl_space_info() has a TOCTOU race between two passes over the
> > > block group RAID type lists. The first pass counts entries to determine
> > > the allocation size, then the second pass fills the buffer. The
> > > groups_sem rwlock is released between passes, allowing concurrent block
> > > group removal to reduce the entry count.
> > >
> > > When the second pass fills fewer entries than the first pass counted,
> > > copy_to_user() copies the full alloc_size bytes including trailing
> > > uninitialized kmalloc bytes to userspace.
> >
> > This sounds correct.
> >
> > > Fix by copying only total_spaces entries (the actually-filled count from
> > > the second pass) instead of alloc_size bytes, and switch to kzalloc so
> > > any future copy size mismatch cannot leak heap data.
> >
> > Trying to hit this race looks very hard though, reducing number of block
> > group types is quite rare.
>
> I agree that this may not be your btrfs typical behavior, but I wouldn't
> have raised the issue if I wasn't able to prove it. I can send the PoC
> code your way if you're interested - it leaks kernel data. A malicious
> user can utilize a fresh btrfs disk over e.g. zram to trigger the issue.
I believe you, the pattern for leaking data works, I'd apply the fix
even without a PoC. Using zeroing allocations in ioctls should be used
by default, this one was missing it.
For a user to trigger that I don't see how this can be well timed with
just passively check the space info ioctl ("btrfs fi df") when the
administrator runs the rebalance command and the block group number
decreases. Like on an installed system it takes the defaults and stays
like that forever.
Active user would have to be able to mkfs an image (trivial) and have it
mounted (possible), which on itself opens a lot of other options.
FS_USERNS_MOUNT is usually not enabled for that reason.
> > The change to kzalloc looks like best fix, for all ioctls that are
> > exposed to userspace. Copying the exact number makes sense. The other
> > case (copying too much) has been fixed in 51788b1bdd0d68 ("btrfs:
> > prevent heap corruption in btrfs_ioctl_space_info()").
>
> Just to make sure we're on the same page:
> 1. Following the above, do you approve of the copy_to_user fix I
> suggested?
Yeah it's ok. For normal case there's no difference, the user side will
read up to args.total_spaces which matches the valid data, and ignore the
empty slot. Attacker will find zeros there.
> 2. I think it makes sense to treat other ioctl kmallocs in a different
> patch, no?
Yes, one thing per patch. I was mentioning that as further work as it's
good to look for the similar problems in other code.
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] fs: btrfs: fix btrfs_ioctl_space_info() slot_count
2026-03-22 6:39 [PATCH] fs: btrfs: fix btrfs_ioctl_space_info() slot_count TOCTOU which can lead to info-leak Yochai Eisenrich
2026-03-23 14:26 ` David Sterba
@ 2026-03-23 22:34 ` Teng Liu
1 sibling, 0 replies; 5+ messages in thread
From: Teng Liu @ 2026-03-23 22:34 UTC (permalink / raw)
To: echelonh; +Cc: linux-btrfs, Teng Liu
Applied and tested on v7.0-rc4 in a QEMU VM with btrfs as the root
filesystem.
Verified that BTRFS_IOC_SPACE_INFO (via btrfs fi usage) returns correct
results under normal operation and while running concurrent filesystem
activity (file creation/deletion in a loop).
No kernel warnings or errors observed in dmesg.
It's hard to create a race condition between 2 passes so didn't test whether
before-patch behaviour.
Tested-by: Teng Liu <27rabbitlt@gmail.com>
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-03-23 22:34 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-22 6:39 [PATCH] fs: btrfs: fix btrfs_ioctl_space_info() slot_count TOCTOU which can lead to info-leak Yochai Eisenrich
2026-03-23 14:26 ` David Sterba
2026-03-23 15:03 ` Yochai E
2026-03-23 18:54 ` David Sterba
2026-03-23 22:34 ` [PATCH] fs: btrfs: fix btrfs_ioctl_space_info() slot_count Teng Liu
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox