Linux filesystem development
 help / color / mirror / Atom feed
From: Hui Peng <benquike@gmail.com>
To: luisbg@kernel.org, salah.triki@gmail.com, brauner@kernel.org
Cc: linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: [PATCH] befs: check NULL return from befs_bt_get_key() and fix keysize in befs_btree_read()
Date: Sat, 19 Sep 2026 22:25:55 +0000	[thread overview]
Message-ID: <20260919222555.3792599-1-benquike@gmail.com> (raw)

Fix two issues in fs/befs/:

1. In befs_btree_find() and befs_btree_read() (fs/befs/btree.c), check
   for a NULL return from befs_bt_get_key() when a corrupted B+tree node
   has out-of-bounds key offsets or lengths.
2. In befs_btree_read() and befs_readdir() (fs/befs/linuxvfs.c), set
   keysize from the actual copied string length rather than the raw
   buffer size so uninitialized stack bytes are not passed to filldir().

Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Assisted-by: LLM
Signed-off-by: Hui Peng <benquike@gmail.com>
---
diff --git a/fs/befs/btree.c b/fs/befs/btree.c
index aa24f1daccdd..67633e5f27fe 100644
--- a/fs/befs/btree.c
+++ b/fs/befs/btree.c
@@ -219,6 +219,19 @@ befs_bt_read_node(struct super_block *sb, const befs_data_stream *ds,
 	node->head.all_key_length =
 	    fs16_to_cpu(sb, node->od_node->all_key_length);
 
+	{
+		size_t keylen_off = round_up(sizeof(befs_btree_nodehead) +
+					     node->head.all_key_length, 8);
+		size_t total_needed = keylen_off +
+			(size_t)node->head.all_key_count * (sizeof(fs16) + sizeof(fs64));
+		if (off >= node->bh->b_size ||
+		    total_needed > node->bh->b_size - off) {
+			brelse(node->bh);
+			node->bh = NULL;
+			return BEFS_ERR;
+		}
+	}
+
 	befs_debug(sb, "<--- %s", __func__);
 	return BEFS_OK;
 }
@@ -343,6 +356,8 @@ befs_find_key(struct super_block *sb, struct befs_btree_node *node,
 	/* if node can not contain key, just skip this node */
 	last = node->head.all_key_count - 1;
 	thiskey = befs_bt_get_key(sb, node, last, &keylen);
+	if (!thiskey)
+		return BEFS_BT_NOT_FOUND;
 
 	eq = befs_compare_strings(thiskey, keylen, findkey, findkey_len);
 	if (eq < 0) {
@@ -360,6 +375,8 @@ befs_find_key(struct super_block *sb, struct befs_btree_node *node,
 		befs_debug(sb, "first: %d, last: %d, mid: %d", first, last,
 			   mid);
 		thiskey = befs_bt_get_key(sb, node, mid, &keylen);
+		if (!thiskey)
+			return BEFS_BT_NOT_FOUND;
 		eq = befs_compare_strings(thiskey, keylen, findkey,
 					  findkey_len);
 
@@ -417,6 +434,7 @@ befs_btree_read(struct super_block *sb, const befs_data_stream *ds,
 	int cur_key;
 	fs64 *valarray;
 	char *keystart;
+	ssize_t copy_len;
 	u16 keylen;
 	int res;
 
@@ -487,6 +505,10 @@ befs_btree_read(struct super_block *sb, const befs_data_stream *ds,
 	valarray = befs_bt_valarray(this_node);
 
 	keystart = befs_bt_get_key(sb, this_node, cur_key, &keylen);
+	if (!keystart) {
+		brelse(this_node->bh);
+		goto error_alloc;
+	}
 
 	befs_debug(sb, "Read [%llu,%d]: keysize %d",
 		   (long long unsigned int)node_off, (int)cur_key,
@@ -499,9 +521,9 @@ befs_btree_read(struct super_block *sb, const befs_data_stream *ds,
 		goto error_alloc;
 	}
 
-	strscpy(keybuf, keystart, keylen + 1);
+	copy_len = strscpy(keybuf, keystart, keylen + 1);
+	*keysize = (copy_len < 0) ? keylen : copy_len;
 	*value = fs64_to_cpu(sb, valarray[cur_key]);
-	*keysize = keylen;
 
 	befs_debug(sb, "Read [%llu,%d]: Key \"%.*s\", Value %llu", node_off,
 		   cur_key, keylen, keybuf, *value);
@@ -678,7 +700,7 @@ befs_bt_get_key(struct super_block *sb, struct befs_btree_node *node,
 	char *keystart;
 	fs16 *keylen_index;
 
-	if (index < 0 || index > node->head.all_key_count) {
+	if (index < 0 || index >= node->head.all_key_count) {
 		*keylen = 0;
 		return NULL;
 	}
@@ -691,6 +713,12 @@ befs_bt_get_key(struct super_block *sb, struct befs_btree_node *node,
 	else
 		prev_key_end = fs16_to_cpu(sb, keylen_index[index - 1]);
 
+	if (fs16_to_cpu(sb, keylen_index[index]) < prev_key_end ||
+	    fs16_to_cpu(sb, keylen_index[index]) > node->head.all_key_length) {
+		*keylen = 0;
+		return NULL;
+	}
+
 	*keylen = fs16_to_cpu(sb, keylen_index[index]) - prev_key_end;
 
 	return keystart + prev_key_end;
diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c
index ee0cbae521b9..de3be4d61c80 100644
--- a/fs/befs/linuxvfs.c
+++ b/fs/befs/linuxvfs.c
@@ -222,7 +222,7 @@ befs_readdir(struct file *file, struct dir_context *ctx)
 	befs_off_t value;
 	int result;
 	size_t keysize;
-	char keybuf[BEFS_NAME_LEN + 1];
+	char keybuf[BEFS_NAME_LEN + 1] = { 0 };
 
 	befs_debug(sb, "---> %s name %pD, inode %llu, ctx->pos %lld",
 		  __func__, file, inode->i_ino, ctx->pos);

                 reply	other threads:[~2026-09-19 22:25 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

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=20260919222555.3792599-1-benquike@gmail.com \
    --to=benquike@gmail.com \
    --cc=brauner@kernel.org \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=luisbg@kernel.org \
    --cc=salah.triki@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