Re: [PATCH 2/3] fix bitmap byte size calculations
Andreas Dilger <[email protected]> Fri, 31 Jul 2026 02:57:48 -0600
| Newsgroups | org.kernel.vger.linux-ext4 |
|---|---|
| Message-ID | <[email protected]> |
On Jul 30, 2026, at 21:37, Josh Hunt <[email protected]> wrote: >=20 > From: Kit Knox <[email protected]> >=20 > The bitmap byte size calculations use integer division (count / 8) = without > rounding up. When clusters_per_group or inodes_per_group is not a = multiple > of 8, this allocates too few bytes. The bitmap backends copy (num + = 7) / 8 > bytes via ext2fs_get_block_bitmap_range2(), causing a buffer overrun = of 1-7 > bytes. Is it ever legal to have clusters_per_group or inodes_per_group in a = filesystem? Is this something you've seen in real life or is this a fuzzed = filesystem image? It would probably be better to refuse processing such a filesystem = entirely, since it is more likely that the superblock is corrupt and a backup superblock = should be used instead? Testing mke2fs it doesn't appear to allow a non-multiple-of-8 value for = blocks_per_group: $ mke2fs -N 77 -g 77 /tmp/tt mke2fs: blocks per group must be multiple of 8 and while the inode count is specified as an odd number, it is = internally rounded to a multiple of 8 per group: $ mke2fs -N 77 -g 800 /tmp/tt mke2fs 1.47.3-wc2 (11-Nov-2025) : Creating filesystem with 262144 4k blocks and 5248 inodes Superblock backups stored on blocks: 2400, 194400 : $ dumpe2fs -h /tmp/tt | grep -i group dumpe2fs 1.47.3-wc2 (11-Nov-2025) Blocks per group: 800 Fragments per group: 800 Inodes per group: 16 Inode blocks per group: 1 even with 4KiB inode size (one inode per block) the number of inodes is a multiple of 8: $ mke2fs -N 77 -I 4096 /tmp/tt mke2fs 1.47.3-wc2 (11-Nov-2025) : Creating filesystem with 262144 4k blocks and 64 inodes : $ dumpe2fs -h /tmp/tt | grep -i group dumpe2fs 1.47.3-wc2 (11-Nov-2025) Blocks per group: 32768 Fragments per group: 32768 Inodes per group: 8 Inode blocks per group: 8 Cheers, Andreas >=20 > Example: With s_clusters_per_group =3D blocksize*8 + 1, the buffer is > undersized by 1 byte, causing heap corruption when the bitmap is = copied. >=20 > Signed-off-by: Kit Knox <[email protected]> > --- > e2fsck/pass5.c | 10 ++++++---- > lib/ext2fs/rw_bitmaps.c | 13 ++++++------- > misc/dumpe2fs.c | 4 ++-- > resize/resize2fs.c | 3 ++- > 4 files changed, 16 insertions(+), 14 deletions(-) >=20 > diff --git a/e2fsck/pass5.c b/e2fsck/pass5.c > index c1d45a5f..aad2e76a 100644 > --- a/e2fsck/pass5.c > +++ b/e2fsck/pass5.c > @@ -324,10 +324,12 @@ static void check_block_bitmaps(e2fsck_t ctx) > int redo_flag =3D 0; > char *actual_buf, *bitmap_buf; >=20 > - actual_buf =3D (char *) e2fsck_allocate_memory(ctx, fs->blocksize, > - "actual bitmap buffer"); > - bitmap_buf =3D (char *) e2fsck_allocate_memory(ctx, fs->blocksize, > - "bitmap block buffer"); > + actual_buf =3D (char *) e2fsck_allocate_memory(ctx, > + ext2fs_div_ceil(fs->super->s_clusters_per_group, 8), > + "actual bitmap buffer"); > + bitmap_buf =3D (char *) e2fsck_allocate_memory(ctx, > + ext2fs_div_ceil(fs->super->s_clusters_per_group, 8), > + "bitmap block buffer"); >=20 > clear_problem_context(&pctx); > free_array =3D (unsigned int *) e2fsck_allocate_memory(ctx, > diff --git a/lib/ext2fs/rw_bitmaps.c b/lib/ext2fs/rw_bitmaps.c > index 1da75e4a..211d9ec4 100644 > --- a/lib/ext2fs/rw_bitmaps.c > +++ b/lib/ext2fs/rw_bitmaps.c > @@ -72,15 +72,14 @@ static errcode_t write_bitmaps(ext2_filsys fs, int = do_inode, int do_block) >=20 > inode_nbytes =3D block_nbytes =3D 0; > if (do_block) { > - block_nbytes =3D EXT2_CLUSTERS_PER_GROUP(fs->super) / 8; > + block_nbytes =3D ext2fs_div_ceil(EXT2_CLUSTERS_PER_GROUP(fs->super), = 8); > retval =3D io_channel_alloc_buf(fs->io, 0, &block_buf); > if (retval) > goto errout; > memset(block_buf, 0xff, fs->blocksize); > } > if (do_inode) { > - inode_nbytes =3D (size_t) > - ((EXT2_INODES_PER_GROUP(fs->super)+7) / 8); > + inode_nbytes =3D ext2fs_div_ceil(EXT2_INODES_PER_GROUP(fs->super), = 8); > retval =3D io_channel_alloc_buf(fs->io, 0, &inode_buf); > if (retval) > goto errout; > @@ -230,8 +229,8 @@ static int bitmap_tail_verify(unsigned char = *bitmap, int first, int last) > static errcode_t read_bitmaps_range_prepare(ext2_filsys fs, int flags) > { > errcode_t retval; > - int block_nbytes =3D EXT2_CLUSTERS_PER_GROUP(fs->super) / 8; > - int inode_nbytes =3D EXT2_INODES_PER_GROUP(fs->super) / 8; > + int block_nbytes =3D = ext2fs_div_ceil(EXT2_CLUSTERS_PER_GROUP(fs->super), 8); > + int inode_nbytes =3D = ext2fs_div_ceil(EXT2_INODES_PER_GROUP(fs->super), 8); > char *buf; >=20 > EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); > @@ -289,8 +288,8 @@ static errcode_t = read_bitmaps_range_start(ext2_filsys fs, int flags, > dgrp_t i; > char *block_bitmap =3D 0, *inode_bitmap =3D 0; > errcode_t retval =3D 0; > - int block_nbytes =3D EXT2_CLUSTERS_PER_GROUP(fs->super) / 8; > - int inode_nbytes =3D EXT2_INODES_PER_GROUP(fs->super) / 8; > + int block_nbytes =3D = ext2fs_div_ceil(EXT2_CLUSTERS_PER_GROUP(fs->super), 8); > + int inode_nbytes =3D = ext2fs_div_ceil(EXT2_INODES_PER_GROUP(fs->super), 8); > int csum_flag; > unsigned int cnt; > blk64_t blk; > diff --git a/misc/dumpe2fs.c b/misc/dumpe2fs.c > index b56d15d9..2c45d6bb 100644 > --- a/misc/dumpe2fs.c > +++ b/misc/dumpe2fs.c > @@ -168,8 +168,8 @@ static void list_desc(ext2_filsys fs, int = grp_only) > if (ext2fs_has_feature_bigalloc(fs->super)) > units =3D _("clusters"); >=20 > - block_nbytes =3D EXT2_CLUSTERS_PER_GROUP(fs->super) / 8; > - inode_nbytes =3D EXT2_INODES_PER_GROUP(fs->super) / 8; > + block_nbytes =3D ext2fs_div_ceil(EXT2_CLUSTERS_PER_GROUP(fs->super), = 8); > + inode_nbytes =3D ext2fs_div_ceil(EXT2_INODES_PER_GROUP(fs->super), = 8); >=20 > if (fs->block_map) > block_bitmap =3D malloc(block_nbytes); > diff --git a/resize/resize2fs.c b/resize/resize2fs.c > index dfefca1d..ad092244 100644 > --- a/resize/resize2fs.c > +++ b/resize/resize2fs.c > @@ -2088,6 +2088,7 @@ static int fix_ea_ibody_entries(ext2_extent = imap, >=20 > ea_magic =3D (__u32 *)((char *)inode + EXT2_GOOD_OLD_INODE_SIZE + > inode->i_extra_isize); > + > if (*ea_magic !=3D EXT2_EXT_ATTR_MAGIC) > return 0; >=20 > @@ -2950,7 +2951,7 @@ static errcode_t = resize2fs_calculate_summary_stats(ext2_filsys fs) > /* > * First calculate the block statistics > */ > - bitmap_buf =3D malloc(fs->blocksize); > + bitmap_buf =3D = malloc(ext2fs_div_ceil(fs->super->s_clusters_per_group, 8)); > if (!bitmap_buf) > return ENOMEM; > for (group =3D 0; group < fs->group_desc_count; group++) { > --=20 > 2.34.1 >=20 >=20 Cheers, Andreas