mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH v3] hfsplus: validate btree bitmap during mount and handle corruption gracefully
@ 2026-01-31 14:04 Shardul Bankar
  2026-02-02 20:52 ` Viacheslav Dubeyko
  0 siblings, 1 reply; 7+ messages in thread
From: Shardul Bankar @ 2026-01-31 14:04 UTC (permalink / raw)
  To: slava, glaubitz, frank.li, linux-fsdevel, linux-kernel
  Cc: janak, shardulsb08, Shardul Bankar, syzbot+1c8ff72d0cd8a50dfeaa

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@syzkaller.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@mpiricsoftware.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


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

end of thread, other threads:[~2026-02-26 19:03 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-01-31 14:04 [PATCH v3] hfsplus: validate btree bitmap during mount and handle corruption gracefully Shardul Bankar
2026-02-02 20:52 ` Viacheslav Dubeyko
2026-02-03  8:58   ` Shardul Bankar
2026-02-03 23:12     ` Viacheslav Dubeyko
2026-02-15 17:57       ` Shardul Bankar
2026-02-17  0:41         ` Viacheslav Dubeyko
2026-02-26 19:02           ` Shardul Bankar

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

all inboxes | Powered by JetHome®