Re: [PATCH v2 07/12] ext4: Fix out-of-bounds read in ext4_get_group_info()
From: Zhang Yi
Date: Tue Sep 01 2026 - 02:45:41 EST
On 9/1/2026 10:42 AM, Jinjie Ruan wrote:
> A plain read of s_groups_count in ext4_get_group_info() allows CPU
> load-load reordering. On weak memory models, speculative prefetch of
> s_group_info prior to the boundary check could lead to an out-of-bounds
> read if a concurrent online resize expands the array and increments
> s_groups_count.
>
> The data race occurs between the ioctl configuration path (holding the
> resize lock via ext4_resize_begin) and the lockless metadata lookup path:
>
> CPU 0 (Writer, Resize Lock) CPU 1 (Reader, Lockless)
> --------------------------- ------------------------
> ext4_ioctl()
> [EXT4_IOC_GROUP_ADD]
> ext4_ioctl_group_add()
> ext4_resize_begin() // Takes lock
> ext4_group_add()
> ext4_mb_alloc_groupinfo()
> // Publishes expanded array via RCU
> rcu_assign_pointer(s_group_info, ...)
>
> ext4_flex_group_add()
> ext4_update_super()
> ext4_get_group_info()
> // Speculative / out-of-order read
> [Loads old/smaller s_group_info pointer]
> [Plain C store / smp_wmb()]
> sbi->s_groups_count += ...;
> // Reads new s_groups_count,
> // boundary check passes
> if (group >= s_groups_count)
>
> // Out-of-bounds array access!
> sbi_array_rcu_deref(..., s_group_info)
>
> Fix this by using ext4_get_groups_count() to enforce acquire semantics.
>
> Cc: stable@xxxxxxxxxxxxxxx
> Cc: "Theodore Ts'o" <tytso@xxxxxxx>
> Cc: Andreas Dilger <adilger.kernel@xxxxxxxxx>
> Cc: Baokun Li <libaokun@xxxxxxxxxxxxxxxxx>
> Cc: Jan Kara <jack@xxxxxxx>
> Cc: Ojaswin Mujoo <ojaswin@xxxxxxxxxxxxx>
> Cc: "Ritesh Harjani (IBM)" <ritesh.list@xxxxxxxxx>
> Cc: Zhang Yi <yi.zhang@xxxxxxxxxx>
> Fixes: 5354b2af3406 ("ext4: allow ext4_get_group_info() to fail")
> Link: https://sashiko.dev/#/patchset/20260825095422.3166067-1-ruanjinjie%40huawei.com
> Signed-off-by: Jinjie Ruan <ruanjinjie@xxxxxxxxxx>
Looks good to me.
Reviewed-by: Zhang Yi <yi.zhang@xxxxxxxxxx>
> ---
> fs/ext4/balloc.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c
> index 52f4c5169f91..778fe8788f06 100644
> --- a/fs/ext4/balloc.c
> +++ b/fs/ext4/balloc.c
> @@ -329,7 +329,7 @@ struct ext4_group_info *ext4_get_group_info(struct super_block *sb,
> struct ext4_group_info **grp_info;
> long indexv, indexh;
>
> - if (unlikely(group >= EXT4_SB(sb)->s_groups_count))
> + if (unlikely(group >= ext4_get_groups_count(sb)))
> return NULL;
> if (unlikely(!EXT4_SB(sb)->s_group_info))
> return NULL;