Commit d92539e1 authored by Andries E. Brouwer's avatar Andries E. Brouwer Committed by Linus Torvalds

[PATCH] don't divide by zero on bad ext2 fs

Experimented a bit more with mounting a bad ext2 filesystem.

An immediate crash was caused by zero EXT2_BLOCKS_PER_GROUP(sb).
The patch below (relative to 2.6.9) adds a few checks to make sure
that things we divide by are not zero.
parent cfe15b8a
...@@ -593,12 +593,9 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent) ...@@ -593,12 +593,9 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
sbi->s_es = es; sbi->s_es = es;
sb->s_magic = le16_to_cpu(es->s_magic); sb->s_magic = le16_to_cpu(es->s_magic);
sb->s_flags |= MS_ONE_SECOND; sb->s_flags |= MS_ONE_SECOND;
if (sb->s_magic != EXT2_SUPER_MAGIC) {
if (!silent) if (sb->s_magic != EXT2_SUPER_MAGIC)
printk ("VFS: Can't find ext2 filesystem on dev %s.\n", goto cantfind_ext2;
sb->s_id);
goto failed_mount;
}
/* Set defaults before we parse the mount options */ /* Set defaults before we parse the mount options */
def_mount_opts = le32_to_cpu(es->s_default_mount_opts); def_mount_opts = le32_to_cpu(es->s_default_mount_opts);
...@@ -653,7 +650,9 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent) ...@@ -653,7 +650,9 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
sb->s_id, le32_to_cpu(features)); sb->s_id, le32_to_cpu(features));
goto failed_mount; goto failed_mount;
} }
blocksize = BLOCK_SIZE << le32_to_cpu(sbi->s_es->s_log_block_size); blocksize = BLOCK_SIZE << le32_to_cpu(sbi->s_es->s_log_block_size);
/* If the blocksize doesn't match, re-read the thing.. */ /* If the blocksize doesn't match, re-read the thing.. */
if (sb->s_blocksize != blocksize) { if (sb->s_blocksize != blocksize) {
brelse(bh); brelse(bh);
...@@ -695,35 +694,36 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent) ...@@ -695,35 +694,36 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
goto failed_mount; goto failed_mount;
} }
} }
sbi->s_frag_size = EXT2_MIN_FRAG_SIZE << sbi->s_frag_size = EXT2_MIN_FRAG_SIZE <<
le32_to_cpu(es->s_log_frag_size); le32_to_cpu(es->s_log_frag_size);
if (sbi->s_frag_size) if (sbi->s_frag_size == 0)
sbi->s_frags_per_block = sb->s_blocksize / goto cantfind_ext2;
sbi->s_frag_size; sbi->s_frags_per_block = sb->s_blocksize / sbi->s_frag_size;
else
sb->s_magic = 0;
sbi->s_blocks_per_group = le32_to_cpu(es->s_blocks_per_group); sbi->s_blocks_per_group = le32_to_cpu(es->s_blocks_per_group);
sbi->s_frags_per_group = le32_to_cpu(es->s_frags_per_group); sbi->s_frags_per_group = le32_to_cpu(es->s_frags_per_group);
sbi->s_inodes_per_group = le32_to_cpu(es->s_inodes_per_group); sbi->s_inodes_per_group = le32_to_cpu(es->s_inodes_per_group);
sbi->s_inodes_per_block = sb->s_blocksize /
EXT2_INODE_SIZE(sb); if (EXT2_INODE_SIZE(sb) == 0)
goto cantfind_ext2;
sbi->s_inodes_per_block = sb->s_blocksize / EXT2_INODE_SIZE(sb);
if (sbi->s_inodes_per_block == 0)
goto cantfind_ext2;
sbi->s_itb_per_group = sbi->s_inodes_per_group / sbi->s_itb_per_group = sbi->s_inodes_per_group /
sbi->s_inodes_per_block; sbi->s_inodes_per_block;
sbi->s_desc_per_block = sb->s_blocksize / sbi->s_desc_per_block = sb->s_blocksize /
sizeof (struct ext2_group_desc); sizeof (struct ext2_group_desc);
sbi->s_sbh = bh; sbi->s_sbh = bh;
sbi->s_mount_state = le16_to_cpu(es->s_state); sbi->s_mount_state = le16_to_cpu(es->s_state);
sbi->s_addr_per_block_bits = sbi->s_addr_per_block_bits =
log2 (EXT2_ADDR_PER_BLOCK(sb)); log2 (EXT2_ADDR_PER_BLOCK(sb));
sbi->s_desc_per_block_bits = sbi->s_desc_per_block_bits =
log2 (EXT2_DESC_PER_BLOCK(sb)); log2 (EXT2_DESC_PER_BLOCK(sb));
if (sb->s_magic != EXT2_SUPER_MAGIC) {
if (!silent) if (sb->s_magic != EXT2_SUPER_MAGIC)
printk ("VFS: Can't find an ext2 filesystem on dev " goto cantfind_ext2;
"%s.\n",
sb->s_id);
goto failed_mount;
}
if (sb->s_blocksize != bh->b_size) { if (sb->s_blocksize != bh->b_size) {
if (!silent) if (!silent)
printk ("VFS: Unsupported blocksize on dev " printk ("VFS: Unsupported blocksize on dev "
...@@ -753,6 +753,8 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent) ...@@ -753,6 +753,8 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
goto failed_mount; goto failed_mount;
} }
if (EXT2_BLOCKS_PER_GROUP(sb) == 0)
goto cantfind_ext2;
sbi->s_groups_count = (le32_to_cpu(es->s_blocks_count) - sbi->s_groups_count = (le32_to_cpu(es->s_blocks_count) -
le32_to_cpu(es->s_first_data_block) + le32_to_cpu(es->s_first_data_block) +
EXT2_BLOCKS_PER_GROUP(sb) - 1) / EXT2_BLOCKS_PER_GROUP(sb) - 1) /
...@@ -823,13 +825,19 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent) ...@@ -823,13 +825,19 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
percpu_counter_mod(&sbi->s_dirs_counter, percpu_counter_mod(&sbi->s_dirs_counter,
ext2_count_dirs(sb)); ext2_count_dirs(sb));
return 0; return 0;
cantfind_ext2:
if (!silent)
printk("VFS: Can't find an ext2 filesystem on dev %s.\n",
sb->s_id);
goto failed_mount;
failed_mount2: failed_mount2:
for (i = 0; i < db_count; i++) for (i = 0; i < db_count; i++)
brelse(sbi->s_group_desc[i]); brelse(sbi->s_group_desc[i]);
failed_mount_group_desc: failed_mount_group_desc:
kfree(sbi->s_group_desc); kfree(sbi->s_group_desc);
if (sbi->s_debts) kfree(sbi->s_debts);
kfree(sbi->s_debts);
failed_mount: failed_mount:
brelse(bh); brelse(bh);
failed_sbi: failed_sbi:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment