lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [day] [month] [year] [list]
Message-Id: <20260131140438.2296273-1-shardul.b@mpiricsoftware.com>
Date: Sat, 31 Jan 2026 19:34:38 +0530
From: Shardul Bankar <shardulsb08@...il.com>
To: slava@...eyko.com,
	glaubitz@...sik.fu-berlin.de,
	frank.li@...o.com,
	linux-fsdevel@...r.kernel.org,
	linux-kernel@...r.kernel.org
Cc: janak@...ricsoftware.com,
	shardulsb08@...il.com,
	Shardul Bankar <shardul.b@...ricsoftware.com>,
	syzbot+1c8ff72d0cd8a50dfeaa@...kaller.appspotmail.com
Subject: [PATCH v3] hfsplus: validate btree bitmap during mount and handle corruption gracefully

Add bitmap validation during HFS+ btree open to detect corruption where
node 0 (header node) is not marked allocated.

Syzkaller reported issues with corrupted HFS+ images where the btree
allocation bitmap indicates that the header node is free. Node 0 must
always be allocated as it contains the btree header record and the
allocation bitmap itself. Violating this invariant can lead to kernel
panics or undefined behavior when the filesystem attempts to allocate
blocks or manipulate the btree.

The validation checks the node allocation bitmap in the btree header
node (record #2) and verifies that bit 7 (MSB) of the first byte is
set.

Implementation details:
- Perform validation inside hfs_btree_open() to allow identifying the
  specific tree (Extents, Catalog, or Attributes) involved.
- Use hfs_bnode_find() and hfs_brec_lenoff() to safely access the
  bitmap record using existing infrastructure, ensuring correct handling
  of multi-page nodes and endianness.
- If corruption is detected, print a warning identifying the specific
  btree and force the filesystem to mount read-only (SB_RDONLY).

This prevents kernel panics from corrupted syzkaller-generated images
while enabling data recovery by allowing the mount to proceed in
read-only mode rather than failing completely.

Reported-by: syzbot+1c8ff72d0cd8a50dfeaa@...kaller.appspotmail.com
Link: https://syzkaller.appspot.com/bug?extid=1c8ff72d0cd8a50dfeaa
Link: https://lore.kernel.org/all/b78c1e380a17186b73bc8641b139eca56a8de964.camel@ibm.com/
Signed-off-by: Shardul Bankar <shardul.b@...ricsoftware.com>
---
v3:
  - Moved validation logic inline into hfs_btree_open() to allow
    reporting the specific corrupted tree ID.
  - Replaced custom offset calculations with existing hfs_bnode_find()
    and hfs_brec_lenoff() infrastructure to handle node sizes and
    page boundaries correctly.
  - Removed temporary 'btree_bitmap_corrupted' superblock flag; setup
    SB_RDONLY directly upon detection.
  - Moved logging to hfs_btree_open() to include the specific tree ID in
    the warning message
  - Used explicit bitwise check (&) instead of test_bit() to ensure
    portability. test_bit() bit-numbering is architecture-dependent
    (e.g., bit 0 vs bit 7 can swap meanings on BE vs LE), whereas
    masking 0x80 consistently targets the MSB required by the HFS+
    on-disk format.
v2:
  - Fix compiler warning about comparing u16 bitmap_off with PAGE_SIZE which
can exceed u16 maximum on some architectures
  - Cast bitmap_off to unsigned int for the PAGE_SIZE comparison to avoid
tautological constant-out-of-range comparison warning.
  - Link: https://lore.kernel.org/oe-kbuild-all/202601251011.kJUhBF3P-lkp@intel.com/

 fs/hfsplus/btree.c         | 27 +++++++++++++++++++++++++++
 include/linux/hfs_common.h |  2 ++
 2 files changed, 29 insertions(+)

diff --git a/fs/hfsplus/btree.c b/fs/hfsplus/btree.c
index 229f25dc7c49..ae81608ba3cf 100644
--- a/fs/hfsplus/btree.c
+++ b/fs/hfsplus/btree.c
@@ -135,9 +135,12 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id)
 	struct hfs_btree *tree;
 	struct hfs_btree_header_rec *head;
 	struct address_space *mapping;
+	struct hfs_bnode *node;
+	u16 len, bitmap_off;
 	struct inode *inode;
 	struct page *page;
 	unsigned int size;
+	u8 bitmap_byte;
 
 	tree = kzalloc(sizeof(*tree), GFP_KERNEL);
 	if (!tree)
@@ -242,6 +245,30 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id)
 
 	kunmap_local(head);
 	put_page(page);
+
+	/*
+	 * Validate bitmap: node 0 (header node) must be marked allocated.
+	 */
+
+	node = hfs_bnode_find(tree, 0);
+	if (IS_ERR(node))
+		goto free_inode;
+
+	len = hfs_brec_lenoff(node,
+			HFSPLUS_BTREE_HDR_MAP_REC, &bitmap_off);
+
+	if (len != 0 && bitmap_off >= sizeof(struct hfs_bnode_desc)) {
+		hfs_bnode_read(node, &bitmap_byte, bitmap_off, 1);
+		if (!(bitmap_byte & HFSPLUS_BTREE_NODE0_BIT)) {
+			pr_warn("(%s): Btree 0x%x bitmap corruption detected, forcing read-only.\n",
+					sb->s_id, id);
+			pr_warn("Run fsck.hfsplus to repair.\n");
+			sb->s_flags |= SB_RDONLY;
+		}
+	}
+
+	hfs_bnode_put(node);
+
 	return tree;
 
  fail_page:
diff --git a/include/linux/hfs_common.h b/include/linux/hfs_common.h
index dadb5e0aa8a3..8d21d476cb57 100644
--- a/include/linux/hfs_common.h
+++ b/include/linux/hfs_common.h
@@ -510,7 +510,9 @@ struct hfs_btree_header_rec {
 #define HFSPLUS_NODE_MXSZ			32768
 #define HFSPLUS_ATTR_TREE_NODE_SIZE		8192
 #define HFSPLUS_BTREE_HDR_NODE_RECS_COUNT	3
+#define HFSPLUS_BTREE_HDR_MAP_REC		2	/* Map (bitmap) record in header node */
 #define HFSPLUS_BTREE_HDR_USER_BYTES		128
+#define HFSPLUS_BTREE_NODE0_BIT		0x80
 
 /* btree key type */
 #define HFSPLUS_KEY_CASEFOLDING		0xCF	/* case-insensitive */
-- 
2.34.1


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ