Skip to content

Commit 4ea9993

Browse files
committed
ext4: add more paranoia checking in ext4_expand_extra_isize handling
It's possible to specify a non-zero s_want_extra_isize via debugging option, and this can cause bad things(tm) to happen when using a file system with an inode size of 128 bytes. Add better checking when the file system is mounted, as well as when we are actually doing the trying to do the inode expansion. Link: https://lore.kernel.org/r/[email protected] Reported-by: [email protected] Reported-by: [email protected] Reported-by: [email protected] Signed-off-by: Theodore Ts'o <[email protected]> Cc: [email protected]
1 parent 8d0d47e commit 4ea9993

File tree

2 files changed

+27
-9
lines changed

2 files changed

+27
-9
lines changed

fs/ext4/inode.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5569,8 +5569,23 @@ static int __ext4_expand_extra_isize(struct inode *inode,
55695569
{
55705570
struct ext4_inode *raw_inode;
55715571
struct ext4_xattr_ibody_header *header;
5572+
unsigned int inode_size = EXT4_INODE_SIZE(inode->i_sb);
5573+
struct ext4_inode_info *ei = EXT4_I(inode);
55725574
int error;
55735575

5576+
/* this was checked at iget time, but double check for good measure */
5577+
if ((EXT4_GOOD_OLD_INODE_SIZE + ei->i_extra_isize > inode_size) ||
5578+
(ei->i_extra_isize & 3)) {
5579+
EXT4_ERROR_INODE(inode, "bad extra_isize %u (inode size %u)",
5580+
ei->i_extra_isize,
5581+
EXT4_INODE_SIZE(inode->i_sb));
5582+
return -EFSCORRUPTED;
5583+
}
5584+
if ((new_extra_isize < ei->i_extra_isize) ||
5585+
(new_extra_isize < 4) ||
5586+
(new_extra_isize > inode_size - EXT4_GOOD_OLD_INODE_SIZE))
5587+
return -EINVAL; /* Should never happen */
5588+
55745589
raw_inode = ext4_raw_inode(iloc);
55755590

55765591
header = IHDR(inode, raw_inode);

fs/ext4/super.c

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3545,12 +3545,15 @@ static void ext4_clamp_want_extra_isize(struct super_block *sb)
35453545
{
35463546
struct ext4_sb_info *sbi = EXT4_SB(sb);
35473547
struct ext4_super_block *es = sbi->s_es;
3548+
unsigned def_extra_isize = sizeof(struct ext4_inode) -
3549+
EXT4_GOOD_OLD_INODE_SIZE;
35483550

3549-
/* determine the minimum size of new large inodes, if present */
3550-
if (sbi->s_inode_size > EXT4_GOOD_OLD_INODE_SIZE &&
3551-
sbi->s_want_extra_isize == 0) {
3552-
sbi->s_want_extra_isize = sizeof(struct ext4_inode) -
3553-
EXT4_GOOD_OLD_INODE_SIZE;
3551+
if (sbi->s_inode_size == EXT4_GOOD_OLD_INODE_SIZE) {
3552+
sbi->s_want_extra_isize = 0;
3553+
return;
3554+
}
3555+
if (sbi->s_want_extra_isize < 4) {
3556+
sbi->s_want_extra_isize = def_extra_isize;
35543557
if (ext4_has_feature_extra_isize(sb)) {
35553558
if (sbi->s_want_extra_isize <
35563559
le16_to_cpu(es->s_want_extra_isize))
@@ -3563,10 +3566,10 @@ static void ext4_clamp_want_extra_isize(struct super_block *sb)
35633566
}
35643567
}
35653568
/* Check if enough inode space is available */
3566-
if (EXT4_GOOD_OLD_INODE_SIZE + sbi->s_want_extra_isize >
3567-
sbi->s_inode_size) {
3568-
sbi->s_want_extra_isize = sizeof(struct ext4_inode) -
3569-
EXT4_GOOD_OLD_INODE_SIZE;
3569+
if ((sbi->s_want_extra_isize > sbi->s_inode_size) ||
3570+
(EXT4_GOOD_OLD_INODE_SIZE + sbi->s_want_extra_isize >
3571+
sbi->s_inode_size)) {
3572+
sbi->s_want_extra_isize = def_extra_isize;
35703573
ext4_msg(sb, KERN_INFO,
35713574
"required extra inode space not available");
35723575
}

0 commit comments

Comments
 (0)