hfs_bnode_read_key() reads the key length of leaf records (and of all records of variable-key and attributes trees) from disk and only checks it against sizeof(hfsplus_btree_key), 518 bytes. The destination is always one of the two key buffers hfs_find_init() allocates, each tree->max_key_len + 2 bytes long. For the extents tree max_key_len is fixed at 10, so the whole allocation is 24 bytes and a crafted leaf key writes up to 516 attacker-controlled bytes into kmalloc-32. The error path has the same problem: it clears 518 bytes of the 24-byte buffer. hfs_brec_insert() reaches this with an unvalidated key: when the tree root is 0 it reads the key of record 0 of the leaf it inserts into, and after a split it reads the first key of the new node. A read-write mount that extends the catalog (creating the private data directory), or an append to a file whose extents spill into the extents tree, is enough; no other file operation is needed. The 518-byte bound was added by commit bb5e07cb9277 ("hfs/hfsplus: fix slab-out-of-bounds in hfs_bnode_read_key"); it covers the catalog and attributes buffers but not the extents buffer. Bound the key length by the tree's own maximum, which btree.c already validates per tree, and only clear the bytes the buffer actually has. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Fixes: bb5e07cb9277 ("hfs/hfsplus: fix slab-out-of-bounds in hfs_bnode_read_key") Reported-by: Guikun Yang Closes: https://lore.kernel.org/all/tencent_F85118A9AFDF9B230D4E8FA672510A3E2F08@qq.com/ Cc: stable@vger.kernel.org Signed-off-by: ozgun kultekin --- diff --git a/fs/hfsplus/bnode.c b/fs/hfsplus/bnode.c index 3a1a1fa..f414020 100644 --- a/fs/hfsplus/bnode.c +++ b/fs/hfsplus/bnode.c @@ -84,8 +84,13 @@ void hfs_bnode_read_key(struct hfs_bnode *node, void *key, u32 off) else key_len = tree->max_key_len + 2; - if (key_len > sizeof(hfsplus_btree_key) || key_len < 1) { - memset(key, 0, sizeof(hfsplus_btree_key)); + /* + * The key buffers come from hfs_find_init() and hold + * tree->max_key_len + 2 bytes each, which is far less than + * sizeof(hfsplus_btree_key) for the extents tree. + */ + if (key_len > tree->max_key_len + 2 || key_len < 1) { + memset(key, 0, tree->max_key_len + 2); pr_err("hfsplus: Invalid key length: %u\n", key_len); return; } -- 2.47.0