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

> From: Simon Glass <simon.gl...@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.gl...@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

Attachment: signature.asc
Description: PGP signature

Reply via email to