diff mbox series

[4/5] ext4: add more inode number paranoia checks

Message ID 20180618032232.25481-4-tytso@mit.edu
State Accepted, archived
Headers show
Series [1/5] ext4: never move the system.data xattr out of the inode body | expand

Commit Message

Theodore Ts'o June 18, 2018, 3:22 a.m. UTC
If there is a directory entry pointing to a system inode (such as a
journal inode), complain and declare the file system to be corrupted.

Also, if the superblock's first inode number field is too small,
refuse to mount the file system.

https://bugzilla.kernel.org/show_bug.cgi?id=200069

Signed-off-by: Theodore Ts'o <tytso@mit.edu>
---
 fs/ext4/ext4.h  | 5 -----
 fs/ext4/inode.c | 3 ++-
 fs/ext4/super.c | 5 +++++
 3 files changed, 7 insertions(+), 6 deletions(-)

Comments

Andreas Dilger June 18, 2018, 6:35 p.m. UTC | #1
On Jun 17, 2018, at 9:22 PM, Theodore Ts'o <tytso@mit.edu> wrote:
> 
> If there is a directory entry pointing to a system inode (such as a
> journal inode), complain and declare the file system to be corrupted.
> 
> Also, if the superblock's first inode number field is too small,
> refuse to mount the file system.
> 
> https://bugzilla.kernel.org/show_bug.cgi?id=200069
> 
> Signed-off-by: Theodore Ts'o <tytso@mit.edu>

I was a bit concerned that this would break the ancient option of the
journal or quota inodes being created in the filesystem namespace and
then converted to be internal inodes, but my thought is not correct.
Those inodes would be regular-numbered inodes added into the superblock
fields, rather than reserved inode numbers being added to the namespace.

Reviewed-by: Andreas Dilger <adilger@dilger.ca>

> ---
> fs/ext4/ext4.h  | 5 -----
> fs/ext4/inode.c | 3 ++-
> fs/ext4/super.c | 5 +++++
> 3 files changed, 7 insertions(+), 6 deletions(-)
> 
> diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
> index 859d6433dcc1..4bd69649a048 100644
> --- a/fs/ext4/ext4.h
> +++ b/fs/ext4/ext4.h
> @@ -1502,11 +1502,6 @@ static inline struct ext4_inode_info *EXT4_I(struct inode *inode)
> static inline int ext4_valid_inum(struct super_block *sb, unsigned long ino)
> {
> 	return ino == EXT4_ROOT_INO ||
> -		ino == EXT4_USR_QUOTA_INO ||
> -		ino == EXT4_GRP_QUOTA_INO ||
> -		ino == EXT4_BOOT_LOADER_INO ||
> -		ino == EXT4_JOURNAL_INO ||
> -		ino == EXT4_RESIZE_INO ||
> 		(ino >= EXT4_FIRST_INO(sb) &&
> 		 ino <= le32_to_cpu(EXT4_SB(sb)->s_es->s_inodes_count));
> }
> diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
> index c2f4ccb880c4..7d6c10017bdf 100644
> --- a/fs/ext4/inode.c
> +++ b/fs/ext4/inode.c
> @@ -4506,7 +4506,8 @@ static int __ext4_get_inode_loc(struct inode *inode,
> 	int			inodes_per_block, inode_offset;
> 
> 	iloc->bh = NULL;
> -	if (!ext4_valid_inum(sb, inode->i_ino))
> +	if (inode->i_ino < EXT4_ROOT_INO ||
> +	    inode->i_ino > le32_to_cpu(EXT4_SB(sb)->s_es->s_inodes_count))
> 		return -EFSCORRUPTED;
> 
> 	iloc->block_group = (inode->i_ino - 1) / EXT4_INODES_PER_GROUP(sb);
> diff --git a/fs/ext4/super.c b/fs/ext4/super.c
> index 4d34430d75f6..1f955c128e0d 100644
> --- a/fs/ext4/super.c
> +++ b/fs/ext4/super.c
> @@ -3858,6 +3858,11 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
> 	} else {
> 		sbi->s_inode_size = le16_to_cpu(es->s_inode_size);
> 		sbi->s_first_ino = le32_to_cpu(es->s_first_ino);
> +		if (sbi->s_first_ino < EXT4_GOOD_OLD_FIRST_INO) {
> +			ext4_msg(sb, KERN_ERR, "invalid first ino: %u",
> +				 sbi->s_first_ino);
> +			goto failed_mount;
> +		}
> 		if ((sbi->s_inode_size < EXT4_GOOD_OLD_INODE_SIZE) ||
> 		    (!is_power_of_2(sbi->s_inode_size)) ||
> 		    (sbi->s_inode_size > blocksize)) {
> --
> 2.18.0.rc0
> 


Cheers, Andreas
diff mbox series

Patch

diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index 859d6433dcc1..4bd69649a048 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -1502,11 +1502,6 @@  static inline struct ext4_inode_info *EXT4_I(struct inode *inode)
 static inline int ext4_valid_inum(struct super_block *sb, unsigned long ino)
 {
 	return ino == EXT4_ROOT_INO ||
-		ino == EXT4_USR_QUOTA_INO ||
-		ino == EXT4_GRP_QUOTA_INO ||
-		ino == EXT4_BOOT_LOADER_INO ||
-		ino == EXT4_JOURNAL_INO ||
-		ino == EXT4_RESIZE_INO ||
 		(ino >= EXT4_FIRST_INO(sb) &&
 		 ino <= le32_to_cpu(EXT4_SB(sb)->s_es->s_inodes_count));
 }
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index c2f4ccb880c4..7d6c10017bdf 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -4506,7 +4506,8 @@  static int __ext4_get_inode_loc(struct inode *inode,
 	int			inodes_per_block, inode_offset;
 
 	iloc->bh = NULL;
-	if (!ext4_valid_inum(sb, inode->i_ino))
+	if (inode->i_ino < EXT4_ROOT_INO ||
+	    inode->i_ino > le32_to_cpu(EXT4_SB(sb)->s_es->s_inodes_count))
 		return -EFSCORRUPTED;
 
 	iloc->block_group = (inode->i_ino - 1) / EXT4_INODES_PER_GROUP(sb);
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index 4d34430d75f6..1f955c128e0d 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -3858,6 +3858,11 @@  static int ext4_fill_super(struct super_block *sb, void *data, int silent)
 	} else {
 		sbi->s_inode_size = le16_to_cpu(es->s_inode_size);
 		sbi->s_first_ino = le32_to_cpu(es->s_first_ino);
+		if (sbi->s_first_ino < EXT4_GOOD_OLD_FIRST_INO) {
+			ext4_msg(sb, KERN_ERR, "invalid first ino: %u",
+				 sbi->s_first_ino);
+			goto failed_mount;
+		}
 		if ((sbi->s_inode_size < EXT4_GOOD_OLD_INODE_SIZE) ||
 		    (!is_power_of_2(sbi->s_inode_size)) ||
 		    (sbi->s_inode_size > blocksize)) {