Skip to content

Commit f37981e

Browse files
zlatistivJaegeuk Kim
authored andcommitted
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>
1 parent 9b3c833 commit f37981e

File tree

2 files changed

+18
-5
lines changed

2 files changed

+18
-5
lines changed

fs/f2fs/inode.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,12 @@ static bool sanity_check_inode(struct inode *inode, struct folio *node_folio)
294294
return false;
295295
}
296296

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+
297303
if (f2fs_has_extra_attr(inode)) {
298304
if (!f2fs_sb_has_extra_attr(sbi)) {
299305
f2fs_warn(sbi, "%s: inode (ino=%lx) is with extra_attr, but extra_attr feature is off",

fs/f2fs/namei.c

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -570,12 +570,13 @@ static int f2fs_unlink(struct inode *dir, struct dentry *dentry)
570570
}
571571

572572
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",
574574
__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;
579580
}
580581

581582
f2fs_balance_fs(sbi, true);
@@ -601,6 +602,12 @@ static int f2fs_unlink(struct inode *dir, struct dentry *dentry)
601602

602603
if (IS_DIRSYNC(dir))
603604
f2fs_sync_fs(sbi->sb, 1);
605+
606+
goto out;
607+
corrupted:
608+
err = -EFSCORRUPTED;
609+
set_sbi_flag(sbi, SBI_NEED_FSCK);
610+
f2fs_folio_put(folio, false);
604611
out:
605612
trace_f2fs_unlink_exit(inode, err);
606613
return err;

0 commit comments

Comments
 (0)