e2fsck, libext2fs: add checks for insanely large file systems
PATCH 1/1 e2fsck, libext2fs: add checks for insanely large file systems
If the blocks count field is too large, this can cause numberic overflows which can result in buffer overflows.
Addresses-Debian-Bug: #873757
Signed-off-by Theodore Ts'o <[email protected]>
Reported-by Jakub Wilk <[email protected]>
--- e2fsck/super.c | 31 +++++++++++++++++++++++++++++-- lib/ext2fs/openfs.c | 12 +++++++++--- 2 files changed, 38 insertions(+), 5 deletions(-)
e2fsck/super.c +29 -2
@@ -41,6 +41,23 @@ static void check_super_value(e2fsck_t ctx, const char *descr, } } +static void check_super_value64 (e2fsck_t ctx,const char *descr, +__u64 value,int flags, +__u64 min_val,__u64 max_val) +{ +struct problem_context pctx; + +if ((flags &MIN_CHECK && value < min_val) || + (flags &MAX_CHECK && value > max_val) || + (flags &LOG2_CHECK && (value & (value -1 )) !=0 )) { +clear_problem_context (&pctx); + pctx.num = value; + pctx.str = descr; +fix_problem (ctx,PR_0_MISC_CORRUPT_SUPER , &pctx); + ctx->flags |=E2F_FLAG_ABORT ;/* never get here! */ + } +} +/* * helper function to release an inode */
@@ -468,6 +485,7 @@ void check_super_block(e2fsck_t ctx)problem_t problem;blk64_t blocks_per_group = fs->super->s_blocks_per_group;__u32 bpg_max, cpg_max; +__u64 blks_max;int inodes_per_block;int inode_size;int accept_time_fudge;
@@ -497,6 +515,15 @@ void check_super_block(e2fsck_t ctx) ctx->invalid_inode_table_flag = (int *)e2fsck_allocate_memory (ctx,sizeof (int ) * fs->group_desc_count,"invalid_inode_table" ); + blks_max = (1ULL <<32 ) *EXT2_MAX_BLOCKS_PER_GROUP (fs->super); +if (ext2fs_has_feature_64bit (fs->super)) { +if (blks_max > ((1ULL <<48 ) -1 )) + blks_max = (1ULL <<48 ) -1 ; + }else { +if (blks_max > ((1ULL <<32 ) -1 )) + blks_max = (1ULL <<32 ) -1 ; + } +clear_problem_context (&pctx);/*
@@ -504,8 +531,8 @@ void check_super_block(e2fsck_t ctx)*/ check_super_value (ctx,"inodes_count" , sb->s_inodes_count,MIN_CHECK ,1 ,0 ); -check_super_value (ctx,"blocks_count" ,ext2fs_blocks_count (sb), -MIN_CHECK ,1 ,0 ); +check_super_value64 (ctx,"blocks_count" ,ext2fs_blocks_count (sb), +MIN_CHECK |MAX_CHECK ,1 , blks_max);check_super_value (ctx,"first_data_block" , sb->s_first_data_block,MAX_CHECK ,0 ,ext2fs_blocks_count (sb)); check_super_value(ctx, "log_block_size", sb->s_log_block_size,
lib/ext2fs/openfs.c +9 -3
@@ -122,6 +122,7 @@ errcode_t ext2fs_open2(const char *name, const char *io_options,char *dest, *cp;int group_zero_adjust =0 ;int inode_size; +__u64 groups_cnt;#ifdef WORDS_BIGENDIAN unsigned int groups_per_block;struct ext2_group_desc *gdp;
@@ -371,9 +372,14 @@ errcode_t ext2fs_open2(const char *name, const char *io_options, retval =EXT2_ET_CORRUPT_SUPERBLOCK ; goto cleanup; } - fs->group_desc_count =ext2fs_div64_ceil (ext2fs_blocks_count (fs->super) - - fs->super->s_first_data_block, - blocks_per_group); + groups_cnt =ext2fs_div64_ceil (ext2fs_blocks_count (fs->super) - + fs->super->s_first_data_block, + blocks_per_group); +if (groups_cnt >>32 ) { + retval =EXT2_ET_CORRUPT_SUPERBLOCK ; + goto cleanup; + } + fs->group_desc_count = groups_cnt;if (fs->group_desc_count *EXT2_INODES_PER_GROUP (fs->super) != fs->super->s_inodes_count) { retval =EXT2_ET_CORRUPT_SUPERBLOCK ;
Signature · 1 line
2.11.0.rc0.7.gbe5a750