Skip to content

Commit 63b1e9b

Browse files
LiBaokun96tytso
authored andcommitted
ext4: add EXT4_IGET_BAD flag to prevent unexpected bad inode
There are many places that will get unhappy (and crash) when ext4_iget() returns a bad inode. However, if iget the boot loader inode, allows a bad inode to be returned, because the inode may not be initialized. This mechanism can be used to bypass some checks and cause panic. To solve this problem, we add a special iget flag EXT4_IGET_BAD. Only with this flag we'd be returning bad inode from ext4_iget(), otherwise we always return the error code if the inode is bad inode.(suggested by Jan Kara) Signed-off-by: Baokun Li <[email protected]> Reviewed-by: Jason Yan <[email protected]> Reviewed-by: Jan Kara <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Theodore Ts'o <[email protected]> Cc: [email protected]
1 parent 07342ec commit 63b1e9b

File tree

3 files changed

+11
-3
lines changed

3 files changed

+11
-3
lines changed

fs/ext4/ext4.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -2964,7 +2964,8 @@ int do_journal_get_write_access(handle_t *handle, struct inode *inode,
29642964
typedef enum {
29652965
EXT4_IGET_NORMAL = 0,
29662966
EXT4_IGET_SPECIAL = 0x0001, /* OK to iget a system inode */
2967-
EXT4_IGET_HANDLE = 0x0002 /* Inode # is from a handle */
2967+
EXT4_IGET_HANDLE = 0x0002, /* Inode # is from a handle */
2968+
EXT4_IGET_BAD = 0x0004 /* Allow to iget a bad inode */
29682969
} ext4_iget_flags;
29692970

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

fs/ext4/inode.c

+7-1
Original file line numberDiff line numberDiff line change
@@ -5058,8 +5058,14 @@ struct inode *__ext4_iget(struct super_block *sb, unsigned long ino,
50585058
if (IS_CASEFOLDED(inode) && !ext4_has_feature_casefold(inode->i_sb))
50595059
ext4_error_inode(inode, function, line, 0,
50605060
"casefold flag without casefold feature");
5061-
brelse(iloc.bh);
5061+
if (is_bad_inode(inode) && !(flags & EXT4_IGET_BAD)) {
5062+
ext4_error_inode(inode, function, line, 0,
5063+
"bad inode without EXT4_IGET_BAD flag");
5064+
ret = -EUCLEAN;
5065+
goto bad_inode;
5066+
}
50625067

5068+
brelse(iloc.bh);
50635069
unlock_new_inode(inode);
50645070
return inode;
50655071

fs/ext4/ioctl.c

+2-1
Original file line numberDiff line numberDiff line change
@@ -374,7 +374,8 @@ static long swap_inode_boot_loader(struct super_block *sb,
374374
blkcnt_t blocks;
375375
unsigned short bytes;
376376

377-
inode_bl = ext4_iget(sb, EXT4_BOOT_LOADER_INO, EXT4_IGET_SPECIAL);
377+
inode_bl = ext4_iget(sb, EXT4_BOOT_LOADER_INO,
378+
EXT4_IGET_SPECIAL | EXT4_IGET_BAD);
378379
if (IS_ERR(inode_bl))
379380
return PTR_ERR(inode_bl);
380381
ei_bl = EXT4_I(inode_bl);

0 commit comments

Comments
 (0)