The Linux Kernel Mailing List
 help / color / mirror / Atom feed
* [syzbot] kernel BUG in hfs_write_inode
@ 2022-11-25  9:45 syzbot
  2025-10-02 16:16 ` George Anthony Vernon
                   ` (8 more replies)
  0 siblings, 9 replies; 15+ messages in thread
From: syzbot @ 2022-11-25  9:45 UTC (permalink / raw)
  To: damien.lemoal, jlayton, linux-fsdevel, linux-kernel,
	syzkaller-bugs, willy

Hello,

syzbot found the following issue on:

HEAD commit:    65762d97e6fa Merge branch 'for-next/perf' into for-kernelci
git tree:       git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux.git for-kernelci
console output: https://syzkaller.appspot.com/x/log.txt?x=14e324e3880000
kernel config:  https://syzkaller.appspot.com/x/.config?x=56d0c7c3a2304e8f
dashboard link: https://syzkaller.appspot.com/bug?extid=97e301b4b82ae803d21b
compiler:       Debian clang version 13.0.1-++20220126092033+75e33f71c2da-1~exp1~20220126212112.63, GNU ld (GNU Binutils for Debian) 2.35.2
userspace arch: arm64
syz repro:      https://syzkaller.appspot.com/x/repro.syz?x=10983553880000
C reproducer:   https://syzkaller.appspot.com/x/repro.c?x=13315ebb880000

Downloadable assets:
disk image: https://storage.googleapis.com/syzbot-assets/52f702197b30/disk-65762d97.raw.xz
vmlinux: https://storage.googleapis.com/syzbot-assets/72189c2789ce/vmlinux-65762d97.xz
kernel image: https://storage.googleapis.com/syzbot-assets/ec0349196c98/Image-65762d97.gz.xz
mounted in repro: https://storage.googleapis.com/syzbot-assets/6bfea2266b7f/mount_0.gz

IMPORTANT: if you fix the issue, please add the following tag to the commit:
Reported-by: syzbot+97e301b4b82ae803d21b@syzkaller.appspotmail.com

------------[ cut here ]------------
kernel BUG at fs/hfs/inode.c:446!
Internal error: Oops - BUG: 00000000f2000800 [#1] PREEMPT SMP
Modules linked in:
CPU: 0 PID: 347 Comm: kworker/u4:3 Not tainted 6.1.0-rc6-syzkaller-32653-g65762d97e6fa #0
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 09/30/2022
Workqueue: writeback wb_workfn (flush-7:0)
pstate: 80400005 (Nzcv daif +PAN -UAO -TCO -DIT -SSBS BTYPE=--)
pc : hfs_write_inode+0x44c/0x450 fs/hfs/inode.c:446
lr : hfs_write_inode+0x44c/0x450 fs/hfs/inode.c:446
sp : ffff800012f9b960
x29: ffff800012f9ba10 x28: ffff0000cb9013e0 x27: ffff0000cb901358
x26: 0000000000000021 x25: 0000000000000007 x24: ffff0000cb9013e0
x23: 0000000000000003 x22: 0000000000000000 x21: ffff800012f9b9a0
x20: 0000000000000000 x19: ffff0000cb901358 x18: 00000000000000c0
x17: ffff80000dda8198 x16: 0000000000000000 x15: 0000000000000000
x14: 0000000000000000 x13: 0000000000000004 x12: ffff80000d51b008
x11: ff80800008903460 x10: 0000000000000000 x9 : ffff800008903460
x8 : ffff0000c4048000 x7 : ffff80000862d114 x6 : 0000000000000000
x5 : 0000000000000000 x4 : 0000000000000001 x3 : 0000000000000000
x2 : 0000000000000001 x1 : ffff80000d51afe0 x0 : 0000000000000000
Call trace:
 hfs_write_inode+0x44c/0x450 fs/hfs/inode.c:446
 write_inode fs/fs-writeback.c:1440 [inline]
 __writeback_single_inode+0x240/0x2e4 fs/fs-writeback.c:1652
 writeback_sb_inodes+0x3e4/0x85c fs/fs-writeback.c:1870
 wb_writeback+0x198/0x328 fs/fs-writeback.c:2044
 wb_do_writeback+0xc8/0x384 fs/fs-writeback.c:2187
 wb_workfn+0x70/0x15c fs/fs-writeback.c:2227
 process_one_work+0x2d8/0x504 kernel/workqueue.c:2289
 worker_thread+0x340/0x610 kernel/workqueue.c:2436
 kthread+0x12c/0x158 kernel/kthread.c:376
 ret_from_fork+0x10/0x20 arch/arm64/kernel/entry.S:863
Code: d4210000 17ffff98 94ddff99 97e6893f (d4210000) 
---[ end trace 0000000000000000 ]---


---
This report is generated by a bot. It may contain errors.
See https://goo.gl/tpsmEJ for more information about syzbot.
syzbot engineers can be reached at syzkaller@googlegroups.com.

syzbot will keep track of this issue. See:
https://goo.gl/tpsmEJ#status for how to communicate with syzbot.
syzbot can test patches for this issue, for details see:
https://goo.gl/tpsmEJ#testing-patches

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [syzbot] kernel BUG in hfs_write_inode
  2022-11-25  9:45 [syzbot] kernel BUG in hfs_write_inode syzbot
@ 2025-10-02 16:16 ` George Anthony Vernon
  2025-10-02 16:31   ` [syzbot] [hfs?] " syzbot
  2025-10-29  2:49 ` Forwarded: " syzbot
                   ` (7 subsequent siblings)
  8 siblings, 1 reply; 15+ messages in thread
From: George Anthony Vernon @ 2025-10-02 16:16 UTC (permalink / raw)
  To: syzbot
  Cc: damien.lemoal, jlayton, linux-fsdevel, linux-kernel,
	syzkaller-bugs, willy

On Fri, Nov 25, 2022 at 01:45:41AM -0800, syzbot wrote:
> Hello,
> 
> syzbot found the following issue on:
> 
> HEAD commit:    65762d97e6fa Merge branch 'for-next/perf' into for-kernelci
> git tree:       git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux.git for-kernelci
> console output: https://syzkaller.appspot.com/x/log.txt?x=14e324e3880000
> kernel config:  https://syzkaller.appspot.com/x/.config?x=56d0c7c3a2304e8f
> dashboard link: https://syzkaller.appspot.com/bug?extid=97e301b4b82ae803d21b
> compiler:       Debian clang version 13.0.1-++20220126092033+75e33f71c2da-1~exp1~20220126212112.63, GNU ld (GNU Binutils for Debian) 2.35.2
> userspace arch: arm64
> syz repro:      https://syzkaller.appspot.com/x/repro.syz?x=10983553880000
> C reproducer:   https://syzkaller.appspot.com/x/repro.c?x=13315ebb880000
> 
> Downloadable assets:
> disk image: https://storage.googleapis.com/syzbot-assets/52f702197b30/disk-65762d97.raw.xz
> vmlinux: https://storage.googleapis.com/syzbot-assets/72189c2789ce/vmlinux-65762d97.xz
> kernel image: https://storage.googleapis.com/syzbot-assets/ec0349196c98/Image-65762d97.gz.xz
> mounted in repro: https://storage.googleapis.com/syzbot-assets/6bfea2266b7f/mount_0.gz
> 
> IMPORTANT: if you fix the issue, please add the following tag to the commit:
> Reported-by: syzbot+97e301b4b82ae803d21b@syzkaller.appspotmail.com
> 

I simplified the reproducer previously while working on a patch for this bug and found it no longer reproduces on mainline. I just want to sanity check this by testing mainline with syzbot's repro:

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

Thanks,

George

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [syzbot] [hfs?] kernel BUG in hfs_write_inode
  2025-10-02 16:16 ` George Anthony Vernon
@ 2025-10-02 16:31   ` syzbot
  2025-10-02 23:55     ` George Anthony Vernon
  0 siblings, 1 reply; 15+ messages in thread
From: syzbot @ 2025-10-02 16:31 UTC (permalink / raw)
  To: contact, damien.lemoal, jlayton, linux-fsdevel, linux-kernel,
	syzkaller-bugs, willy

Hello,

syzbot has tested the proposed patch but the reproducer is still triggering an issue:
kernel BUG in hfs_write_inode

------------[ cut here ]------------
kernel BUG at fs/hfs/inode.c:444!
Oops: invalid opcode: 0000 [#1] SMP KASAN PTI
CPU: 1 UID: 0 PID: 1438 Comm: kworker/u8:9 Not tainted syzkaller #0 PREEMPT_{RT,(full)} 
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 08/18/2025
Workqueue: writeback wb_workfn (flush-7:0)
RIP: 0010:hfs_write_inode+0x7c8/0x7d0 fs/hfs/inode.c:444
Code: c1 40 c2 05 99 80 e1 07 80 c1 03 38 c1 0f 8c 7d fe ff ff 48 c7 c7 40 c2 05 99 e8 e3 dc 8c ff e9 6c fe ff ff e8 a9 96 2d ff 90 <0f> 0b 66 0f 1f 44 00 00 90 90 90 90 90 90 90 90 90 90 90 90 90 90
RSP: 0018:ffffc9000534f180 EFLAGS: 00010293
RAX: ffffffff8290d517 RBX: ffff8880323301c8 RCX: ffff88802787d940
RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000000
RBP: ffffc9000534f310 R08: ffff88802787d940 R09: 0000000000000003
R10: 0000000000000100 R11: 0000000000000004 R12: dffffc0000000000
R13: 1ffff92000a69e34 R14: ffff888032330188 R15: 0000000000000000
FS:  0000000000000000(0000) GS:ffff8881269bc000(0000) knlGS:0000000000000000
CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 00007ff2f4ecb000 CR3: 0000000036660000 CR4: 00000000003526f0
Call Trace:
 <TASK>
 write_inode fs/fs-writeback.c:1525 [inline]
 __writeback_single_inode+0x6f1/0x1000 fs/fs-writeback.c:1745
 writeback_sb_inodes+0x6b7/0xf60 fs/fs-writeback.c:1976
 wb_writeback+0x43b/0xaf0 fs/fs-writeback.c:2156
 wb_do_writeback fs/fs-writeback.c:2303 [inline]
 wb_workfn+0x40e/0xf00 fs/fs-writeback.c:2343
 process_one_work kernel/workqueue.c:3236 [inline]
 process_scheduled_works+0xae1/0x17b0 kernel/workqueue.c:3319
 worker_thread+0x8a0/0xda0 kernel/workqueue.c:3400
 kthread+0x711/0x8a0 kernel/kthread.c:463
 ret_from_fork+0x436/0x7d0 arch/x86/kernel/process.c:148
 ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245
 </TASK>
Modules linked in:
---[ end trace 0000000000000000 ]---
RIP: 0010:hfs_write_inode+0x7c8/0x7d0 fs/hfs/inode.c:444
Code: c1 40 c2 05 99 80 e1 07 80 c1 03 38 c1 0f 8c 7d fe ff ff 48 c7 c7 40 c2 05 99 e8 e3 dc 8c ff e9 6c fe ff ff e8 a9 96 2d ff 90 <0f> 0b 66 0f 1f 44 00 00 90 90 90 90 90 90 90 90 90 90 90 90 90 90
RSP: 0018:ffffc9000534f180 EFLAGS: 00010293
RAX: ffffffff8290d517 RBX: ffff8880323301c8 RCX: ffff88802787d940
RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000000
RBP: ffffc9000534f310 R08: ffff88802787d940 R09: 0000000000000003
R10: 0000000000000100 R11: 0000000000000004 R12: dffffc0000000000
R13: 1ffff92000a69e34 R14: ffff888032330188 R15: 0000000000000000
FS:  0000000000000000(0000) GS:ffff8881269bc000(0000) knlGS:0000000000000000
CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 00007ff2f4ecb000 CR3: 0000000036660000 CR4: 00000000003526f0


Tested on:

commit:         e5f0a698 Linux 6.17
git tree:       git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git v6.17
console output: https://syzkaller.appspot.com/x/log.txt?x=13b28458580000
kernel config:  https://syzkaller.appspot.com/x/.config?x=f5b21423ca3f0a96
dashboard link: https://syzkaller.appspot.com/bug?extid=97e301b4b82ae803d21b
compiler:       Debian clang version 20.1.8 (++20250708063551+0c9f909b7976-1~exp1~20250708183702.136), Debian LLD 20.1.8

Note: no patches were applied.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [syzbot] [hfs?] kernel BUG in hfs_write_inode
  2025-10-02 16:31   ` [syzbot] [hfs?] " syzbot
@ 2025-10-02 23:55     ` George Anthony Vernon
  2025-10-03  0:18       ` syzbot
  0 siblings, 1 reply; 15+ messages in thread
From: George Anthony Vernon @ 2025-10-02 23:55 UTC (permalink / raw)
  To: syzbot
  Cc: damien.lemoal, jlayton, linux-fsdevel, linux-kernel,
	syzkaller-bugs, willy

[-- Attachment #1: Type: text/plain, Size: 437 bytes --]

On Thu, Oct 02, 2025 at 09:31:03AM -0700, syzbot wrote:
> Hello,
> 
> syzbot has tested the proposed patch but the reproducer is still triggering an issue:
> kernel BUG in hfs_write_inode
> 
> ------------[ cut here ]------------
> kernel BUG at fs/hfs/inode.c:444!

Attaching a patch since I'm failing to reproduce locally on mainline.

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

Thanks,

George

[-- Attachment #2: 0001-hfs-Validate-CNIDs-in-hfs_read_inode.patch --]
[-- Type: text/plain, Size: 2353 bytes --]

From 40db09869bfabf51593f9a638aff09c72d9c8f1e Mon Sep 17 00:00:00 2001
From: George Anthony Vernon <contact@gvernon.com>
Date: Fri, 3 Oct 2025 00:32:06 +0100
Subject: [PATCH] hfs: Validate CNIDs in hfs_read_inode

hfs_read_inode previously did not validate CNIDs read from disk,
thereby allowing bad inodes to be placed on the dirty list and written
back.

Validate reserved CNIDs according to Apple technical note TN1150.

Reported-by: syzbot+97e301b4b82ae803d21b@syzkaller.appspotmail.com
Signed-off-by: George Anthony Vernon <contact@gvernon.com>
---
 fs/hfs/inode.c | 38 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 38 insertions(+)

diff --git a/fs/hfs/inode.c b/fs/hfs/inode.c
index a81ce7a740b9..ab71493cf501 100644
--- a/fs/hfs/inode.c
+++ b/fs/hfs/inode.c
@@ -310,6 +310,34 @@ static int hfs_test_inode(struct inode *inode, void *data)
 	}
 }
 
+/*
+ * is_valid_cnid
+ *
+ * Validate the catalog number of an inode read from disk
+ */
+static bool is_valid_cnid(unsigned long cnid, s8 type)
+{
+	if (likely(cnid >= HFS_FIRSTUSER_CNID))
+		return true;
+
+	switch (cnid) {
+	case HFS_POR_CNID:
+		return type == HFS_CDR_DIR;
+	case HFS_ROOT_CNID:
+		return type == HFS_CDR_DIR;
+	case HFS_EXT_CNID:
+		return type == HFS_CDR_FIL;
+	case HFS_CAT_CNID:
+		return type == HFS_CDR_FIL;
+	case HFS_BAD_CNID:
+		return type == HFS_CDR_FIL;
+	case HFS_EXCH_CNID:
+		return type == HFS_CDR_FIL;
+	default:
+		return false;
+	}
+}
+
 /*
  * hfs_read_inode
  */
@@ -348,6 +376,11 @@ static int hfs_read_inode(struct inode *inode, void *data)
 		}
 
 		inode->i_ino = be32_to_cpu(rec->file.FlNum);
+		if (!is_valid_cnid(inode->i_ino, HFS_CDR_FIL)) {
+			printk(KERN_WARNING "hfs: rejected cnid %lu\n", inode->i_ino);
+			make_bad_inode(inode);
+			break;
+		}
 		inode->i_mode = S_IRUGO | S_IXUGO;
 		if (!(rec->file.Flags & HFS_FIL_LOCK))
 			inode->i_mode |= S_IWUGO;
@@ -361,6 +394,11 @@ static int hfs_read_inode(struct inode *inode, void *data)
 		break;
 	case HFS_CDR_DIR:
 		inode->i_ino = be32_to_cpu(rec->dir.DirID);
+		if (!is_valid_cnid(inode->i_ino, HFS_CDR_DIR)) {
+			printk(KERN_WARNING "hfs: rejected cnid %lu\n", inode->i_ino);
+			make_bad_inode(inode);
+			break;
+		}
 		inode->i_size = be16_to_cpu(rec->dir.Val) + 2;
 		HFS_I(inode)->fs_blocks = 0;
 		inode->i_mode = S_IFDIR | (S_IRWXUGO & ~hsb->s_dir_umask);
-- 
2.50.1


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [syzbot] [hfs?] kernel BUG in hfs_write_inode
  2025-10-02 23:55     ` George Anthony Vernon
@ 2025-10-03  0:18       ` syzbot
  2025-10-03  1:03         ` George Anthony Vernon
  0 siblings, 1 reply; 15+ messages in thread
From: syzbot @ 2025-10-03  0:18 UTC (permalink / raw)
  To: contact, damien.lemoal, jlayton, linux-fsdevel, linux-kernel,
	syzkaller-bugs, willy

Hello,

syzbot has tested the proposed patch and the reproducer did not trigger any issue:

Reported-by: syzbot+97e301b4b82ae803d21b@syzkaller.appspotmail.com
Tested-by: syzbot+97e301b4b82ae803d21b@syzkaller.appspotmail.com

Tested on:

commit:         e5f0a698 Linux 6.17
git tree:       git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git v6.17
console output: https://syzkaller.appspot.com/x/log.txt?x=160acee2580000
kernel config:  https://syzkaller.appspot.com/x/.config?x=f5b21423ca3f0a96
dashboard link: https://syzkaller.appspot.com/bug?extid=97e301b4b82ae803d21b
compiler:       Debian clang version 20.1.8 (++20250708063551+0c9f909b7976-1~exp1~20250708183702.136), Debian LLD 20.1.8
patch:          https://syzkaller.appspot.com/x/patch.diff?x=11089334580000

Note: testing is done by a robot and is best-effort only.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [syzbot] [hfs?] kernel BUG in hfs_write_inode
  2025-10-03  0:18       ` syzbot
@ 2025-10-03  1:03         ` George Anthony Vernon
  2025-10-03  1:27           ` syzbot
  0 siblings, 1 reply; 15+ messages in thread
From: George Anthony Vernon @ 2025-10-03  1:03 UTC (permalink / raw)
  To: syzbot
  Cc: damien.lemoal, jlayton, linux-fsdevel, linux-kernel,
	syzkaller-bugs, willy

[-- Attachment #1: Type: text/plain, Size: 944 bytes --]

On Thu, Oct 02, 2025 at 05:18:03PM -0700, syzbot wrote:
> Hello,
> 
> syzbot has tested the proposed patch and the reproducer did not trigger any issue:
> 
> Reported-by: syzbot+97e301b4b82ae803d21b@syzkaller.appspotmail.com
> Tested-by: syzbot+97e301b4b82ae803d21b@syzkaller.appspotmail.com
> 
> Tested on:
> 
> commit:         e5f0a698 Linux 6.17
> git tree:       git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git v6.17
> console output: https://syzkaller.appspot.com/x/log.txt?x=160acee2580000
> kernel config:  https://syzkaller.appspot.com/x/.config?x=f5b21423ca3f0a96
> dashboard link: https://syzkaller.appspot.com/bug?extid=97e301b4b82ae803d21b
> compiler:       Debian clang version 20.1.8 (++20250708063551+0c9f909b7976-1~exp1~20250708183702.136), Debian LLD 20.1.8
> patch:          https://syzkaller.appspot.com/x/patch.diff?x=11089334580000
> 
> Note: testing is done by a robot and is best-effort only.

#syz test

[-- Attachment #2: 0001-hfs-Validate-CNIDs-in-hfs_read_inode.patch --]
[-- Type: text/plain, Size: 2490 bytes --]

From 5ff1f6bf582a643bce73f6a1c431bfe540f76b8a Mon Sep 17 00:00:00 2001
From: George Anthony Vernon <contact@gvernon.com>
Date: Fri, 3 Oct 2025 01:41:24 +0100
Subject: [PATCH] hfs: Validate CNIDs in hfs_read_inode

hfs_read_inode previously did not validate CNIDs read from disk, thereby
allowing bad inodes to be constructed and placed on the dirty list,
eventually hitting a bug on writeback.

Validate reserved CNIDs according to Apple technical note TN1150.

This issue was discussed on LKML previously:
https://lore.kernel.org/all/427fcb57-8424-4e52-9f21-7041b2c4ae5b@
I-love.SAKURA.ne.jp/T/

Reported-by: syzbot+97e301b4b82ae803d21b@syzkaller.appspotmail.com
Signed-off-by: George Anthony Vernon <contact@gvernon.com>
---
 fs/hfs/inode.c | 38 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 38 insertions(+)

diff --git a/fs/hfs/inode.c b/fs/hfs/inode.c
index 9cd449913dc8..da6a6b32d8c2 100644
--- a/fs/hfs/inode.c
+++ b/fs/hfs/inode.c
@@ -321,6 +321,34 @@ static int hfs_test_inode(struct inode *inode, void *data)
 	}
 }
 
+/*
+ * is_valid_cnid
+ *
+ * Validate the CNID of a catalog record read from disk
+ */
+static bool is_valid_cnid(unsigned long cnid, s8 type)
+{
+	if (likely(cnid >= HFS_FIRSTUSER_CNID))
+		return true;
+
+	switch (cnid) {
+	case HFS_POR_CNID:
+		return type == HFS_CDR_DIR;
+	case HFS_ROOT_CNID:
+		return type == HFS_CDR_DIR;
+	case HFS_EXT_CNID:
+		return type == HFS_CDR_FIL;
+	case HFS_CAT_CNID:
+		return type == HFS_CDR_FIL;
+	case HFS_BAD_CNID:
+		return type == HFS_CDR_FIL;
+	case HFS_EXCH_CNID:
+		return type == HFS_CDR_FIL;
+	default:
+		return false;
+	}
+}
+
 /*
  * hfs_read_inode
  */
@@ -359,6 +387,11 @@ static int hfs_read_inode(struct inode *inode, void *data)
 		}
 
 		inode->i_ino = be32_to_cpu(rec->file.FlNum);
+		if (!is_valid_cnid(inode->i_ino, HFS_CDR_FIL)) {
+			pr_warn("rejected cnid %lu\n", inode->i_ino);
+			make_bad_inode(inode);
+			break;
+		}
 		inode->i_mode = S_IRUGO | S_IXUGO;
 		if (!(rec->file.Flags & HFS_FIL_LOCK))
 			inode->i_mode |= S_IWUGO;
@@ -372,6 +405,11 @@ static int hfs_read_inode(struct inode *inode, void *data)
 		break;
 	case HFS_CDR_DIR:
 		inode->i_ino = be32_to_cpu(rec->dir.DirID);
+		if (!is_valid_cnid(inode->i_ino, HFS_CDR_DIR)) {
+			pr_warn("rejected cnid %lu\n", inode->i_ino);
+			make_bad_inode(inode);
+			break;
+		}
 		inode->i_size = be16_to_cpu(rec->dir.Val) + 2;
 		HFS_I(inode)->fs_blocks = 0;
 		inode->i_mode = S_IFDIR | (S_IRWXUGO & ~hsb->s_dir_umask);
-- 
2.50.1


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [syzbot] [hfs?] kernel BUG in hfs_write_inode
  2025-10-03  1:03         ` George Anthony Vernon
@ 2025-10-03  1:27           ` syzbot
  0 siblings, 0 replies; 15+ messages in thread
From: syzbot @ 2025-10-03  1:27 UTC (permalink / raw)
  To: contact, damien.lemoal, jlayton, linux-fsdevel, linux-kernel,
	syzkaller-bugs, willy

Hello,

syzbot has tested the proposed patch and the reproducer did not trigger any issue:

Reported-by: syzbot+97e301b4b82ae803d21b@syzkaller.appspotmail.com
Tested-by: syzbot+97e301b4b82ae803d21b@syzkaller.appspotmail.com

Tested on:

commit:         24d9e8b3 Merge tag 'slab-for-6.18' of git://git.kernel..
git tree:       upstream
console output: https://syzkaller.appspot.com/x/log.txt?x=1472aa7c580000
kernel config:  https://syzkaller.appspot.com/x/.config?x=e9442f6915cec8b7
dashboard link: https://syzkaller.appspot.com/bug?extid=97e301b4b82ae803d21b
compiler:       Debian clang version 20.1.8 (++20250708063551+0c9f909b7976-1~exp1~20250708183702.136), Debian LLD 20.1.8
patch:          https://syzkaller.appspot.com/x/patch.diff?x=13c8d942580000

Note: testing is done by a robot and is best-effort only.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Forwarded: Re: [syzbot] [hfs?] kernel BUG in hfs_write_inode
  2022-11-25  9:45 [syzbot] kernel BUG in hfs_write_inode syzbot
  2025-10-02 16:16 ` George Anthony Vernon
@ 2025-10-29  2:49 ` syzbot
  2026-03-09 23:04 ` Forwarded: syzbot
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 15+ messages in thread
From: syzbot @ 2025-10-29  2:49 UTC (permalink / raw)
  To: linux-kernel, syzkaller-bugs

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

***

Subject: Re: [syzbot] [hfs?] kernel BUG in hfs_write_inode
Author: contact@gvernon.com

On Tue, Oct 28, 2025 at 07:47:05PM -0700, syzbot wrote:
> want either no args or 2 args (repo, branch), got 1

#syz test

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Forwarded:
  2022-11-25  9:45 [syzbot] kernel BUG in hfs_write_inode syzbot
  2025-10-02 16:16 ` George Anthony Vernon
  2025-10-29  2:49 ` Forwarded: " syzbot
@ 2026-03-09 23:04 ` syzbot
  2026-03-11 20:48 ` Forwarded: Re: [syzbot] [hfs?] kernel BUG in hfs_write_inode syzbot
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 15+ messages in thread
From: syzbot @ 2026-03-09 23:04 UTC (permalink / raw)
  To: linux-kernel, syzkaller-bugs

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

***

Subject: 
Author: contact@gvernon.com

#syz test

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Forwarded: Re: [syzbot] [hfs?] kernel BUG in hfs_write_inode
  2022-11-25  9:45 [syzbot] kernel BUG in hfs_write_inode syzbot
                   ` (2 preceding siblings ...)
  2026-03-09 23:04 ` Forwarded: syzbot
@ 2026-03-11 20:48 ` syzbot
  2026-03-28 12:51 ` syzbot
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 15+ messages in thread
From: syzbot @ 2026-03-11 20:48 UTC (permalink / raw)
  To: linux-kernel, syzkaller-bugs

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

***

Subject: Re: [syzbot] [hfs?] kernel BUG in hfs_write_inode
Author: contact@gvernon.com

#syz test

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Forwarded: Re: [syzbot] [hfs?] kernel BUG in hfs_write_inode
  2022-11-25  9:45 [syzbot] kernel BUG in hfs_write_inode syzbot
                   ` (3 preceding siblings ...)
  2026-03-11 20:48 ` Forwarded: Re: [syzbot] [hfs?] kernel BUG in hfs_write_inode syzbot
@ 2026-03-28 12:51 ` syzbot
  2026-03-29 18:51 ` syzbot
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 15+ messages in thread
From: syzbot @ 2026-03-28 12:51 UTC (permalink / raw)
  To: linux-kernel, syzkaller-bugs

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

***

Subject: Re: [syzbot] [hfs?] kernel BUG in hfs_write_inode
Author: contact@gvernon.com

#syz test

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Forwarded: Re: [syzbot] [hfs?] kernel BUG in hfs_write_inode
  2022-11-25  9:45 [syzbot] kernel BUG in hfs_write_inode syzbot
                   ` (4 preceding siblings ...)
  2026-03-28 12:51 ` syzbot
@ 2026-03-29 18:51 ` syzbot
  2026-07-02  5:11 ` Forwarded: [PATCH] hfs: validate catalog CNIDs before instantiating inodes syzbot
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 15+ messages in thread
From: syzbot @ 2026-03-29 18:51 UTC (permalink / raw)
  To: linux-kernel, syzkaller-bugs

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

***

Subject: Re: [syzbot] [hfs?] kernel BUG in hfs_write_inode
Author: contact@gvernon.com

#syz test

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Forwarded: [PATCH] hfs: validate catalog CNIDs before instantiating inodes
  2022-11-25  9:45 [syzbot] kernel BUG in hfs_write_inode syzbot
                   ` (5 preceding siblings ...)
  2026-03-29 18:51 ` syzbot
@ 2026-07-02  5:11 ` syzbot
  2026-07-02  6:28 ` syzbot
  2026-07-02 14:38 ` syzbot
  8 siblings, 0 replies; 15+ messages in thread
From: syzbot @ 2026-07-02  5:11 UTC (permalink / raw)
  To: linux-kernel

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

***

Subject: [PATCH] hfs: validate catalog CNIDs before instantiating inodes
Author: davemadmaxxx@gmail.com

hfs_cat_find_brec() first resolves a catalog thread record by CNID and
then looks up the corresponding catalog record by parent/name. On a
corrupted filesystem image, the second lookup may find a record whose
CNID does not match the CNID that was requested.

Validate the catalog record found by the second lookup before returning
it to callers. Inspect the already-found record with hfs_bnode_read(),
not hfs_brec_read(), and reject records whose CNID is invalid for their
record type or does not match the requested CNID.

Also validate CNIDs in hfs_read_inode() before the inode is populated,
and propagate hfs_read_inode() errors from the resource-fork lookup path.
For the root inode path, require the root catalog record to be a directory
with DirID == HFS_ROOT_CNID, and drop the root inode reference if it was
instantiated as a bad inode.

This keeps hfs_write_inode() unchanged and prevents corrupted catalog
records from reaching the existing reserved-CNID BUG() path during
writeback.

Reported-by: syzbot+97e301b4b82ae803d21b@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=97e301b4b82ae803d21b
Cc: George Anthony Vernon <contact@gvernon.com>
Cc: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Signed-off-by: David Maximiliano Hermitte <davemadmaxxx@gmail.com>
#syz test: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git master
---
 fs/hfs/catalog.c | 48 +++++++++++++++++++++++++++++++++++++++++++++++-
 fs/hfs/hfs_fs.h  | 19 +++++++++++++++++++
 fs/hfs/inode.c   |  9 ++++++++-
 fs/hfs/super.c   |  8 +++++++-
 4 files changed, 81 insertions(+), 3 deletions(-)

diff --git a/fs/hfs/catalog.c b/fs/hfs/catalog.c
index 1bfa36d71e24..fa2a0a5975e3 100644
--- a/fs/hfs/catalog.c
+++ b/fs/hfs/catalog.c
@@ -182,6 +182,47 @@ int hfs_cat_keycmp(const btree_key *key1, const btree_key *key2)
 			  key2->cat.CName.name, key2->cat.CName.len);
 }
 
+static int hfs_cat_validate_found_cnid(struct hfs_find_data *fd, u32 cnid)
+{
+	hfs_cat_rec rec;
+	u32 found_cnid;
+	unsigned int rec_len;
+	size_t cnid_off;
+
+	if (fd->entrylength <= 0)
+		return -EIO;
+
+	if ((unsigned int)fd->entrylength > sizeof(rec))
+		rec_len = sizeof(rec);
+	else
+		rec_len = fd->entrylength;
+
+	memset(&rec, 0, sizeof(rec));
+	hfs_bnode_read(fd->bnode, &rec, fd->entryoffset, rec_len);
+
+	switch (rec.type) {
+	case HFS_CDR_FIL:
+		cnid_off = offsetof(struct hfs_cat_file, FlNum);
+		if ((size_t)rec_len < cnid_off + sizeof(rec.file.FlNum))
+			return -EIO;
+		found_cnid = be32_to_cpu(rec.file.FlNum);
+		break;
+	case HFS_CDR_DIR:
+		cnid_off = offsetof(struct hfs_cat_dir, DirID);
+		if ((size_t)rec_len < cnid_off + sizeof(rec.dir.DirID))
+			return -EIO;
+		found_cnid = be32_to_cpu(rec.dir.DirID);
+		break;
+	default:
+		return -EIO;
+	}
+
+	if (!hfs_is_valid_cnid(found_cnid, rec.type) || found_cnid != cnid)
+		return -EIO;
+
+	return 0;
+}
+
 /* Try to get a catalog entry for given catalog id */
 // move to read_super???
 int hfs_cat_find_brec(struct super_block *sb, u32 cnid,
@@ -208,7 +249,12 @@ int hfs_cat_find_brec(struct super_block *sb, u32 cnid,
 		return -EIO;
 	}
 	memcpy(fd->search_key->cat.CName.name, rec.thread.CName.name, len);
-	return hfs_brec_find(fd);
+
+	res = hfs_brec_find(fd);
+	if (res)
+		return res;
+
+	return hfs_cat_validate_found_cnid(fd, cnid);
 }
 
 static inline
diff --git a/fs/hfs/hfs_fs.h b/fs/hfs/hfs_fs.h
index f3624514fcb0..670638f17438 100644
--- a/fs/hfs/hfs_fs.h
+++ b/fs/hfs/hfs_fs.h
@@ -155,6 +155,25 @@ extern int hfs_cat_move(u32 cnid, struct inode *src_dir,
 extern void hfs_cat_build_key(struct super_block *sb, btree_key *key,
 			      u32 parent, const struct qstr *name);
 
+/*
+ * Validate the CNID of a catalog record.
+ */
+static inline bool hfs_is_valid_cnid(u32 cnid, u8 type)
+{
+	if (likely(cnid >= HFS_FIRSTUSER_CNID))
+		return true;
+
+	switch (cnid) {
+	case HFS_ROOT_CNID:
+		return type == HFS_CDR_DIR;
+	case HFS_EXT_CNID:
+	case HFS_CAT_CNID:
+		return type == HFS_CDR_FIL;
+	default:
+		return false;
+	}
+}
+
 /* dir.c */
 extern const struct file_operations hfs_dir_operations;
 extern const struct inode_operations hfs_dir_inode_operations;
diff --git a/fs/hfs/inode.c b/fs/hfs/inode.c
index ac4a9055c5c0..c685f1bb7009 100644
--- a/fs/hfs/inode.c
+++ b/fs/hfs/inode.c
@@ -367,6 +367,9 @@ static int hfs_read_inode(struct inode *inode, void *data)
 	rec = idata->rec;
 	switch (rec->type) {
 	case HFS_CDR_FIL:
+		if (!hfs_is_valid_cnid(be32_to_cpu(rec->file.FlNum), rec->type))
+			return -EIO;
+
 		if (!HFS_IS_RSRC(inode)) {
 			hfs_inode_read_fork(inode, rec->file.ExtRec, rec->file.LgLen,
 					    rec->file.PyLen, be16_to_cpu(rec->file.ClpSize));
@@ -390,6 +393,9 @@ static int hfs_read_inode(struct inode *inode, void *data)
 		inode->i_mapping->a_ops = &hfs_aops;
 		break;
 	case HFS_CDR_DIR:
+		if (!hfs_is_valid_cnid(be32_to_cpu(rec->dir.DirID), rec->type))
+			return -EIO;
+
 		inode->i_ino = be32_to_cpu(rec->dir.DirID);
 		inode->i_size = be16_to_cpu(rec->dir.Val) + 2;
 		HFS_I(inode)->fs_blocks = 0;
@@ -571,7 +577,8 @@ static struct dentry *hfs_file_lookup(struct inode *dir, struct dentry *dentry,
 	res = hfs_brec_read(&fd, &rec, sizeof(rec));
 	if (!res) {
 		struct hfs_iget_data idata = { NULL, &rec };
-		hfs_read_inode(inode, &idata);
+
+		res = hfs_read_inode(inode, &idata);
 	}
 	hfs_find_exit(&fd);
 	if (res) {
diff --git a/fs/hfs/super.c b/fs/hfs/super.c
index a466c401f6bb..5275936304c7 100644
--- a/fs/hfs/super.c
+++ b/fs/hfs/super.c
@@ -361,7 +361,8 @@ static int hfs_fill_super(struct super_block *sb, struct fs_context *fc)
 			goto bail_hfs_find;
 		}
 		hfs_bnode_read(fd.bnode, &rec, fd.entryoffset, fd.entrylength);
-		if (rec.type != HFS_CDR_DIR)
+		if (rec.type != HFS_CDR_DIR ||
+		    be32_to_cpu(rec.dir.DirID) != HFS_ROOT_CNID)
 			res = -EIO;
 	}
 	if (res)
@@ -372,6 +373,11 @@ static int hfs_fill_super(struct super_block *sb, struct fs_context *fc)
 	if (!root_inode)
 		goto bail_no_root;
 
+	if (is_bad_inode(root_inode)) {
+		iput(root_inode);
+		goto bail_no_root;
+	}
+
 	set_default_d_op(sb, &hfs_dentry_operations);
 	res = -ENOMEM;
 	sb->s_root = d_make_root(root_inode);
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Forwarded: [PATCH] hfs: validate catalog CNIDs before instantiating inodes
  2022-11-25  9:45 [syzbot] kernel BUG in hfs_write_inode syzbot
                   ` (6 preceding siblings ...)
  2026-07-02  5:11 ` Forwarded: [PATCH] hfs: validate catalog CNIDs before instantiating inodes syzbot
@ 2026-07-02  6:28 ` syzbot
  2026-07-02 14:38 ` syzbot
  8 siblings, 0 replies; 15+ messages in thread
From: syzbot @ 2026-07-02  6:28 UTC (permalink / raw)
  To: linux-kernel

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

***

Subject: [PATCH] hfs: validate catalog CNIDs before instantiating inodes
Author: davemadmaxxx@gmail.com

hfs_cat_find_brec() first resolves a catalog thread record by CNID and
then looks up the corresponding catalog record by parent/name. On a
corrupted filesystem image, the second lookup may find a record whose
CNID does not match the CNID that was requested.

Validate the catalog record found by the second lookup before returning
it to callers. Inspect the already-found record with hfs_bnode_read(),
not hfs_brec_read(), and reject records whose CNID is invalid for their
record type or does not match the requested CNID.

Also validate CNIDs in hfs_read_inode() before the inode is populated,
and propagate hfs_read_inode() errors from the resource-fork lookup path.
For the root inode path, require the root catalog record to be a directory
with DirID == HFS_ROOT_CNID, and drop the root inode reference if it was
instantiated as a bad inode.

This keeps hfs_write_inode() unchanged and prevents corrupted catalog
records from reaching the existing reserved-CNID BUG() path during
writeback.

Reported-by: syzbot+97e301b4b82ae803d21b@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=97e301b4b82ae803d21b
Cc: George Anthony Vernon <contact@gvernon.com>
Cc: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Signed-off-by: David Maximiliano Hermitte <davemadmaxxx@gmail.com>
#syz test: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git master

Please retest this HFS patch on current upstream master. The previous syzbot run ended with "lost connection to test machine".
---
 fs/hfs/catalog.c | 48 +++++++++++++++++++++++++++++++++++++++++++++++-
 fs/hfs/hfs_fs.h  | 19 +++++++++++++++++++
 fs/hfs/inode.c   |  9 ++++++++-
 fs/hfs/super.c   |  8 +++++++-
 4 files changed, 81 insertions(+), 3 deletions(-)

diff --git a/fs/hfs/catalog.c b/fs/hfs/catalog.c
index 1bfa36d71e24..fa2a0a5975e3 100644
--- a/fs/hfs/catalog.c
+++ b/fs/hfs/catalog.c
@@ -182,6 +182,47 @@ int hfs_cat_keycmp(const btree_key *key1, const btree_key *key2)
 			  key2->cat.CName.name, key2->cat.CName.len);
 }
 
+static int hfs_cat_validate_found_cnid(struct hfs_find_data *fd, u32 cnid)
+{
+	hfs_cat_rec rec;
+	u32 found_cnid;
+	unsigned int rec_len;
+	size_t cnid_off;
+
+	if (fd->entrylength <= 0)
+		return -EIO;
+
+	if ((unsigned int)fd->entrylength > sizeof(rec))
+		rec_len = sizeof(rec);
+	else
+		rec_len = fd->entrylength;
+
+	memset(&rec, 0, sizeof(rec));
+	hfs_bnode_read(fd->bnode, &rec, fd->entryoffset, rec_len);
+
+	switch (rec.type) {
+	case HFS_CDR_FIL:
+		cnid_off = offsetof(struct hfs_cat_file, FlNum);
+		if ((size_t)rec_len < cnid_off + sizeof(rec.file.FlNum))
+			return -EIO;
+		found_cnid = be32_to_cpu(rec.file.FlNum);
+		break;
+	case HFS_CDR_DIR:
+		cnid_off = offsetof(struct hfs_cat_dir, DirID);
+		if ((size_t)rec_len < cnid_off + sizeof(rec.dir.DirID))
+			return -EIO;
+		found_cnid = be32_to_cpu(rec.dir.DirID);
+		break;
+	default:
+		return -EIO;
+	}
+
+	if (!hfs_is_valid_cnid(found_cnid, rec.type) || found_cnid != cnid)
+		return -EIO;
+
+	return 0;
+}
+
 /* Try to get a catalog entry for given catalog id */
 // move to read_super???
 int hfs_cat_find_brec(struct super_block *sb, u32 cnid,
@@ -208,7 +249,12 @@ int hfs_cat_find_brec(struct super_block *sb, u32 cnid,
 		return -EIO;
 	}
 	memcpy(fd->search_key->cat.CName.name, rec.thread.CName.name, len);
-	return hfs_brec_find(fd);
+
+	res = hfs_brec_find(fd);
+	if (res)
+		return res;
+
+	return hfs_cat_validate_found_cnid(fd, cnid);
 }
 
 static inline
diff --git a/fs/hfs/hfs_fs.h b/fs/hfs/hfs_fs.h
index f3624514fcb0..670638f17438 100644
--- a/fs/hfs/hfs_fs.h
+++ b/fs/hfs/hfs_fs.h
@@ -155,6 +155,25 @@ extern int hfs_cat_move(u32 cnid, struct inode *src_dir,
 extern void hfs_cat_build_key(struct super_block *sb, btree_key *key,
 			      u32 parent, const struct qstr *name);
 
+/*
+ * Validate the CNID of a catalog record.
+ */
+static inline bool hfs_is_valid_cnid(u32 cnid, u8 type)
+{
+	if (likely(cnid >= HFS_FIRSTUSER_CNID))
+		return true;
+
+	switch (cnid) {
+	case HFS_ROOT_CNID:
+		return type == HFS_CDR_DIR;
+	case HFS_EXT_CNID:
+	case HFS_CAT_CNID:
+		return type == HFS_CDR_FIL;
+	default:
+		return false;
+	}
+}
+
 /* dir.c */
 extern const struct file_operations hfs_dir_operations;
 extern const struct inode_operations hfs_dir_inode_operations;
diff --git a/fs/hfs/inode.c b/fs/hfs/inode.c
index ac4a9055c5c0..c685f1bb7009 100644
--- a/fs/hfs/inode.c
+++ b/fs/hfs/inode.c
@@ -367,6 +367,9 @@ static int hfs_read_inode(struct inode *inode, void *data)
 	rec = idata->rec;
 	switch (rec->type) {
 	case HFS_CDR_FIL:
+		if (!hfs_is_valid_cnid(be32_to_cpu(rec->file.FlNum), rec->type))
+			return -EIO;
+
 		if (!HFS_IS_RSRC(inode)) {
 			hfs_inode_read_fork(inode, rec->file.ExtRec, rec->file.LgLen,
 					    rec->file.PyLen, be16_to_cpu(rec->file.ClpSize));
@@ -390,6 +393,9 @@ static int hfs_read_inode(struct inode *inode, void *data)
 		inode->i_mapping->a_ops = &hfs_aops;
 		break;
 	case HFS_CDR_DIR:
+		if (!hfs_is_valid_cnid(be32_to_cpu(rec->dir.DirID), rec->type))
+			return -EIO;
+
 		inode->i_ino = be32_to_cpu(rec->dir.DirID);
 		inode->i_size = be16_to_cpu(rec->dir.Val) + 2;
 		HFS_I(inode)->fs_blocks = 0;
@@ -571,7 +577,8 @@ static struct dentry *hfs_file_lookup(struct inode *dir, struct dentry *dentry,
 	res = hfs_brec_read(&fd, &rec, sizeof(rec));
 	if (!res) {
 		struct hfs_iget_data idata = { NULL, &rec };
-		hfs_read_inode(inode, &idata);
+
+		res = hfs_read_inode(inode, &idata);
 	}
 	hfs_find_exit(&fd);
 	if (res) {
diff --git a/fs/hfs/super.c b/fs/hfs/super.c
index a466c401f6bb..5275936304c7 100644
--- a/fs/hfs/super.c
+++ b/fs/hfs/super.c
@@ -361,7 +361,8 @@ static int hfs_fill_super(struct super_block *sb, struct fs_context *fc)
 			goto bail_hfs_find;
 		}
 		hfs_bnode_read(fd.bnode, &rec, fd.entryoffset, fd.entrylength);
-		if (rec.type != HFS_CDR_DIR)
+		if (rec.type != HFS_CDR_DIR ||
+		    be32_to_cpu(rec.dir.DirID) != HFS_ROOT_CNID)
 			res = -EIO;
 	}
 	if (res)
@@ -372,6 +373,11 @@ static int hfs_fill_super(struct super_block *sb, struct fs_context *fc)
 	if (!root_inode)
 		goto bail_no_root;
 
+	if (is_bad_inode(root_inode)) {
+		iput(root_inode);
+		goto bail_no_root;
+	}
+
 	set_default_d_op(sb, &hfs_dentry_operations);
 	res = -ENOMEM;
 	sb->s_root = d_make_root(root_inode);
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Forwarded: [PATCH] hfs: validate catalog CNIDs before instantiating inodes
  2022-11-25  9:45 [syzbot] kernel BUG in hfs_write_inode syzbot
                   ` (7 preceding siblings ...)
  2026-07-02  6:28 ` syzbot
@ 2026-07-02 14:38 ` syzbot
  8 siblings, 0 replies; 15+ messages in thread
From: syzbot @ 2026-07-02 14:38 UTC (permalink / raw)
  To: linux-kernel

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

***

Subject: [PATCH] hfs: validate catalog CNIDs before instantiating inodes
Author: davemadmaxxx@gmail.com

hfs_cat_find_brec() first resolves a catalog thread record by CNID and
then looks up the corresponding catalog record by parent/name. On a
corrupted filesystem image, the second lookup may find a record whose
CNID does not match the CNID that was requested.

Validate the catalog record found by the second lookup before returning
it to callers. Inspect the already-found record with hfs_bnode_read(),
not hfs_brec_read(), and reject records whose CNID is invalid for their
record type or does not match the requested CNID.

Also validate CNIDs in hfs_read_inode() before the inode is populated,
and propagate hfs_read_inode() errors from the resource-fork lookup path.
For the root inode path, require the root catalog record to be a directory
with DirID == HFS_ROOT_CNID, and drop the root inode reference if it was
instantiated as a bad inode.

This keeps hfs_write_inode() unchanged and prevents corrupted catalog
records from reaching the existing reserved-CNID BUG() path during
writeback.

Reported-by: syzbot+97e301b4b82ae803d21b@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=97e301b4b82ae803d21b
Cc: George Anthony Vernon <contact@gvernon.com>
Cc: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Signed-off-by: David Maximiliano Hermitte <davemadmaxxx@gmail.com>
#syz test: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git master
---
 fs/hfs/catalog.c | 48 +++++++++++++++++++++++++++++++++++++++++++++++-
 fs/hfs/hfs_fs.h  | 19 +++++++++++++++++++
 fs/hfs/inode.c   |  9 ++++++++-
 fs/hfs/super.c   |  8 +++++++-
 4 files changed, 81 insertions(+), 3 deletions(-)

diff --git a/fs/hfs/catalog.c b/fs/hfs/catalog.c
index 1bfa36d71e24..fa2a0a5975e3 100644
--- a/fs/hfs/catalog.c
+++ b/fs/hfs/catalog.c
@@ -182,6 +182,47 @@ int hfs_cat_keycmp(const btree_key *key1, const btree_key *key2)
 			  key2->cat.CName.name, key2->cat.CName.len);
 }
 
+static int hfs_cat_validate_found_cnid(struct hfs_find_data *fd, u32 cnid)
+{
+	hfs_cat_rec rec;
+	u32 found_cnid;
+	unsigned int rec_len;
+	size_t cnid_off;
+
+	if (fd->entrylength <= 0)
+		return -EIO;
+
+	if ((unsigned int)fd->entrylength > sizeof(rec))
+		rec_len = sizeof(rec);
+	else
+		rec_len = fd->entrylength;
+
+	memset(&rec, 0, sizeof(rec));
+	hfs_bnode_read(fd->bnode, &rec, fd->entryoffset, rec_len);
+
+	switch (rec.type) {
+	case HFS_CDR_FIL:
+		cnid_off = offsetof(struct hfs_cat_file, FlNum);
+		if ((size_t)rec_len < cnid_off + sizeof(rec.file.FlNum))
+			return -EIO;
+		found_cnid = be32_to_cpu(rec.file.FlNum);
+		break;
+	case HFS_CDR_DIR:
+		cnid_off = offsetof(struct hfs_cat_dir, DirID);
+		if ((size_t)rec_len < cnid_off + sizeof(rec.dir.DirID))
+			return -EIO;
+		found_cnid = be32_to_cpu(rec.dir.DirID);
+		break;
+	default:
+		return -EIO;
+	}
+
+	if (!hfs_is_valid_cnid(found_cnid, rec.type) || found_cnid != cnid)
+		return -EIO;
+
+	return 0;
+}
+
 /* Try to get a catalog entry for given catalog id */
 // move to read_super???
 int hfs_cat_find_brec(struct super_block *sb, u32 cnid,
@@ -208,7 +249,12 @@ int hfs_cat_find_brec(struct super_block *sb, u32 cnid,
 		return -EIO;
 	}
 	memcpy(fd->search_key->cat.CName.name, rec.thread.CName.name, len);
-	return hfs_brec_find(fd);
+
+	res = hfs_brec_find(fd);
+	if (res)
+		return res;
+
+	return hfs_cat_validate_found_cnid(fd, cnid);
 }
 
 static inline
diff --git a/fs/hfs/hfs_fs.h b/fs/hfs/hfs_fs.h
index f3624514fcb0..670638f17438 100644
--- a/fs/hfs/hfs_fs.h
+++ b/fs/hfs/hfs_fs.h
@@ -155,6 +155,25 @@ extern int hfs_cat_move(u32 cnid, struct inode *src_dir,
 extern void hfs_cat_build_key(struct super_block *sb, btree_key *key,
 			      u32 parent, const struct qstr *name);
 
+/*
+ * Validate the CNID of a catalog record.
+ */
+static inline bool hfs_is_valid_cnid(u32 cnid, u8 type)
+{
+	if (likely(cnid >= HFS_FIRSTUSER_CNID))
+		return true;
+
+	switch (cnid) {
+	case HFS_ROOT_CNID:
+		return type == HFS_CDR_DIR;
+	case HFS_EXT_CNID:
+	case HFS_CAT_CNID:
+		return type == HFS_CDR_FIL;
+	default:
+		return false;
+	}
+}
+
 /* dir.c */
 extern const struct file_operations hfs_dir_operations;
 extern const struct inode_operations hfs_dir_inode_operations;
diff --git a/fs/hfs/inode.c b/fs/hfs/inode.c
index ac4a9055c5c0..c685f1bb7009 100644
--- a/fs/hfs/inode.c
+++ b/fs/hfs/inode.c
@@ -367,6 +367,9 @@ static int hfs_read_inode(struct inode *inode, void *data)
 	rec = idata->rec;
 	switch (rec->type) {
 	case HFS_CDR_FIL:
+		if (!hfs_is_valid_cnid(be32_to_cpu(rec->file.FlNum), rec->type))
+			return -EIO;
+
 		if (!HFS_IS_RSRC(inode)) {
 			hfs_inode_read_fork(inode, rec->file.ExtRec, rec->file.LgLen,
 					    rec->file.PyLen, be16_to_cpu(rec->file.ClpSize));
@@ -390,6 +393,9 @@ static int hfs_read_inode(struct inode *inode, void *data)
 		inode->i_mapping->a_ops = &hfs_aops;
 		break;
 	case HFS_CDR_DIR:
+		if (!hfs_is_valid_cnid(be32_to_cpu(rec->dir.DirID), rec->type))
+			return -EIO;
+
 		inode->i_ino = be32_to_cpu(rec->dir.DirID);
 		inode->i_size = be16_to_cpu(rec->dir.Val) + 2;
 		HFS_I(inode)->fs_blocks = 0;
@@ -571,7 +577,8 @@ static struct dentry *hfs_file_lookup(struct inode *dir, struct dentry *dentry,
 	res = hfs_brec_read(&fd, &rec, sizeof(rec));
 	if (!res) {
 		struct hfs_iget_data idata = { NULL, &rec };
-		hfs_read_inode(inode, &idata);
+
+		res = hfs_read_inode(inode, &idata);
 	}
 	hfs_find_exit(&fd);
 	if (res) {
diff --git a/fs/hfs/super.c b/fs/hfs/super.c
index a466c401f6bb..5275936304c7 100644
--- a/fs/hfs/super.c
+++ b/fs/hfs/super.c
@@ -361,7 +361,8 @@ static int hfs_fill_super(struct super_block *sb, struct fs_context *fc)
 			goto bail_hfs_find;
 		}
 		hfs_bnode_read(fd.bnode, &rec, fd.entryoffset, fd.entrylength);
-		if (rec.type != HFS_CDR_DIR)
+		if (rec.type != HFS_CDR_DIR ||
+		    be32_to_cpu(rec.dir.DirID) != HFS_ROOT_CNID)
 			res = -EIO;
 	}
 	if (res)
@@ -372,6 +373,11 @@ static int hfs_fill_super(struct super_block *sb, struct fs_context *fc)
 	if (!root_inode)
 		goto bail_no_root;
 
+	if (is_bad_inode(root_inode)) {
+		iput(root_inode);
+		goto bail_no_root;
+	}
+
 	set_default_d_op(sb, &hfs_dentry_operations);
 	res = -ENOMEM;
 	sb->s_root = d_make_root(root_inode);
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2026-07-02 14:38 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2022-11-25  9:45 [syzbot] kernel BUG in hfs_write_inode syzbot
2025-10-02 16:16 ` George Anthony Vernon
2025-10-02 16:31   ` [syzbot] [hfs?] " syzbot
2025-10-02 23:55     ` George Anthony Vernon
2025-10-03  0:18       ` syzbot
2025-10-03  1:03         ` George Anthony Vernon
2025-10-03  1:27           ` syzbot
2025-10-29  2:49 ` Forwarded: " syzbot
2026-03-09 23:04 ` Forwarded: syzbot
2026-03-11 20:48 ` Forwarded: Re: [syzbot] [hfs?] kernel BUG in hfs_write_inode syzbot
2026-03-28 12:51 ` syzbot
2026-03-29 18:51 ` syzbot
2026-07-02  5:11 ` Forwarded: [PATCH] hfs: validate catalog CNIDs before instantiating inodes syzbot
2026-07-02  6:28 ` syzbot
2026-07-02 14:38 ` syzbot

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox