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

Configure Feed

Select the types of activity you want to include in your feed.

f2fs: Add sanity checks before unlinking and loading inodes

Add check for inode->i_nlink == 1 for directories during unlink,
as their value is decremented twice, which can trigger a warning in
drop_nlink. In such case mark the filesystem as corrupted and return
from the function call with the relevant failure return value.

Additionally add the check for i_nlink == 1 in
sanity_check_inode in order to detect on-disk corruption early.

Reported-by: syzbot+c07d47c7bc68f47b9083@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=c07d47c7bc68f47b9083
Tested-by: syzbot+c07d47c7bc68f47b9083@syzkaller.appspotmail.com
Signed-off-by: Nikola Z. Ivanov <zlatistiv@gmail.com>
Reviewed-by: Chao Yu <chao@kernel.org>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>

authored by

Nikola Z. Ivanov and committed by
Jaegeuk Kim
f37981ed 9b3c8336

+18 -5
+6
fs/f2fs/inode.c
··· 294 294 return false; 295 295 } 296 296 297 + if (S_ISDIR(inode->i_mode) && unlikely(inode->i_nlink == 1)) { 298 + f2fs_warn(sbi, "%s: directory inode (ino=%lx) has a single i_nlink", 299 + __func__, inode->i_ino); 300 + return false; 301 + } 302 + 297 303 if (f2fs_has_extra_attr(inode)) { 298 304 if (!f2fs_sb_has_extra_attr(sbi)) { 299 305 f2fs_warn(sbi, "%s: inode (ino=%lx) is with extra_attr, but extra_attr feature is off",
+12 -5
fs/f2fs/namei.c
··· 570 570 } 571 571 572 572 if (unlikely(inode->i_nlink == 0)) { 573 - f2fs_warn(F2FS_I_SB(inode), "%s: inode (ino=%lx) has zero i_nlink", 573 + f2fs_warn(sbi, "%s: inode (ino=%lx) has zero i_nlink", 574 574 __func__, inode->i_ino); 575 - err = -EFSCORRUPTED; 576 - set_sbi_flag(F2FS_I_SB(inode), SBI_NEED_FSCK); 577 - f2fs_folio_put(folio, false); 578 - goto out; 575 + goto corrupted; 576 + } else if (S_ISDIR(inode->i_mode) && unlikely(inode->i_nlink == 1)) { 577 + f2fs_warn(sbi, "%s: directory inode (ino=%lx) has a single i_nlink", 578 + __func__, inode->i_ino); 579 + goto corrupted; 579 580 } 580 581 581 582 f2fs_balance_fs(sbi, true); ··· 602 601 603 602 if (IS_DIRSYNC(dir)) 604 603 f2fs_sync_fs(sbi->sb, 1); 604 + 605 + goto out; 606 + corrupted: 607 + err = -EFSCORRUPTED; 608 + set_sbi_flag(sbi, SBI_NEED_FSCK); 609 + f2fs_folio_put(folio, false); 605 610 out: 606 611 trace_f2fs_unlink_exit(inode, err); 607 612 return err;