On Wed 26-10-22 12:23:09, Baokun Li wrote: > 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 <libaokun1@xxxxxxxxxx> Looks good to me. Feel free to add: Reviewed-by: Jan Kara <jack@xxxxxxx> Honza > --- > fs/ext4/ext4.h | 3 ++- > fs/ext4/inode.c | 8 +++++++- > fs/ext4/ioctl.c | 3 ++- > 3 files changed, 11 insertions(+), 3 deletions(-) > > diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h > index 8d5453852f98..2b574b143bde 100644 > --- a/fs/ext4/ext4.h > +++ b/fs/ext4/ext4.h > @@ -2964,7 +2964,8 @@ int do_journal_get_write_access(handle_t *handle, struct inode *inode, > typedef enum { > EXT4_IGET_NORMAL = 0, > EXT4_IGET_SPECIAL = 0x0001, /* OK to iget a system inode */ > - EXT4_IGET_HANDLE = 0x0002 /* Inode # is from a handle */ > + EXT4_IGET_HANDLE = 0x0002, /* Inode # is from a handle */ > + EXT4_IGET_BAD = 0x0004 /* Allow to iget a bad inode */ > } ext4_iget_flags; > > extern struct inode *__ext4_iget(struct super_block *sb, unsigned long ino, > diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c > index ae3a836dd9d7..f767340229fd 100644 > --- a/fs/ext4/inode.c > +++ b/fs/ext4/inode.c > @@ -5043,8 +5043,14 @@ struct inode *__ext4_iget(struct super_block *sb, unsigned long ino, > if (IS_CASEFOLDED(inode) && !ext4_has_feature_casefold(inode->i_sb)) > ext4_error_inode(inode, function, line, 0, > "casefold flag without casefold feature"); > - brelse(iloc.bh); > + if (is_bad_inode(inode) && !(flags & EXT4_IGET_BAD)) { > + ext4_error_inode(inode, function, line, 0, > + "bad inode without EXT4_IGET_BAD flag"); > + ret = -EUCLEAN; > + goto bad_inode; > + } > > + brelse(iloc.bh); > unlock_new_inode(inode); > return inode; > > diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c > index ded535535b27..e0be8026c996 100644 > --- a/fs/ext4/ioctl.c > +++ b/fs/ext4/ioctl.c > @@ -375,7 +375,8 @@ static long swap_inode_boot_loader(struct super_block *sb, > blkcnt_t blocks; > unsigned short bytes; > > - inode_bl = ext4_iget(sb, EXT4_BOOT_LOADER_INO, EXT4_IGET_SPECIAL); > + inode_bl = ext4_iget(sb, EXT4_BOOT_LOADER_INO, > + EXT4_IGET_SPECIAL | EXT4_IGET_BAD); > if (IS_ERR(inode_bl)) > return PTR_ERR(inode_bl); > ei_bl = EXT4_I(inode_bl); > -- > 2.31.1 > -- Jan Kara <jack@xxxxxxxx> SUSE Labs, CR