All of lore.kernel.org
 help / color / mirror / Atom feed
From: 이상호 <kudo3228@gmail.com>
To: Bob Copeland <me@bobcopeland.com>
Cc: linux-karma-devel@lists.sourceforge.net,
	linux-kernel@vger.kernel.org, 이상호 <kudo3228@gmail.com>
Subject: [PATCH 1/2] omfs: detect directory sibling chain cycles
Date: Thu,  2 Jul 2026 07:02:10 +0900	[thread overview]
Message-ID: <20260701220211.822033-2-kudo3228@gmail.com> (raw)
In-Reply-To: <20260701220211.822033-1-kudo3228@gmail.com>

OMFS directory lookup follows an on-disk sibling chain until it
reaches the ~0 terminator.

The sibling block number is image-controlled, so a crafted image can
point an entry back to itself or create a small cycle. Lookup of a
missing name in that hash bucket then spins in the kernel.

Detect cycles in OMFS directory sibling chains and return -ELOOP from
lookup when a cycle is found. Readdir uses the same detection to stop
traversing malformed chains.

Fixes: a3ab7155ea21 ("omfs: add directory routines")
Signed-off-by: 이상호 <kudo3228@gmail.com>
---
 fs/omfs/dir.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 63 insertions(+), 1 deletion(-)

diff --git a/fs/omfs/dir.c b/fs/omfs/dir.c
index 2ed541fccf33..11b680f1c383 100644
--- a/fs/omfs/dir.c
+++ b/fs/omfs/dir.c
@@ -31,6 +31,56 @@ static struct buffer_head *omfs_get_bucket(struct inode *dir,
 	return omfs_bread(dir->i_sb, dir->i_ino);
 }
 
+static int omfs_get_sibling(struct inode *dir, u64 block, u64 *sibling)
+{
+	struct buffer_head *bh;
+	struct omfs_inode *oi;
+
+	bh = omfs_bread(dir->i_sb, block);
+	if (!bh)
+		return -EIO;
+
+	oi = (struct omfs_inode *)bh->b_data;
+	if (omfs_is_bad(OMFS_SB(dir->i_sb), &oi->i_head, block)) {
+		brelse(bh);
+		return -EIO;
+	}
+
+	*sibling = be64_to_cpu(oi->i_sibling);
+	brelse(bh);
+	return 0;
+}
+
+static int omfs_check_chain_cycle(struct inode *dir, u64 *slow, u64 *fast)
+{
+	int err;
+
+	if (*fast == ~0)
+		return 0;
+
+	err = omfs_get_sibling(dir, *fast, fast);
+	if (err)
+		return err;
+
+	if (*fast == ~0)
+		return 0;
+
+	err = omfs_get_sibling(dir, *fast, fast);
+	if (err)
+		return err;
+
+	if (*slow != ~0) {
+		err = omfs_get_sibling(dir, *slow, slow);
+		if (err)
+			return err;
+	}
+
+	if (*slow != ~0 && *slow == *fast)
+		return -ELOOP;
+
+	return 0;
+}
+
 static struct buffer_head *omfs_scan_list(struct inode *dir, u64 block,
 				const char *name, int namelen,
 				u64 *prev_block)
@@ -38,6 +88,8 @@ static struct buffer_head *omfs_scan_list(struct inode *dir, u64 block,
 	struct buffer_head *bh;
 	struct omfs_inode *oi;
 	int err = -ENOENT;
+	u64 slow = block;
+	u64 fast = block;
 	*prev_block = ~0;
 
 	while (block != ~0) {
@@ -59,6 +111,10 @@ static struct buffer_head *omfs_scan_list(struct inode *dir, u64 block,
 		*prev_block = block;
 		block = be64_to_cpu(oi->i_sibling);
 		brelse(bh);
+
+		err = omfs_check_chain_cycle(dir, &slow, &fast);
+		if (err)
+			goto err;
 	}
 err:
 	return ERR_PTR(err);
@@ -331,12 +387,15 @@ static bool omfs_fill_chain(struct inode *dir, struct dir_context *ctx,
 		u64 fsblock, int hindex)
 {
 	/* follow chain in this bucket */
+	u64 slow = fsblock;
+	u64 fast = fsblock;
 	while (fsblock != ~0) {
-		struct buffer_head *bh = omfs_bread(dir->i_sb, fsblock);
+		struct buffer_head *bh;
 		struct omfs_inode *oi;
 		u64 self;
 		unsigned char d_type;
 
+		bh = omfs_bread(dir->i_sb, fsblock);
 		if (!bh)
 			return true;
 
@@ -366,6 +425,9 @@ static bool omfs_fill_chain(struct inode *dir, struct dir_context *ctx,
 		}
 		brelse(bh);
 		ctx->pos++;
+
+		if (omfs_check_chain_cycle(dir, &slow, &fast))
+			return true;
 	}
 	return true;
 }
-- 
2.43.0


  reply	other threads:[~2026-07-01 22:02 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-01 22:02 [PATCH 0/2] omfs: detect metadata chain cycles 이상호
2026-07-01 22:02 ` 이상호 [this message]
2026-07-01 22:02 ` [PATCH 2/2] omfs: detect file extent " 이상호

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=20260701220211.822033-2-kudo3228@gmail.com \
    --to=kudo3228@gmail.com \
    --cc=linux-karma-devel@lists.sourceforge.net \
    --cc=linux-kernel@vger.kernel.org \
    --cc=me@bobcopeland.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.