[PATCH 2/3] fix bitmap byte size calculations

Josh Hunt <[email protected]> Thu, 30 Jul 2026 20:37:00 -0700
Newsgroups org.kernel.vger.linux-ext4
Message-ID <[email protected]>
From: Kit Knox <[email protected]>

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.

Example: With s_clusters_per_group = blocksize*8 + 1, the buffer is
undersized by 1 byte, causing heap corruption when the bitmap is copied.

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(-)

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 = 0;
 	char *actual_buf, *bitmap_buf;
 
-	actual_buf = (char *) e2fsck_allocate_memory(ctx, fs->blocksize,
-						     "actual bitmap buffer");
-	bitmap_buf = (char *) e2fsck_allocate_memory(ctx, fs->blocksize,
-						     "bitmap block buffer");
+	actual_buf = (char *) e2fsck_allocate_memory(ctx,
+		ext2fs_div_ceil(fs->super->s_clusters_per_group, 8),
+		"actual bitmap buffer");
+	bitmap_buf = (char *) e2fsck_allocate_memory(ctx,
+		ext2fs_div_ceil(fs->super->s_clusters_per_group, 8),
+		"bitmap block buffer");
 
 	clear_problem_context(&pctx);
 	free_array = (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)
 
 	inode_nbytes = block_nbytes = 0;
 	if (do_block) {
-		block_nbytes = EXT2_CLUSTERS_PER_GROUP(fs->super) / 8;
+		block_nbytes = ext2fs_div_ceil(EXT2_CLUSTERS_PER_GROUP(fs->super), 8);
 		retval = io_channel_alloc_buf(fs->io, 0, &block_buf);
 		if (retval)
 			goto errout;
 		memset(block_buf, 0xff, fs->blocksize);
 	}
 	if (do_inode) {
-		inode_nbytes = (size_t)
-			((EXT2_INODES_PER_GROUP(fs->super)+7) / 8);
+		inode_nbytes = ext2fs_div_ceil(EXT2_INODES_PER_GROUP(fs->super), 8);
 		retval = 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 = EXT2_CLUSTERS_PER_GROUP(fs->super) / 8;
-	int inode_nbytes = EXT2_INODES_PER_GROUP(fs->super) / 8;
+	int block_nbytes = ext2fs_div_ceil(EXT2_CLUSTERS_PER_GROUP(fs->super), 8);
+	int inode_nbytes = ext2fs_div_ceil(EXT2_INODES_PER_GROUP(fs->super), 8);
 	char *buf;
 
 	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 = 0, *inode_bitmap = 0;
 	errcode_t retval = 0;
-	int block_nbytes = EXT2_CLUSTERS_PER_GROUP(fs->super) / 8;
-	int inode_nbytes = EXT2_INODES_PER_GROUP(fs->super) / 8;
+	int block_nbytes = ext2fs_div_ceil(EXT2_CLUSTERS_PER_GROUP(fs->super), 8);
+	int inode_nbytes = 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 = _("clusters");
 
-	block_nbytes = EXT2_CLUSTERS_PER_GROUP(fs->super) / 8;
-	inode_nbytes = EXT2_INODES_PER_GROUP(fs->super) / 8;
+	block_nbytes = ext2fs_div_ceil(EXT2_CLUSTERS_PER_GROUP(fs->super), 8);
+	inode_nbytes = ext2fs_div_ceil(EXT2_INODES_PER_GROUP(fs->super), 8);
 
 	if (fs->block_map)
 		block_bitmap = 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,
 
 	ea_magic = (__u32 *)((char *)inode + EXT2_GOOD_OLD_INODE_SIZE +
 				inode->i_extra_isize);
+
 	if (*ea_magic != EXT2_EXT_ATTR_MAGIC)
 		return 0;
 
@@ -2950,7 +2951,7 @@ static errcode_t resize2fs_calculate_summary_stats(ext2_filsys fs)
 	/*
 	 * First calculate the block statistics
 	 */
-	bitmap_buf = malloc(fs->blocksize);
+	bitmap_buf = malloc(ext2fs_div_ceil(fs->super->s_clusters_per_group, 8));
 	if (!bitmap_buf)
 		return ENOMEM;
 	for (group = 0; group < fs->group_desc_count; group++) {
-- 
2.34.1