Re: [PATCH 2/2] ufs: validate cylinder group metadata before caching it

Jan Kara <[email protected]> Mon, 3 Aug 2026 12:10:17 +0200
Newsgroups org.kernel.vger.linux-fsdevel,org.kernel.vger.linux-kernel,org.kernel.vger.stable
Message-ID <3zr3q6j73h6ttv3rib34rjeb3luxv3y3c7rovyqik5cp4dflf6@eif226wccquv>
On Sat 01-08-26 10:12:58, Ali Ahmet Memis wrote:
> ufs_read_cylinder() copies the cylinder group index and the rotor
> positions straight from the on-disk group and caches them without any
> check:
> 
> 	ucpi->c_cgx    = fs32_to_cpu(sb, ucg->cg_cgx);
> 	ucpi->c_rotor  = fs32_to_cpu(sb, ucg->cg_rotor);
> 	ucpi->c_frotor = fs32_to_cpu(sb, ucg->cg_frotor);
> 	ucpi->c_irotor = fs32_to_cpu(sb, ucg->cg_irotor);
> 
> They are then used as indices during allocation and free:
> 
>   - c_cgx indexes the cylinder summary array as
>     UFS_SB(sb)->fs_cs(ucpi->c_cgx), so a value past s_ncg writes a 32
>     bit count outside the s_csp allocation.
> 
>   - c_frotor becomes a bitmap scan start, start = c_frotor >> 3, and
>     then length = ((s_fpg + 7) >> 3) - start. A start beyond the block
>     bitmap wraps the unsigned length to a huge value, so ubh_scanc()
>     walks far past the cylinder group buffers. c_irotor drives the
>     inode bitmap the same way.
> 
> A crafted image can set any of these freely, turning an ordinary
> allocation into an out of bounds access.
> 
> Reject a cylinder group whose recorded index does not match the group
> being read, or whose rotors fall outside the group, before the metadata
> is cached. Valid filesystems keep cg_cgx equal to the group number and
> the rotors within the group, so only malformed images are rejected.
> 
> Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
> Cc: [email protected]
> Signed-off-by: Ali Ahmet Memis <[email protected]>

Looks good. Feel free to add:

Reviewed-by: Jan Kara <[email protected]>

								Honza

> ---
>  fs/ufs/cylinder.c | 10 ++++++++++
>  1 file changed, 10 insertions(+)
> 
> diff --git a/fs/ufs/cylinder.c b/fs/ufs/cylinder.c
> index a2813270c..b930ee1cf 100644
> --- a/fs/ufs/cylinder.c
> +++ b/fs/ufs/cylinder.c
> @@ -68,6 +68,16 @@ static bool ufs_read_cylinder(struct super_block *sb,
>  	ucpi->c_clustersumoff = fs32_to_cpu(sb, ucg->cg_u.cg_44.cg_clustersumoff);
>  	ucpi->c_clusteroff = fs32_to_cpu(sb, ucg->cg_u.cg_44.cg_clusteroff);
>  	ucpi->c_nclusterblks = fs32_to_cpu(sb, ucg->cg_u.cg_44.cg_nclusterblks);
> +
> +	/* these on-disk values become array and bitmap indices */
> +	if (ucpi->c_cgx != cgno ||
> +	    ucpi->c_rotor >= uspi->s_fpg ||
> +	    ucpi->c_frotor >= uspi->s_fpg ||
> +	    ucpi->c_irotor >= uspi->s_ipg) {
> +		ufs_error(sb, __func__,
> +			  "inconsistent metadata in cylinder group %u\n", cgno);
> +		goto failed;
> +	}
>  	UFSD("EXIT\n");
>  	return true;
>  	
> -- 
> 2.54.0
> 
-- 
Jan Kara <[email protected]>
SUSE Labs, CR