aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTheodore Ts'o <tytso@mit.edu>2009-01-06 14:53:26 -0500
committerTheodore Ts'o <tytso@mit.edu>2009-01-06 14:53:26 -0500
commit4ec110281379826c5cf6ed14735e47027c3c5765 (patch)
tree593bcbafe3541264e4effe5310546617de0a76ce
parentb3881f74b31b7d47d0f1c4d89ac3e7f0b9c05e3e (diff)
ext4: Add sanity checks for the superblock before mounting the filesystem
This avoids insane superblock configurations that could lead to kernel oops due to null pointer derefences. http://bugzilla.kernel.org/show_bug.cgi?id=12371 Thanks to David Maciejak at Fortinet's FortiGuard Global Security Research Team who discovered this bug independently (but at approximately the same time) as Thiemo Nagel, who submitted the patch. Signed-off-by: Thiemo Nagel <thiemo.nagel@ph.tum.de> Signed-off-by: "Theodore Ts'o" <tytso@mit.edu> Cc: stable@kernel.org
-rw-r--r--fs/ext4/super.c30
1 files changed, 20 insertions, 10 deletions
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index 8ff8709828fd..517c90ad25bd 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -2041,8 +2041,8 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
2041 const char *descr; 2041 const char *descr;
2042 int ret = -EINVAL; 2042 int ret = -EINVAL;
2043 int blocksize; 2043 int blocksize;
2044 int db_count; 2044 unsigned int db_count;
2045 int i; 2045 unsigned int i;
2046 int needs_recovery, has_huge_files; 2046 int needs_recovery, has_huge_files;
2047 int features; 2047 int features;
2048 __u64 blocks_count; 2048 __u64 blocks_count;
@@ -2331,20 +2331,30 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
2331 if (EXT4_BLOCKS_PER_GROUP(sb) == 0) 2331 if (EXT4_BLOCKS_PER_GROUP(sb) == 0)
2332 goto cantfind_ext4; 2332 goto cantfind_ext4;
2333 2333
2334 /* ensure blocks_count calculation below doesn't sign-extend */ 2334 /*
2335 if (ext4_blocks_count(es) + EXT4_BLOCKS_PER_GROUP(sb) < 2335 * It makes no sense for the first data block to be beyond the end
2336 le32_to_cpu(es->s_first_data_block) + 1) { 2336 * of the filesystem.
2337 printk(KERN_WARNING "EXT4-fs: bad geometry: block count %llu, " 2337 */
2338 "first data block %u, blocks per group %lu\n", 2338 if (le32_to_cpu(es->s_first_data_block) >= ext4_blocks_count(es)) {
2339 ext4_blocks_count(es), 2339 printk(KERN_WARNING "EXT4-fs: bad geometry: first data"
2340 le32_to_cpu(es->s_first_data_block), 2340 "block %u is beyond end of filesystem (%llu)\n",
2341 EXT4_BLOCKS_PER_GROUP(sb)); 2341 le32_to_cpu(es->s_first_data_block),
2342 ext4_blocks_count(es));
2342 goto failed_mount; 2343 goto failed_mount;
2343 } 2344 }
2344 blocks_count = (ext4_blocks_count(es) - 2345 blocks_count = (ext4_blocks_count(es) -
2345 le32_to_cpu(es->s_first_data_block) + 2346 le32_to_cpu(es->s_first_data_block) +
2346 EXT4_BLOCKS_PER_GROUP(sb) - 1); 2347 EXT4_BLOCKS_PER_GROUP(sb) - 1);
2347 do_div(blocks_count, EXT4_BLOCKS_PER_GROUP(sb)); 2348 do_div(blocks_count, EXT4_BLOCKS_PER_GROUP(sb));
2349 if (blocks_count > ((uint64_t)1<<32) - EXT4_DESC_PER_BLOCK(sb)) {
2350 printk(KERN_WARNING "EXT4-fs: groups count too large: %u "
2351 "(block count %llu, first data block %u, "
2352 "blocks per group %lu)\n", sbi->s_groups_count,
2353 ext4_blocks_count(es),
2354 le32_to_cpu(es->s_first_data_block),
2355 EXT4_BLOCKS_PER_GROUP(sb));
2356 goto failed_mount;
2357 }
2348 sbi->s_groups_count = blocks_count; 2358 sbi->s_groups_count = blocks_count;
2349 db_count = (sbi->s_groups_count + EXT4_DESC_PER_BLOCK(sb) - 1) / 2359 db_count = (sbi->s_groups_count + EXT4_DESC_PER_BLOCK(sb) - 1) /
2350 EXT4_DESC_PER_BLOCK(sb); 2360 EXT4_DESC_PER_BLOCK(sb);