Commit f37981ed authored by Nikola Z. Ivanov's avatar Nikola Z. Ivanov Committed by Jaegeuk Kim
Browse files

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: default avatar <syzbot+c07d47c7bc68f47b9083@syzkaller.appspotmail.com>
Closes: https://syzkaller.appspot.com/bug?extid=c07d47c7bc68f47b9083


Tested-by: default avatar <syzbot+c07d47c7bc68f47b9083@syzkaller.appspotmail.com>
Signed-off-by: default avatarNikola Z. Ivanov <zlatistiv@gmail.com>
Reviewed-by: default avatarChao Yu <chao@kernel.org>
Signed-off-by: default avatarJaegeuk Kim <jaegeuk@kernel.org>
parent 9b3c8336
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -294,6 +294,12 @@ static bool sanity_check_inode(struct inode *inode, struct folio *node_folio)
		return false;
	}

	if (S_ISDIR(inode->i_mode) && unlikely(inode->i_nlink == 1)) {
		f2fs_warn(sbi, "%s: directory inode (ino=%lx) has a single i_nlink",
			  __func__, inode->i_ino);
		return false;
	}

	if (f2fs_has_extra_attr(inode)) {
		if (!f2fs_sb_has_extra_attr(sbi)) {
			f2fs_warn(sbi, "%s: inode (ino=%lx) is with extra_attr, but extra_attr feature is off",
+12 −5
Original line number Diff line number Diff line
@@ -570,12 +570,13 @@ static int f2fs_unlink(struct inode *dir, struct dentry *dentry)
	}

	if (unlikely(inode->i_nlink == 0)) {
		f2fs_warn(F2FS_I_SB(inode), "%s: inode (ino=%lx) has zero i_nlink",
		f2fs_warn(sbi, "%s: inode (ino=%lx) has zero i_nlink",
			  __func__, inode->i_ino);
		err = -EFSCORRUPTED;
		set_sbi_flag(F2FS_I_SB(inode), SBI_NEED_FSCK);
		f2fs_folio_put(folio, false);
		goto out;
		goto corrupted;
	} else if (S_ISDIR(inode->i_mode) && unlikely(inode->i_nlink == 1)) {
		f2fs_warn(sbi, "%s: directory inode (ino=%lx) has a single i_nlink",
			  __func__, inode->i_ino);
		goto corrupted;
	}

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

	if (IS_DIRSYNC(dir))
		f2fs_sync_fs(sbi->sb, 1);

	goto out;
corrupted:
	err = -EFSCORRUPTED;
	set_sbi_flag(sbi, SBI_NEED_FSCK);
	f2fs_folio_put(folio, false);
out:
	trace_f2fs_unlink_exit(inode, err);
	return err;