[PATCH 2/2] hfs/hfsplus: stop btree allocators from reusing node 0

Tao Yu <[email protected]>
Newsgroups org.kernel.vger.linux-fsdevel,org.kernel.vger.linux-kernel
Message-ID <[email protected]>
The btree header node is permanently reserved as node 0. If the on-disk
bitmap ever presents node 0 as free, the filesystem is already
corrupted and the allocator must not try to instantiate it again.

Both HFS and HFS+ currently keep scanning the bitmap, set the bit, and
hand node 0 to hfs_bnode_create()/hfsplus_bnode_create(). HFS+ then
hits the "new node 0 already hashed?" warning reported by syzbot, while
HFS risks continuing after the same corruption pattern.

Teach both allocators to treat attempts to allocate node 0 as btree map
corruption. Force the filesystem read-only, emit the existing repair
hint, and abort the allocation before the code reaches the hashed-node
warning.

Reported-by: [email protected]
Closes: https://syzkaller.appspot.com/bug?extid=2bf21610eea63cb2ce93
Signed-off-by: Tao Yu <[email protected]>
---
 fs/hfs/btree.c     | 11 +++++++++++
 fs/hfsplus/btree.c | 11 +++++++++++
 2 files changed, 22 insertions(+)

diff --git a/fs/hfs/btree.c b/fs/hfs/btree.c
index 14114318ec724..9b0b7418ddbd5 100644
--- a/fs/hfs/btree.c
+++ b/fs/hfs/btree.c
@@ -376,6 +376,17 @@ struct hfs_bnode *hfs_bmap_alloc(struct hfs_btree *tree)
 			if (byte != 0xff) {
 				for (m = 0x80, i = 0; i < 8; m >>= 1, i++) {
 					if (!(byte & m)) {
+						if (unlikely(!(idx + i))) {
+							pr_warn("(%s): %s (cnid 0x%x) map record invalid or bitmap corruption detected, forcing read-only.\n",
+								tree->sb->s_id,
+								hfs_btree_name(tree->cnid),
+								tree->cnid);
+							pr_warn("Run fsck.hfs to repair.\n");
+							tree->sb->s_flags |= SB_RDONLY;
+							kunmap_local(data);
+							hfs_bnode_put(node);
+							return ERR_PTR(-EIO);
+						}
 						idx += i;
 						data[off] |= m;
 						set_page_dirty(*pagep);
diff --git a/fs/hfsplus/btree.c b/fs/hfsplus/btree.c
index 394542a47e600..3ee92248b2409 100644
--- a/fs/hfsplus/btree.c
+++ b/fs/hfsplus/btree.c
@@ -561,6 +561,17 @@ struct hfs_bnode *hfs_bmap_alloc(struct hfs_btree *tree)
 			if (byte != 0xff) {
 				for (m = 0x80, i = 0; i < 8; m >>= 1, i++) {
 					if (!(byte & m)) {
+						if (unlikely(!(idx + i))) {
+							pr_warn("(%s): %s (cnid 0x%x) map record invalid or bitmap corruption detected, forcing read-only.\n",
+								tree->sb->s_id,
+								hfs_btree_name(tree->cnid),
+								tree->cnid);
+							pr_warn("Run fsck.hfsplus to repair.\n");
+							tree->sb->s_flags |= SB_RDONLY;
+							kunmap_local(data);
+							hfs_bnode_put(node);
+							return ERR_PTR(-EIO);
+						}
 						idx += i;
 						data[ctx.off] |= m;
 						set_page_dirty(page);
-- 
2.34.1
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.