Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

f2fs: fix to do sanity check for inline inode

Yanming reported a kernel bug in Bugzilla kernel [1], which can be
reproduced. The bug message is:

The kernel message is shown below:

kernel BUG at fs/inode.c:611!
Call Trace:
evict+0x282/0x4e0
__dentry_kill+0x2b2/0x4d0
dput+0x2dd/0x720
do_renameat2+0x596/0x970
__x64_sys_rename+0x78/0x90
do_syscall_64+0x3b/0x90

[1] https://bugzilla.kernel.org/show_bug.cgi?id=215895

The bug is due to fuzzed inode has both inline_data and encrypted flags.
During f2fs_evict_inode(), as the inode was deleted by rename(), it
will cause inline data conversion due to conflicting flags. The page
cache will be polluted and the panic will be triggered in clear_inode().

Try fixing the bug by doing more sanity checks for inline data inode in
sanity_check_inode().

Cc: stable@vger.kernel.org
Reported-by: Ming Yan <yanming@tju.edu.cn>
Signed-off-by: Chao Yu <chao.yu@oppo.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>

authored by

Chao Yu and committed by
Jaegeuk Kim
677a82b4 958ed929

+26 -7
+1
fs/f2fs/f2fs.h
··· 4019 4019 * inline.c 4020 4020 */ 4021 4021 bool f2fs_may_inline_data(struct inode *inode); 4022 + bool f2fs_sanity_check_inline_data(struct inode *inode); 4022 4023 bool f2fs_may_inline_dentry(struct inode *inode); 4023 4024 void f2fs_do_read_inline_data(struct page *page, struct page *ipage); 4024 4025 void f2fs_truncate_inline_inode(struct inode *inode,
+24 -5
fs/f2fs/inline.c
··· 14 14 #include "node.h" 15 15 #include <trace/events/f2fs.h> 16 16 17 - bool f2fs_may_inline_data(struct inode *inode) 17 + static bool support_inline_data(struct inode *inode) 18 18 { 19 19 if (f2fs_is_atomic_file(inode)) 20 20 return false; 21 - 22 21 if (!S_ISREG(inode->i_mode) && !S_ISLNK(inode->i_mode)) 23 22 return false; 24 - 25 23 if (i_size_read(inode) > MAX_INLINE_DATA(inode)) 26 24 return false; 25 + return true; 26 + } 27 27 28 - if (f2fs_post_read_required(inode)) 28 + bool f2fs_may_inline_data(struct inode *inode) 29 + { 30 + if (!support_inline_data(inode)) 29 31 return false; 30 32 31 - return true; 33 + return !f2fs_post_read_required(inode); 34 + } 35 + 36 + bool f2fs_sanity_check_inline_data(struct inode *inode) 37 + { 38 + if (!f2fs_has_inline_data(inode)) 39 + return false; 40 + 41 + if (!support_inline_data(inode)) 42 + return true; 43 + 44 + /* 45 + * used by sanity_check_inode(), when disk layout fields has not 46 + * been synchronized to inmem fields. 47 + */ 48 + return (S_ISREG(inode->i_mode) && 49 + (file_is_encrypt(inode) || file_is_verity(inode) || 50 + (F2FS_I(inode)->i_flags & F2FS_COMPR_FL))); 32 51 } 33 52 34 53 bool f2fs_may_inline_dentry(struct inode *inode)
+1 -2
fs/f2fs/inode.c
··· 276 276 } 277 277 } 278 278 279 - if (f2fs_has_inline_data(inode) && 280 - (!S_ISREG(inode->i_mode) && !S_ISLNK(inode->i_mode))) { 279 + if (f2fs_sanity_check_inline_data(inode)) { 281 280 set_sbi_flag(sbi, SBI_NEED_FSCK); 282 281 f2fs_warn(sbi, "%s: inode (ino=%lx, mode=%u) should not have inline_data, run fsck to fix", 283 282 __func__, inode->i_ino, inode->i_mode);