VYPR
Unrated severityNVD Advisory· Published May 28, 2026

CVE-2026-46159

CVE-2026-46159

Description

In the Linux kernel, the following vulnerability has been resolved:

btrfs: fix btrfs_ioctl_space_info() slot_count TOCTOU which can lead to info-leak

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.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

A TOCTOU race in btrfs_ioctl_space_info() allows uninitialized heap data to be leaked to userspace.

Vulnerability

A time-of-check-time-of-use (TOCTOU) race condition exists in the btrfs_ioctl_space_info() function in the Linux kernel's btrfs filesystem. The function performs two passes over the block group RAID type lists: the first pass counts entries to allocate a buffer, and the second pass fills the buffer. The groups_sem rwlock is released between passes, allowing a concurrent block group removal to reduce the entry count. When the second pass fills fewer entries than counted, copy_to_user() copies the full allocated size, including trailing uninitialized heap bytes, to userspace. This affects Linux kernel versions prior to the commit that fixes the issue.

Exploitation

An attacker must have the ability to call the BTRFS_IOC_SPACE_INFO ioctl on a btrfs filesystem (typically available to unprivileged users) and concurrently trigger block group removal (e.g., via btrfs device remove or balance operations). The race window is between the two passes of the ioctl handler. By repeatedly invoking the ioctl while simultaneously removing block groups, the attacker can cause the second pass to fill fewer entries than expected, resulting in the leak of uninitialized kernel heap memory.

Impact

Successful exploitation leads to an information leak of uninitialized kernel heap data to userspace. The leaked memory may contain sensitive information such as pointers, cryptographic keys, or other kernel objects. The attacker gains this information from an unprivileged position, potentially aiding further exploitation of the system.

Mitigation

The fix is included in Linux kernel commit d09d67d5de577cedae3de9497dff217e0ac8b641, which switches to kzalloc and copies only the actual number of filled entries. Users should update to a kernel version containing this commit. No workaround is available other than restricting access to the BTRFS_IOC_SPACE_INFO ioctl via security modules or system call filtering.

AI Insight generated on May 28, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected products

1

Patches

10
f5ee467b5676

btrfs: fix btrfs_ioctl_space_info() slot_count TOCTOU which can lead to info-leak

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.gitYochai EisenrichMay 15, 2026Fixed in 6.6.140via kernel-cna
1 file changed · +3 3
  • fs/btrfs/ioctl.c+3 3 modified
    diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
    index 4723013995f5bb..d17d1eff8eff4e 100644
    --- a/fs/btrfs/ioctl.c
    +++ b/fs/btrfs/ioctl.c
    @@ -3087,7 +3087,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;
    @@ -3143,7 +3143,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)))
     		ret = -EFAULT;
     
     	kfree(dest_orig);
    -- 
    cgit 1.3-korg
    
    
    
4fdc6ee08021

btrfs: fix btrfs_ioctl_space_info() slot_count TOCTOU which can lead to info-leak

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.gitYochai EisenrichMay 15, 2026Fixed in 6.12.90via kernel-cna
1 file changed · +3 3
  • fs/btrfs/ioctl.c+3 3 modified
    diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
    index 45852dbf9dfbc2..a61022182f45d3 100644
    --- a/fs/btrfs/ioctl.c
    +++ b/fs/btrfs/ioctl.c
    @@ -3113,7 +3113,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;
    @@ -3169,7 +3169,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)))
     		ret = -EFAULT;
     
     	kfree(dest_orig);
    -- 
    cgit 1.3-korg
    
    
    
5d12e0ab009a

btrfs: fix btrfs_ioctl_space_info() slot_count TOCTOU which can lead to info-leak

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.gitYochai EisenrichMay 15, 2026Fixed in 6.18.32via kernel-cna
1 file changed · +3 3
  • fs/btrfs/ioctl.c+3 3 modified
    diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
    index bfe253c2849a54..c0691e93e0a58a 100644
    --- a/fs/btrfs/ioctl.c
    +++ b/fs/btrfs/ioctl.c
    @@ -3025,7 +3025,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;
    @@ -3081,7 +3081,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)))
     		ret = -EFAULT;
     
     	kfree(dest_orig);
    -- 
    cgit 1.3-korg
    
    
    
d09d67d5de57

btrfs: fix btrfs_ioctl_space_info() slot_count TOCTOU which can lead to info-leak

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.gitYochai EisenrichMar 22, 2026Fixed in 7.0.7via kernel-cna
1 file changed · +3 3
  • fs/btrfs/ioctl.c+3 3 modified
    diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
    index d75d31b606e499..4a1d27e4884df0 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:
    -- 
    cgit 1.3-korg
    
    
    
973e57c726c1

btrfs: fix btrfs_ioctl_space_info() slot_count TOCTOU which can lead to info-leak

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.gitYochai EisenrichMar 22, 2026Fixed in 7.1-rc1via kernel-cna
1 file changed · +3 3
  • fs/btrfs/ioctl.c+3 3 modified
    diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
    index a4d715bbed57ba..b2e447f5005c16 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:
    -- 
    cgit 1.3-korg
    
    
    
f5ee467b5676

btrfs: fix btrfs_ioctl_space_info() slot_count TOCTOU which can lead to info-leak

1 file changed · +3 3
  • fs/btrfs/ioctl.c+3 3 modified
    diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
    index 4723013995f5bb..d17d1eff8eff4e 100644
    --- a/fs/btrfs/ioctl.c
    +++ b/fs/btrfs/ioctl.c
    @@ -3087,7 +3087,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;
    @@ -3143,7 +3143,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)))
     		ret = -EFAULT;
     
     	kfree(dest_orig);
    -- 
    cgit 1.3-korg
    
    
    
4fdc6ee08021

btrfs: fix btrfs_ioctl_space_info() slot_count TOCTOU which can lead to info-leak

1 file changed · +3 3
  • fs/btrfs/ioctl.c+3 3 modified
    diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
    index 45852dbf9dfbc2..a61022182f45d3 100644
    --- a/fs/btrfs/ioctl.c
    +++ b/fs/btrfs/ioctl.c
    @@ -3113,7 +3113,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;
    @@ -3169,7 +3169,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)))
     		ret = -EFAULT;
     
     	kfree(dest_orig);
    -- 
    cgit 1.3-korg
    
    
    
5d12e0ab009a

btrfs: fix btrfs_ioctl_space_info() slot_count TOCTOU which can lead to info-leak

1 file changed · +3 3
  • fs/btrfs/ioctl.c+3 3 modified
    diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
    index bfe253c2849a54..c0691e93e0a58a 100644
    --- a/fs/btrfs/ioctl.c
    +++ b/fs/btrfs/ioctl.c
    @@ -3025,7 +3025,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;
    @@ -3081,7 +3081,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)))
     		ret = -EFAULT;
     
     	kfree(dest_orig);
    -- 
    cgit 1.3-korg
    
    
    
d09d67d5de57

btrfs: fix btrfs_ioctl_space_info() slot_count TOCTOU which can lead to info-leak

1 file changed · +3 3
  • fs/btrfs/ioctl.c+3 3 modified
    diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
    index d75d31b606e499..4a1d27e4884df0 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:
    -- 
    cgit 1.3-korg
    
    
    
973e57c726c1

btrfs: fix btrfs_ioctl_space_info() slot_count TOCTOU which can lead to info-leak

1 file changed · +3 3
  • fs/btrfs/ioctl.c+3 3 modified
    diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
    index a4d715bbed57ba..b2e447f5005c16 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:
    -- 
    cgit 1.3-korg
    
    
    

Vulnerability mechanics

Synthesis attempt was rejected by the grounding validator. Re-run pending.

References

5

News mentions

0

No linked articles in our index yet.