[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