Skip to content

Commit b3e6bcb

Browse files
committed
ext4: add EA_INODE checking to ext4_iget()
Add a new flag, EXT4_IGET_EA_INODE which indicates whether the inode is expected to have the EA_INODE flag or not. If the flag is not set/clear as expected, then fail the iget() operation and mark the file system as corrupted. This commit also makes the ext4_iget() always perform the is_bad_inode() check even when the inode is already inode cache. This allows us to remove the is_bad_inode() check from the callers of ext4_iget() in the ea_inode code. Reported-by: [email protected] Reported-by: [email protected] Reported-by: [email protected] Cc: [email protected] Signed-off-by: Theodore Ts'o <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Theodore Ts'o <[email protected]>
1 parent 7877cb9 commit b3e6bcb

File tree

3 files changed

+35
-35
lines changed

3 files changed

+35
-35
lines changed

fs/ext4/ext4.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2901,7 +2901,8 @@ typedef enum {
29012901
EXT4_IGET_NORMAL = 0,
29022902
EXT4_IGET_SPECIAL = 0x0001, /* OK to iget a system inode */
29032903
EXT4_IGET_HANDLE = 0x0002, /* Inode # is from a handle */
2904-
EXT4_IGET_BAD = 0x0004 /* Allow to iget a bad inode */
2904+
EXT4_IGET_BAD = 0x0004, /* Allow to iget a bad inode */
2905+
EXT4_IGET_EA_INODE = 0x0008 /* Inode should contain an EA value */
29052906
} ext4_iget_flags;
29062907

29072908
extern struct inode *__ext4_iget(struct super_block *sb, unsigned long ino,

fs/ext4/inode.c

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4641,6 +4641,21 @@ static inline void ext4_inode_set_iversion_queried(struct inode *inode, u64 val)
46414641
inode_set_iversion_queried(inode, val);
46424642
}
46434643

4644+
static const char *check_igot_inode(struct inode *inode, ext4_iget_flags flags)
4645+
4646+
{
4647+
if (flags & EXT4_IGET_EA_INODE) {
4648+
if (!(EXT4_I(inode)->i_flags & EXT4_EA_INODE_FL))
4649+
return "missing EA_INODE flag";
4650+
} else {
4651+
if ((EXT4_I(inode)->i_flags & EXT4_EA_INODE_FL))
4652+
return "unexpected EA_INODE flag";
4653+
}
4654+
if (is_bad_inode(inode) && !(flags & EXT4_IGET_BAD))
4655+
return "unexpected bad inode w/o EXT4_IGET_BAD";
4656+
return NULL;
4657+
}
4658+
46444659
struct inode *__ext4_iget(struct super_block *sb, unsigned long ino,
46454660
ext4_iget_flags flags, const char *function,
46464661
unsigned int line)
@@ -4650,6 +4665,7 @@ struct inode *__ext4_iget(struct super_block *sb, unsigned long ino,
46504665
struct ext4_inode_info *ei;
46514666
struct ext4_super_block *es = EXT4_SB(sb)->s_es;
46524667
struct inode *inode;
4668+
const char *err_str;
46534669
journal_t *journal = EXT4_SB(sb)->s_journal;
46544670
long ret;
46554671
loff_t size;
@@ -4677,8 +4693,14 @@ struct inode *__ext4_iget(struct super_block *sb, unsigned long ino,
46774693
inode = iget_locked(sb, ino);
46784694
if (!inode)
46794695
return ERR_PTR(-ENOMEM);
4680-
if (!(inode->i_state & I_NEW))
4696+
if (!(inode->i_state & I_NEW)) {
4697+
if ((err_str = check_igot_inode(inode, flags)) != NULL) {
4698+
ext4_error_inode(inode, function, line, 0, err_str);
4699+
iput(inode);
4700+
return ERR_PTR(-EFSCORRUPTED);
4701+
}
46814702
return inode;
4703+
}
46824704

46834705
ei = EXT4_I(inode);
46844706
iloc.bh = NULL;
@@ -4944,10 +4966,9 @@ struct inode *__ext4_iget(struct super_block *sb, unsigned long ino,
49444966
if (IS_CASEFOLDED(inode) && !ext4_has_feature_casefold(inode->i_sb))
49454967
ext4_error_inode(inode, function, line, 0,
49464968
"casefold flag without casefold feature");
4947-
if (is_bad_inode(inode) && !(flags & EXT4_IGET_BAD)) {
4948-
ext4_error_inode(inode, function, line, 0,
4949-
"bad inode without EXT4_IGET_BAD flag");
4950-
ret = -EUCLEAN;
4969+
if ((err_str = check_igot_inode(inode, flags)) != NULL) {
4970+
ext4_error_inode(inode, function, line, 0, err_str);
4971+
ret = -EFSCORRUPTED;
49514972
goto bad_inode;
49524973
}
49534974

fs/ext4/xattr.c

Lines changed: 7 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -433,31 +433,14 @@ static int ext4_xattr_inode_iget(struct inode *parent, unsigned long ea_ino,
433433
return -EFSCORRUPTED;
434434
}
435435

436-
inode = ext4_iget(parent->i_sb, ea_ino, EXT4_IGET_NORMAL);
436+
inode = ext4_iget(parent->i_sb, ea_ino, EXT4_IGET_EA_INODE);
437437
if (IS_ERR(inode)) {
438438
err = PTR_ERR(inode);
439439
ext4_error(parent->i_sb,
440440
"error while reading EA inode %lu err=%d", ea_ino,
441441
err);
442442
return err;
443443
}
444-
445-
if (is_bad_inode(inode)) {
446-
ext4_error(parent->i_sb,
447-
"error while reading EA inode %lu is_bad_inode",
448-
ea_ino);
449-
err = -EIO;
450-
goto error;
451-
}
452-
453-
if (!(EXT4_I(inode)->i_flags & EXT4_EA_INODE_FL)) {
454-
ext4_error(parent->i_sb,
455-
"EA inode %lu does not have EXT4_EA_INODE_FL flag",
456-
ea_ino);
457-
err = -EINVAL;
458-
goto error;
459-
}
460-
461444
ext4_xattr_inode_set_class(inode);
462445

463446
/*
@@ -478,9 +461,6 @@ static int ext4_xattr_inode_iget(struct inode *parent, unsigned long ea_ino,
478461

479462
*ea_inode = inode;
480463
return 0;
481-
error:
482-
iput(inode);
483-
return err;
484464
}
485465

486466
/* Remove entry from mbcache when EA inode is getting evicted */
@@ -1556,11 +1536,10 @@ ext4_xattr_inode_cache_find(struct inode *inode, const void *value,
15561536

15571537
while (ce) {
15581538
ea_inode = ext4_iget(inode->i_sb, ce->e_value,
1559-
EXT4_IGET_NORMAL);
1560-
if (!IS_ERR(ea_inode) &&
1561-
!is_bad_inode(ea_inode) &&
1562-
(EXT4_I(ea_inode)->i_flags & EXT4_EA_INODE_FL) &&
1563-
i_size_read(ea_inode) == value_len &&
1539+
EXT4_IGET_EA_INODE);
1540+
if (IS_ERR(ea_inode))
1541+
goto next_entry;
1542+
if (i_size_read(ea_inode) == value_len &&
15641543
!ext4_xattr_inode_read(ea_inode, ea_data, value_len) &&
15651544
!ext4_xattr_inode_verify_hashes(ea_inode, NULL, ea_data,
15661545
value_len) &&
@@ -1570,9 +1549,8 @@ ext4_xattr_inode_cache_find(struct inode *inode, const void *value,
15701549
kvfree(ea_data);
15711550
return ea_inode;
15721551
}
1573-
1574-
if (!IS_ERR(ea_inode))
1575-
iput(ea_inode);
1552+
iput(ea_inode);
1553+
next_entry:
15761554
ce = mb_cache_entry_find_next(ea_inode_cache, ce);
15771555
}
15781556
kvfree(ea_data);

0 commit comments

Comments
 (0)