| From bfe0a5f47ada40d7984de67e59a7d3390b9b9ecc Mon Sep 17 00:00:00 2001 |
| From: Theodore Ts'o <tytso@mit.edu> |
| Date: Sun, 17 Jun 2018 18:11:20 -0400 |
| Subject: ext4: add more mount time checks of the superblock |
| |
| From: Theodore Ts'o <tytso@mit.edu> |
| |
| commit bfe0a5f47ada40d7984de67e59a7d3390b9b9ecc upstream. |
| |
| The kernel's ext4 mount-time checks were more permissive than |
| e2fsprogs's libext2fs checks when opening a file system. The |
| superblock is considered too insane for debugfs or e2fsck to operate |
| on it, the kernel has no business trying to mount it. |
| |
| This will make file system fuzzing tools work harder, but the failure |
| cases that they find will be more useful and be easier to evaluate. |
| |
| Signed-off-by: Theodore Ts'o <tytso@mit.edu> |
| Cc: stable@kernel.org |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| fs/ext4/super.c | 37 ++++++++++++++++++++++++++----------- |
| 1 file changed, 26 insertions(+), 11 deletions(-) |
| |
| --- a/fs/ext4/super.c |
| +++ b/fs/ext4/super.c |
| @@ -3485,6 +3485,13 @@ static int ext4_fill_super(struct super_ |
| le32_to_cpu(es->s_log_block_size)); |
| goto failed_mount; |
| } |
| + if (le32_to_cpu(es->s_log_cluster_size) > |
| + (EXT4_MAX_CLUSTER_LOG_SIZE - EXT4_MIN_BLOCK_LOG_SIZE)) { |
| + ext4_msg(sb, KERN_ERR, |
| + "Invalid log cluster size: %u", |
| + le32_to_cpu(es->s_log_cluster_size)); |
| + goto failed_mount; |
| + } |
| |
| if (le16_to_cpu(sbi->s_es->s_reserved_gdt_blocks) > (blocksize / 4)) { |
| ext4_msg(sb, KERN_ERR, |
| @@ -3630,13 +3637,6 @@ static int ext4_fill_super(struct super_ |
| "block size (%d)", clustersize, blocksize); |
| goto failed_mount; |
| } |
| - if (le32_to_cpu(es->s_log_cluster_size) > |
| - (EXT4_MAX_CLUSTER_LOG_SIZE - EXT4_MIN_BLOCK_LOG_SIZE)) { |
| - ext4_msg(sb, KERN_ERR, |
| - "Invalid log cluster size: %u", |
| - le32_to_cpu(es->s_log_cluster_size)); |
| - goto failed_mount; |
| - } |
| sbi->s_cluster_bits = le32_to_cpu(es->s_log_cluster_size) - |
| le32_to_cpu(es->s_log_block_size); |
| sbi->s_clusters_per_group = |
| @@ -3657,10 +3657,10 @@ static int ext4_fill_super(struct super_ |
| } |
| } else { |
| if (clustersize != blocksize) { |
| - ext4_warning(sb, "fragment/cluster size (%d) != " |
| - "block size (%d)", clustersize, |
| - blocksize); |
| - clustersize = blocksize; |
| + ext4_msg(sb, KERN_ERR, |
| + "fragment/cluster size (%d) != " |
| + "block size (%d)", clustersize, blocksize); |
| + goto failed_mount; |
| } |
| if (sbi->s_blocks_per_group > blocksize * 8) { |
| ext4_msg(sb, KERN_ERR, |
| @@ -3714,6 +3714,13 @@ static int ext4_fill_super(struct super_ |
| ext4_blocks_count(es)); |
| goto failed_mount; |
| } |
| + if ((es->s_first_data_block == 0) && (es->s_log_block_size == 0) && |
| + (sbi->s_cluster_ratio == 1)) { |
| + ext4_msg(sb, KERN_WARNING, "bad geometry: first data " |
| + "block is 0 with a 1k block and cluster size"); |
| + goto failed_mount; |
| + } |
| + |
| blocks_count = (ext4_blocks_count(es) - |
| le32_to_cpu(es->s_first_data_block) + |
| EXT4_BLOCKS_PER_GROUP(sb) - 1); |
| @@ -3749,6 +3756,14 @@ static int ext4_fill_super(struct super_ |
| ret = -ENOMEM; |
| goto failed_mount; |
| } |
| + if (((u64)sbi->s_groups_count * sbi->s_inodes_per_group) != |
| + le32_to_cpu(es->s_inodes_count)) { |
| + ext4_msg(sb, KERN_ERR, "inodes count not valid: %u vs %llu", |
| + le32_to_cpu(es->s_inodes_count), |
| + ((u64)sbi->s_groups_count * sbi->s_inodes_per_group)); |
| + ret = -EINVAL; |
| + goto failed_mount; |
| + } |
| |
| bgl_lock_init(sbi->s_blockgroup_lock); |
| |