[PATCH 1/3] f2fs: reject non-directory parent inode during dentry recovery

From: Cheng Yongkang

Date: Sun Oct 25 2026 - 14:02:44 EST


recover_dentry() takes i_pino from the on-disk inode and uses the
resulting inode as the directory for __f2fs_find_entry() and
f2fs_add_dentry(). A crafted image can set i_pino to a regular or
special inode; the recovery code does not check S_ISDIR() and then
writes a dentry into a non-directory inode, extending its i_size and
changing its directory-only metadata.

Reject the record with -EFSCORRUPTED and mark the filesystem for fsck:

F2FS-fs (loop0): recover_dentry: ino 4 is not a directory
F2FS-fs (loop0): Cannot recover all fsync data errno=-117

This was reproduced 3/3 times with a crafted image and the patched
kernel leaves the target regular file unmodified in 3/3 runs.

Assisted-by: LLM
Signed-off-by: Cheng Yongkang <teel4res@xxxxxxxxx>
---
fs/f2fs/recovery.c | 7 +++++++
1 file changed, 7 insertions(+)

diff --git a/fs/f2fs/recovery.c b/fs/f2fs/recovery.c
index aaa5227..e40f66f 100644
--- a/fs/f2fs/recovery.c
+++ b/fs/f2fs/recovery.c
@@ -209,6 +209,13 @@ static int recover_dentry(struct inode *inode, struct folio *ifolio,
}

dir = entry->inode;
+ if (!S_ISDIR(dir->i_mode)) {
+ f2fs_err(F2FS_I_SB(inode),
+ "%s: ino %u is not a directory", __func__, pino);
+ set_sbi_flag(F2FS_I_SB(inode), SBI_NEED_FSCK);
+ err = -EFSCORRUPTED;
+ goto out;
+ }
err = init_recovered_filename(dir, inode, raw_inode, &fname, &usr_fname);
if (err)
goto out;
--
2.34.1