mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Kaixuan Li <kaixuanli0131@gmail.com>
To: Jaegeuk Kim <jaegeuk@kernel.org>, Chao Yu <chao@kernel.org>
Cc: Kaixuan Li <kaixuanli0131@gmail.com>,
	linux-f2fs-devel@lists.sourceforge.net,
	linux-kernel@vger.kernel.org
Subject: [PATCH] f2fs: check every cur_*_segno[] entry on readonly images
Date: Sat, 19 Sep 2026 00:55:07 +0800	[thread overview]
Message-ID: <20260918165507.1267942-1-kaixuanli0131@gmail.com> (raw)

sanity_check_ckpt() bounds-checks cur_node_segno[] and cur_data_segno[]
against main_segs, but on an image with the RO feature the goto that skips
the duplicate-segno cross-checks also leaves the enclosing loop, so only
index 0 of each array is ever checked.

An unchecked index reaches __set_sit_entry_type() through build_curseg() ->
reset_curseg(), which writes se->type through &sit_i->sentries[segno]. With
segment_count_main 120 and cur_data_segno[1] set to 200, KASAN reports
three out-of-bounds writes during mount and the mount then succeeds.

Use continue so every index is bounds-checked, and skip the node-vs-data
cross-check explicitly, which is the other thing the old goto skipped.

Fixes: a7d9fe3c3388 ("f2fs: support RO feature")
Signed-off-by: Kaixuan Li <kaixuanli0131@gmail.com>
---
Found on v7.2.4; the code is unchanged in mainline at commit
5dd1818b15d98d4a20806cd00b1b40320b06004f.

Before the patch, mounting such an image on v7.2.4 with KASAN:

	BUG: KASAN: slab-out-of-bounds in reset_curseg+0x48a/0x530
	Write of size 4 at addr ffff888009f8df40 by task init/1
	 reset_curseg+0x48a/0x530
	 f2fs_build_segment_manager+0x1f65/0x8de0
	 f2fs_fill_super+0x4348/0x7a10
	 vfs_get_tree+0x83/0x2f0
	 path_mount+0x570/0x1fb0
	The buggy address is located 3200 bytes to the right of
	 allocated 4800-byte region [ffff888009f8c000, ffff888009f8d2c0)

The 4800-byte region is sentries[], 120 entries. Two further writes of
size 8 follow at f2fs_build_segment_manager+0x479f and +0x480e, so
__set_sit_entry_type() is not the only sink the unchecked value reaches.
The mount completes afterwards, so nothing surfaces the corruption.

Reproducer: mkfs.f2fs on a 256 MB image gives segment_count_main = 120.
Then, in both superblock copies (offset 1024 and 1024 + F2FS_BLKSIZE) and
both checkpoint packs, set F2FS_FEATURE_RO (0x4000) in the feature word and
set cur_data_segno[1] and cur_node_segno[1] to 200; recompute each pack's
crc32 over checksum_offset bytes seeded with F2FS_SUPER_MAGIC and store it
at checksum_offset. Mount read-only. Scripts available on request.

Tested on v7.2.4 x86_64 with KASAN, three cases:

  - crafted image as above: rejected at checkpoint validation, no KASAN
    report (before the patch: three reports, and the mount succeeded);
  - plain mkfs.f2fs image: still mounts;
  - RO feature set with valid segnos: still mounts, which is why the
    node-vs-data cross-check is skipped explicitly rather than by letting
    the loop fall through to it.

fs/f2fs/super.c builds warning-free and checkpatch is clean apart from
"Unknown commit id" for the Fixes: tag, which is an artefact of the tree I
built in rather than the tag.
---
 fs/f2fs/super.c | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

--- a/fs/f2fs/super.c
+++ b/fs/f2fs/super.c
@@ -4239,7 +4239,7 @@
 			return 1;
 
 		if (f2fs_sb_has_readonly(sbi))
-			goto check_data;
+			continue;
 
 		for (j = i + 1; j < NR_CURSEG_NODE_TYPE; j++) {
 			if (le32_to_cpu(ckpt->cur_node_segno[i]) ==
@@ -4251,14 +4251,14 @@
 			}
 		}
 	}
-check_data:
+
 	for (i = 0; i < NR_CURSEG_DATA_TYPE; i++) {
 		if (le32_to_cpu(ckpt->cur_data_segno[i]) >= main_segs ||
 			le16_to_cpu(ckpt->cur_data_blkoff[i]) >= blocks_per_seg)
 			return 1;
 
 		if (f2fs_sb_has_readonly(sbi))
-			goto skip_cross;
+			continue;
 
 		for (j = i + 1; j < NR_CURSEG_DATA_TYPE; j++) {
 			if (le32_to_cpu(ckpt->cur_data_segno[i]) ==
@@ -4270,6 +4270,9 @@
 			}
 		}
 	}
+	if (f2fs_sb_has_readonly(sbi))
+		goto skip_cross;
+
 	for (i = 0; i < NR_CURSEG_NODE_TYPE; i++) {
 		for (j = 0; j < NR_CURSEG_DATA_TYPE; j++) {
 			if (le32_to_cpu(ckpt->cur_node_segno[i]) ==

             reply	other threads:[~2026-09-18 16:55 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-18 16:55 Kaixuan Li [this message]
2026-10-11 12:19 ` Chao Yu
2026-10-13 22:30 ` [f2fs-dev] " patchwork-bot+f2fs

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=20260918165507.1267942-1-kaixuanli0131@gmail.com \
    --to=kaixuanli0131@gmail.com \
    --cc=chao@kernel.org \
    --cc=jaegeuk@kernel.org \
    --cc=linux-f2fs-devel@lists.sourceforge.net \
    --cc=linux-kernel@vger.kernel.org \
    /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

all inboxes | Powered by JetHome®