All of lore.kernel.org
 help / color / mirror / Atom feed
From: syzbot <syzbot+8debf4b3f7c7391cd8eb@syzkaller.appspotmail.com>
To: linux-kernel@vger.kernel.org, syzkaller-bugs@googlegroups.com
Subject: Forwarded: [PATCH] hpfs: add buffer bounds validation in hpfs_bplus_lookup
Date: Fri, 16 Jan 2026 18:32:22 -0800	[thread overview]
Message-ID: <696af4b6.050a0220.3390f1.0001.GAE@google.com> (raw)
In-Reply-To: <696aa7da.a70a0220.31956c.001a.GAE@google.com>

For archival purposes, forwarding an incoming command email to
linux-kernel@vger.kernel.org, syzkaller-bugs@googlegroups.com.

***

Subject: [PATCH] hpfs: add buffer bounds validation in hpfs_bplus_lookup
Author: kartikey406@gmail.com


#syz test: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git master

When traversing the B+ tree in a corrupted HPFS filesystem, the btree
pointer obtained from GET_BTREE_PTR() may point outside the mapped
buffer's bounds if the on-disk data structures are malformed. This
leads to a use-after-free when accessing btree->u.external[i] as the
memory may have been freed and reallocated.

Additionally, a corrupted n_used_nodes value can cause out-of-bounds
array access when iterating through btree->u.internal[] or
btree->u.external[] arrays.

Add validation to ensure:
1. The btree pointer stays within the mapped buffer boundaries
2. The n_used_nodes value is within reasonable limits

This prevents KASAN-detected use-after-free when processing malicious
HPFS filesystem images.

Reported-by: syzbot+8debf4b3f7c7391cd8eb@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=8debf4b3f7c7391cd8eb
Signed-off-by: Deepanshu Kartikey <kartikey406@gmail.com>
---
 fs/hpfs/anode.c | XX insertions(+), X deletions(-)

diff --git a/fs/hpfs/anode.c b/fs/hpfs/anode.c
index XXXXXXX..YYYYYYY 100644
--- a/fs/hpfs/anode.c
+++ b/fs/hpfs/anode.c
@@ -XX,6 +XX,16 @@ secno hpfs_bplus_lookup(struct super_block *s, struct inode *inode,
 				brelse(bh);
 				if (!(anode = hpfs_map_anode(s
---
 fs/hpfs/anode.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 71 insertions(+), 3 deletions(-)

diff --git a/fs/hpfs/anode.c b/fs/hpfs/anode.c
index a4f5321eafae..826e2142223b 100644
--- a/fs/hpfs/anode.c
+++ b/fs/hpfs/anode.c
@@ -19,25 +19,87 @@ secno hpfs_bplus_lookup(struct super_block *s, struct inode *inode,
 	struct anode *anode;
 	int i;
 	int c1, c2 = 0;
+	
+	printk(KERN_DEBUG "hpfs_bplus_lookup: ENTRY btree=%px bh=%px sec=%u\n", 
+	       btree, bh, sec);
+	
 	go_down:
 	if (hpfs_sb(s)->sb_chk) if (hpfs_stop_cycles(s, a, &c1, &c2, "hpfs_bplus_lookup")) return -1;
+	
+	printk(KERN_DEBUG "hpfs_bplus_lookup: go_down - btree=%px bh=%px internal=%d n_used_nodes=%u\n",
+	       btree, bh, bp_internal(btree), btree->n_used_nodes);
+	
 	if (bp_internal(btree)) {
-		for (i = 0; i < btree->n_used_nodes; i++)
+		printk(KERN_DEBUG "hpfs_bplus_lookup: Processing INTERNAL node\n");
+		for (i = 0; i < btree->n_used_nodes; i++) {
+			printk(KERN_DEBUG "hpfs_bplus_lookup: internal[%d] file_secno=%u looking_for=%u\n",
+			       i, le32_to_cpu(btree->u.internal[i].file_secno), sec);
+			
 			if (le32_to_cpu(btree->u.internal[i].file_secno) > sec) {
 				a = le32_to_cpu(btree->u.internal[i].down);
+				
+				printk(KERN_DEBUG "hpfs_bplus_lookup: Found match, going down to anode=%08x\n", a);
+				printk(KERN_DEBUG "hpfs_bplus_lookup: BEFORE brelse - bh=%px btree=%px\n", bh, btree);
+				
 				brelse(bh);
-				if (!(anode = hpfs_map_anode(s, a, &bh))) return -1;
+				
+				printk(KERN_DEBUG "hpfs_bplus_lookup: AFTER brelse - calling hpfs_map_anode\n");
+				
+				if (!(anode = hpfs_map_anode(s, a, &bh))) {
+					printk(KERN_ERR "hpfs_bplus_lookup: hpfs_map_anode FAILED for anode=%08x\n", a);
+					return -1;
+				}
+				
+				printk(KERN_DEBUG "hpfs_bplus_lookup: hpfs_map_anode SUCCESS - new_bh=%px anode=%px\n", bh, anode);
+				
 				btree = GET_BTREE_PTR(&anode->btree);
+				/* Validate btree pointer is within buffer bounds */
+				if ((unsigned long)btree < (unsigned long)bh->b_data ||
+    					(unsigned long)btree + sizeof(*btree) > (unsigned long)bh->b_data + bh->b_size) {
+    					printk(KERN_ERR "hpfs_bplus_lookup: INVALID btree pointer! btree=%px buf_start=%px buf_end=%px\n",
+           					btree, bh->b_data, (void *)((unsigned long)bh->b_data + bh->b_size));
+    					brelse(bh);
+    					return -1;
+				}
+
+				/* Validate n_used_nodes is reasonable */
+				if (btree->n_used_nodes > 100) {  /* Adjust based on actual max */
+    					printk(KERN_ERR "hpfs_bplus_lookup: SUSPICIOUS n_used_nodes=%u (too large)\n",
+           					btree->n_used_nodes);
+    					brelse(bh);
+    					return -1;
+				}				
+				printk(KERN_DEBUG "hpfs_bplus_lookup: NEW btree=%px (from anode->btree)\n", btree);
+				
 				goto go_down;
 			}
+		}
 		hpfs_error(s, "sector %08x not found in internal anode %08x", sec, a);
 		brelse(bh);
 		return -1;
 	}
-	for (i = 0; i < btree->n_used_nodes; i++)
+	
+	printk(KERN_DEBUG "hpfs_bplus_lookup: Processing EXTERNAL node - btree=%px bh=%px n_used_nodes=%u\n",
+	       btree, bh, btree->n_used_nodes);
+	
+	/* Add bounds checking */
+	printk(KERN_DEBUG "hpfs_bplus_lookup: Buffer bounds - bh->b_data=%px size=%zu btree=%px\n",
+	       bh->b_data, bh->b_size, btree);
+	
+	for (i = 0; i < btree->n_used_nodes; i++) {
+		printk(KERN_DEBUG "hpfs_bplus_lookup: external[%d] - accessing btree->u.external[%d] at %px\n",
+		       i, i, &btree->u.external[i]);
+		
+		/* This is line 38 - the crash point */
+		printk(KERN_DEBUG "hpfs_bplus_lookup: external[%d] - reading file_secno from %px\n",
+		       i, &btree->u.external[i].file_secno);
+		
 		if (le32_to_cpu(btree->u.external[i].file_secno) <= sec &&
 		    le32_to_cpu(btree->u.external[i].file_secno) + le32_to_cpu(btree->u.external[i].length) > sec) {
 			a = le32_to_cpu(btree->u.external[i].disk_secno) + sec - le32_to_cpu(btree->u.external[i].file_secno);
+			
+			printk(KERN_DEBUG "hpfs_bplus_lookup: FOUND external match - disk_secno=%u\n", a);
+			
 			if (hpfs_sb(s)->sb_chk) if (hpfs_chk_sectors(s, a, 1, "data")) {
 				brelse(bh);
 				return -1;
@@ -49,10 +111,16 @@ secno hpfs_bplus_lookup(struct super_block *s, struct inode *inode,
 				hpfs_inode->i_n_secs = le32_to_cpu(btree->u.external[i].length);
 			}
 			brelse(bh);
+			
+			printk(KERN_DEBUG "hpfs_bplus_lookup: EXIT SUCCESS - returning %u\n", a);
 			return a;
 		}
+	}
+	
 	hpfs_error(s, "sector %08x not found in external anode %08x", sec, a);
 	brelse(bh);
+	
+	printk(KERN_DEBUG "hpfs_bplus_lookup: EXIT FAILURE\n");
 	return -1;
 }
 
-- 
2.43.0


  reply	other threads:[~2026-01-17  2:32 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-01-16 21:04 [syzbot] [xfs?] KASAN: use-after-free Read in hpfs_bplus_lookup syzbot
2026-01-17  2:32 ` syzbot [this message]
2026-01-17  3:45 ` Forwarded: [PATCH] hpfs: add buffer bounds validation " syzbot
2026-01-17  4:38 ` Forwarded: [PATCH] hpfs: add debug logging to hpfs_bplus_lookup syzbot
2026-01-17  5:05 ` Forwarded: [PATCH] hpfs: add array bounds validation in hpfs_bplus_lookup syzbot
2026-01-19  6:36 ` [syzbot] [xfs?] KASAN: use-after-free Read " Christoph Hellwig
2026-01-19  8:35   ` Aleksandr Nogikh
2026-04-29 15:21 ` Forwarded: " syzbot

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=696af4b6.050a0220.3390f1.0001.GAE@google.com \
    --to=syzbot+8debf4b3f7c7391cd8eb@syzkaller.appspotmail.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=syzkaller-bugs@googlegroups.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.