[PATCH v2 3/3] ext4: Add a few overflow checks in the writing code

Tom Rini trini at konsulko.com
Fri Apr 18 15:47:59 CEST 2025


On Fri, Apr 18, 2025 at 04:59:15AM -0600, Simon Glass wrote:

> From: Simon Glass <simon.glass at canonical.com>
> 
> Some memory allocations make use of data from the disk, so add some
> overflow checks.
> 
> Adjust LOG2_BLOCK_SIZE() so it is easier to read.
> 
> Signed-off-by: Simon Glass <simon.glass at canonical.com>
> ---
> 
> Changes in v2:
> - Use Linux macros instead of gcc built-ins
> 
>  fs/ext4/ext4_write.c | 25 +++++++++++++++++++++----
>  include/ext_common.h |  3 +--
>  2 files changed, 22 insertions(+), 6 deletions(-)

There's a lot going on here, which makes review harder.

> diff --git a/fs/ext4/ext4_write.c b/fs/ext4/ext4_write.c
> index d109ed6e90d..a9a53214dce 100644
> --- a/fs/ext4/ext4_write.c
> +++ b/fs/ext4/ext4_write.c
> @@ -25,6 +25,7 @@
>  #include <malloc.h>
>  #include <memalign.h>
>  #include <part.h>
> +#include <linux/overflow.h>
>  #include <linux/stat.h>
>  #include <div64.h>
>  #include "ext4_common.h"
> @@ -108,8 +109,15 @@ int ext4fs_get_bgdtable(void)
>  {
>  	int status;
>  	struct ext_filesystem *fs = get_fs();
> -	int gdsize_total = ROUND(fs->no_blkgrp * fs->gdsize, fs->blksz);
> +	size_t alloc_size;
> +	int gdsize_total;
> +
> +	if (check_mul_overflow(fs->no_blkgrp, fs->gdsize, &alloc_size))
> +		return -1;
> +	gdsize_total = ROUND(alloc_size, fs->blksz);

This is equivalent, yes.

>  	fs->no_blk_pergdt = gdsize_total / fs->blksz;
> +	if (!fs->no_blk_pergdt)
> +		return -1;

I don't know if that can ever happen but it's not unreasonable given
thee class of vulnerabilities that are "make up a specially corrupt
image", so this is good.

>  	/* allocate memory for gdtable */
>  	fs->gdtable = zalloc(gdsize_total);
> @@ -117,7 +125,7 @@ int ext4fs_get_bgdtable(void)
>  		return -ENOMEM;
>  	/* read the group descriptor table */
>  	status = ext4fs_devread((lbaint_t)fs->gdtable_blkno * fs->sect_perblk,
> -				0, fs->blksz * fs->no_blk_pergdt, fs->gdtable);
> +				0, gdsize_total, fs->gdtable);

Is that equivalent?

>  	if (status == 0)
>  		goto fail;
>  
> @@ -599,10 +607,17 @@ int ext4fs_init(void)
>  	int i;
>  	uint32_t real_free_blocks = 0;
>  	struct ext_filesystem *fs = get_fs();
> +	size_t alloc_size;
> +
> +	/* check for a reasonable block size, no more than 64K */
> +	if (LOG2_BLOCK_SIZE(ext4fs_root) > 16)
> +		goto fail;

Reasonable for the same reason as above, but not related to overflow.

>  	/* populate fs */
>  	fs->blksz = EXT2_BLOCK_SIZE(ext4fs_root);
>  	fs->sect_perblk = fs->blksz >> fs->dev_desc->log2blksz;
> +	if (!fs->sect_perblk)
> +		goto fail;

Same.

>  
>  	/* get the superblock */
>  	fs->sb = zalloc(SUPERBLOCK_SIZE);
> @@ -629,7 +644,9 @@ int ext4fs_init(void)
>  	}
>  
>  	/* load all the available bitmap block of the partition */
> -	fs->blk_bmaps = zalloc(fs->no_blkgrp * sizeof(char *));
> +	if (check_mul_overflow(fs->no_blkgrp, sizeof(char *), &alloc_size))
> +		goto fail;
> +	fs->blk_bmaps = zalloc(alloc_size);

Equivalent.

>  	if (!fs->blk_bmaps)
>  		goto fail;
>  	for (i = 0; i < fs->no_blkgrp; i++) {
> @@ -649,7 +666,7 @@ int ext4fs_init(void)
>  	}
>  
>  	/* load all the available inode bitmap of the partition */
> -	fs->inode_bmaps = zalloc(fs->no_blkgrp * sizeof(unsigned char *));
> +	fs->inode_bmaps = zalloc(alloc_size);

I'm going to assume that yes, really, there's no case where
sizeof(unsigned char *) != sizeof(char *) so this is equivalent.

>  	if (!fs->inode_bmaps)
>  		goto fail;
>  	for (i = 0; i < fs->no_blkgrp; i++) {
> diff --git a/include/ext_common.h b/include/ext_common.h
> index 6e17fbd2771..35d3a1844eb 100644
> --- a/include/ext_common.h
> +++ b/include/ext_common.h
> @@ -67,8 +67,7 @@ struct cmd_tbl;
>  #define EXT2_BLOCK_SIZE(data)	   (1 << LOG2_BLOCK_SIZE(data))
>  
>  /* Log2 size of ext2 block in bytes.  */
> -#define LOG2_BLOCK_SIZE(data)	   (le32_to_cpu		   \
> -				    (data->sblock.log2_block_size) \
> +#define LOG2_BLOCK_SIZE(data)	(le32_to_cpu((data)->sblock.log2_block_size) \
>  				    + EXT2_MIN_BLOCK_LOG_SIZE)
>  
>  #define EXT2_FT_DIR	2

That is indeed an odd place to enforce 80 character width over
readability.

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 659 bytes
Desc: not available
URL: <https://lists.denx.de/pipermail/u-boot/attachments/20250418/6d142395/attachment.sig>


More information about the U-Boot mailing list