public inbox for stable@vger.kernel.org
 help / color / mirror / Atom feed
From: ZhengYuan Huang <gality369@gmail.com>
To: jaegeuk@kernel.org, chao@kernel.org, cm224.lee@samsung.com
Cc: linux-f2fs-devel@lists.sourceforge.net,
	linux-kernel@vger.kernel.org, baijiaju1990@gmail.com,
	r33s3n6@gmail.com, zzzccc427@gmail.com,
	ZhengYuan Huang <gality369@gmail.com>,
	stable@vger.kernel.org
Subject: [PATCH] f2fs: reject non-directory inode in f2fs_get_parent() to prevent null-ptr-deref
Date: Wed, 18 Mar 2026 17:04:10 +0800	[thread overview]
Message-ID: <20260318090410.3368669-1-gality369@gmail.com> (raw)

[BUG]
When accessing a crafted f2fs filesystem via open_by_handle_at(2), a
KASAN null-pointer dereference is triggered deep inside the fscrypt
inline-encryption path:

  KASAN: null-ptr-deref in range [0x0000000000000010-0x0000000000000017]
  RIP: 0010:__fscrypt_inode_uses_inline_crypto fs/crypto/inline_crypt.c:266
  RIP: 0010:fscrypt_set_bio_crypt_ctx+0x200/0x300 fs/crypto/inline_crypt.c:308
  Call Trace:
    f2fs_set_bio_crypt_ctx fs/f2fs/data.c:492 [inline]
    f2fs_grab_read_bio+0x262/0x7d0 fs/f2fs/data.c:1056
    f2fs_submit_page_read+0xb2/0x180 fs/f2fs/data.c:1095
    f2fs_get_read_data_folio+0x633/0xbe0 fs/f2fs/data.c:1263
    f2fs_find_data_folio+0x146/0x330 fs/f2fs/data.c:1286
    find_in_level fs/f2fs/dir.c:302 [inline]
    __f2fs_find_entry+0x651/0xe10 fs/f2fs/dir.c:377
    f2fs_find_entry+0xc6/0x200 fs/f2fs/dir.c:418
    f2fs_inode_by_name+0x2a/0x1d0 fs/f2fs/dir.c:435
    f2fs_get_parent+0x9b/0x160 fs/f2fs/namei.c:451
    reconnect_one fs/exportfs/expfs.c:130 [inline]
    reconnect_path+0x1f6/0x8c0 fs/exportfs/expfs.c:220
    exportfs_decode_fh_raw+0x3f3/0x780 fs/exportfs/expfs.c:535
    do_handle_to_path fs/fhandle.c:276 [inline]
    handle_to_path fs/fhandle.c:400 [inline]
    do_handle_open+0x62f/0xb30 fs/fhandle.c:415
    __do_sys_open_by_handle_at fs/fhandle.c:455 [inline]
    __se_sys_open_by_handle_at fs/fhandle.c:446 [inline]
    __x64_sys_open_by_handle_at+0x7a/0xc0 fs/fhandle.c:446
    x64_sys_call+0x1cd5/0x26a0 arch/x86/include/generated/asm/syscalls_64.h:305
    ...

The bug is reproducible on next-20260313 with our dynamic
metadata fuzzing tool that corrupts f2fs metadata at runtime.

[CAUSE]
The export reconnect path (exportfs_decode_fh_raw -> reconnect_path ->
reconnect_one -> f2fs_get_parent) does not validate that the inode
embedded in a file handle is actually a directory before treating it
as one.

A crafted file handle can therefore supply a non-directory inode that
has IS_ENCRYPTED set and S_IFREG in i_mode. f2fs_get_parent() calls
f2fs_inode_by_name() on this inode, which eventually calls
f2fs_grab_read_bio() to read the inode's data blocks.
f2fs_grab_read_bio() calls fscrypt_set_bio_crypt_ctx(), which detects:

  fscrypt_needs_contents_encryption() == true  (IS_ENCRYPTED && S_ISREG)

and proceeds to call __fscrypt_inode_uses_inline_crypto(), which does:

  fscrypt_get_inode_info_raw(inode)->ci_inlinecrypt

Because the inode was never opened through the normal f2fs_file_open()
path, fscrypt_file_open() was never called, so i_crypt_info is NULL.
fscrypt_get_inode_info_raw() returns NULL unconditionally (only
printing a VFS_WARN_ON_ONCE), and the subsequent dereference of
NULL->ci_inlinecrypt triggers the null-ptr-deref.

[FIX]
Add an S_ISDIR() check at the top of f2fs_get_parent().  The function
is the f2fs implementation of export_operations::get_parent, which by
contract is only supposed to receive directory dentries.  Reject any
non-directory inode with -ENOTDIR before attempting to search for the
".." entry, so that a crafted file handle carrying a non-dir inode
cannot reach the fscrypt bio setup path without a properly initialised
i_crypt_info.

After this fix, the same crafted file handle will instead be rejected by
f2fs_get_parent() with -ENOTDIR, and the export reconnect path will not
proceed to call f2fs_inode_by_name() on the non-directory inode.

Fixes: 57397d86c62d ("f2fs: add inode operations for special inodes")
Cc: stable@vger.kernel.org
Signed-off-by: ZhengYuan Huang <gality369@gmail.com>
---
 fs/f2fs/namei.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c
index b882771e4699..0e81a2124a50 100644
--- a/fs/f2fs/namei.c
+++ b/fs/f2fs/namei.c
@@ -447,8 +447,14 @@ static int f2fs_link(struct dentry *old_dentry, struct inode *dir,
 
 struct dentry *f2fs_get_parent(struct dentry *child)
 {
+	struct inode *inode = d_inode(child);
 	struct folio *folio;
-	unsigned long ino = f2fs_inode_by_name(d_inode(child), &dotdot_name, &folio);
+	unsigned long ino;
+
+	if (!S_ISDIR(inode->i_mode))
+		return ERR_PTR(-ENOTDIR);
+
+	ino = f2fs_inode_by_name(inode, &dotdot_name, &folio);
 
 	if (!ino) {
 		if (IS_ERR(folio))
-- 
2.43.0


             reply	other threads:[~2026-03-18  9:04 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-03-18  9:04 ZhengYuan Huang [this message]
2026-03-18 10:08 ` [PATCH] f2fs: reject non-directory inode in f2fs_get_parent() to prevent null-ptr-deref Greg KH
2026-03-19 10:34   ` ZhengYuan Huang

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260318090410.3368669-1-gality369@gmail.com \
    --to=gality369@gmail.com \
    --cc=baijiaju1990@gmail.com \
    --cc=chao@kernel.org \
    --cc=cm224.lee@samsung.com \
    --cc=jaegeuk@kernel.org \
    --cc=linux-f2fs-devel@lists.sourceforge.net \
    --cc=linux-kernel@vger.kernel.org \
    --cc=r33s3n6@gmail.com \
    --cc=stable@vger.kernel.org \
    --cc=zzzccc427@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox