From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-ot1-f71.google.com (mail-ot1-f71.google.com [209.85.210.71]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id AC4EA26056C for ; Sat, 18 Apr 2026 13:39:31 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.71 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776519573; cv=none; b=ZzDmSMci/cJ6i7NX+4fj//xFV6QVcB7KAfhMtJWq+zZYOqaY3f+bKQIyzHw11zUa0412wtmKrff3/i7UzxNq/gnbNFLGOJALivQmOqpEfS3OFJyd/GQtCtUCdBta3R0z1HHm2yCG+DhIihzp6/8Kg7N5EBnSS/mNe3gEcOXnmAA= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776519573; c=relaxed/simple; bh=1fM29RjTaD2MPCAC847cmHU84pKsxAHhdILMkraE02o=; h=MIME-Version:Date:In-Reply-To:Message-ID:Subject:From:To: Content-Type; b=h+5hZSOmLNeLY1J1KlkSfzJJ9n4ojsrbKr6hv1QCWtOaExMMKGl//ucKzOjzvTXw01cN0IvyyRmHRIQ7f+zdyVpJ19Zz0TyGDPhJbhvVt/CcVBHPkoit7JzKsL0hKXi2+f3oKtjAJWt+hr21U7TBPZqOtG7apXagDcn6APGAwt4= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=fail (p=none dis=none) header.from=syzkaller.appspotmail.com; spf=pass smtp.mailfrom=M3KW2WVRGUFZ5GODRSRYTGD7.apphosting.bounces.google.com; arc=none smtp.client-ip=209.85.210.71 Authentication-Results: smtp.subspace.kernel.org; dmarc=fail (p=none dis=none) header.from=syzkaller.appspotmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=M3KW2WVRGUFZ5GODRSRYTGD7.apphosting.bounces.google.com Received: by mail-ot1-f71.google.com with SMTP id 46e09a7af769-7d4be1dee67so4179486a34.1 for ; Sat, 18 Apr 2026 06:39:31 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1776519570; x=1777124370; h=to:from:subject:message-id:in-reply-to:date:mime-version :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=w5kLzfJS7WoHFlgPBSdFo64E0xY6LFc6kwKMdd8SJcg=; b=QwKv7XOwEb0onlnMlBt5JV/ZOMN6jy/ZFmQ2KI8UlbBiIjmw0urG7RBgXyJUF8TzPj JnF3VMJtUwu1C/fmghXTKM30iowktRO5WBVEIWmg7Pj7Ed7gqXJD3iXzefrfTqz9m8WV za7MRGk8a+IEaWagiZI0v/cPzWLvWH/1xiYRTWImdzW8giIGJKymAJSameatMANPfxvI 9btcLkrwEL2TnglwKKnyk8m5mo6fV2MogKfVGydKEJEvU5ZjhHHftnJGEeroAuq5iUTp +pK8aIviH3jt3ZigqHvbAWILrcKSgtOvUH8uioVA4MgGcSFFRqbFvB25gu0wZnqp1V0J /fXA== X-Gm-Message-State: AOJu0Yz9bpkPY4RjvJdP8Grm7G7mrS8SftdZKoaHZdpTXW4Y1SnnHG9Z 9CnHES0v/GhQhUON98bZpnU0vB34PPAuC6RCwimQeVr8wwE7QaxMIXbZNmvnGTv/Ix4J19nX7FM MXuXa+Sh58QKAiNKIcAOkpYQapiUlXTBt72gXoyOWc7UO64wWK3GHuuVUC8Y= Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Received: by 2002:a05:6820:1caa:b0:67b:ab68:b5e2 with SMTP id 006d021491bc7-69462e484a3mr3938972eaf.18.1776519570711; Sat, 18 Apr 2026 06:39:30 -0700 (PDT) Date: Sat, 18 Apr 2026 06:39:30 -0700 In-Reply-To: <001a11c1461c14bf9e0568fd0cd6@google.com> X-Google-Appengine-App-Id: s~syzkaller X-Google-Appengine-App-Id-Alias: syzkaller Message-ID: <69e38992.050a0220.24bfd3.0009.GAE@google.com> Subject: Forwarded: Re: [syzbot] [hfs?] WARNING in hfs_bnode_create From: syzbot To: linux-kernel@vger.kernel.org, syzkaller-bugs@googlegroups.com Content-Type: text/plain; charset="UTF-8" For archival purposes, forwarding an incoming command email to linux-kernel@vger.kernel.org, syzkaller-bugs@googlegroups.com. *** Subject: Re: [syzbot] [hfs?] WARNING in hfs_bnode_create Author: tristmd@gmail.com #syz test: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git master >>From 056301b328e16474cbd3485e8ba571d064ac31a0 Mon Sep 17 00:00:00 2001 From: Tristan Madani Date: Sat, 18 Apr 2026 13:38:21 +0000 Subject: [PATCH] hfs: validate bitmap record offset in hfs_bmap_alloc hfs_bmap_alloc() retrieves the bitmap record from the header node using hfs_brec_lenoff() but does not validate the returned offset and length before using them to compute page pointers. On a crafted HFS image with corrupted B-tree data, the offset can exceed the node size, causing an out-of-bounds page access. Additionally, when the bitmap has node 0 bit incorrectly unset, hfs_bmap_alloc() calls hfs_bnode_create(tree, 0) for the already- hashed header node, triggering a WARN_ON and returning the existing node without incrementing its reference count. Port the fixes already applied to HFS+ (commits d8a73cc46c84 and 738d5a51864e) to the HFS side: 1. Move is_bnode_offset_valid() and check_and_correct_requested_length() from bnode.c to btree.h so they can be used by btree.c. 2. Validate the record offset and length in hfs_bmap_alloc() before computing page pointers, preventing out-of-bounds access. 3. Return ERR_PTR(-EEXIST) from hfs_bnode_create() when the node is already hashed, properly signaling filesystem corruption to callers. Reported-by: syzbot+a19ca73b21fe8bc69101@syzkaller.appspotmail.com Tested-by: syzbot+a19ca73b21fe8bc69101@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=a19ca73b21fe8bc69101 Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Cc: stable@vger.kernel.org Signed-off-by: Tristan Madani --- fs/hfs/bnode.c | 44 +------------------------------------------- fs/hfs/btree.c | 6 ++++++ fs/hfs/btree.h | 42 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 49 insertions(+), 43 deletions(-) diff --git a/fs/hfs/bnode.c b/fs/hfs/bnode.c index 13d58c51fc46b..26c2e65ab5935 100644 --- a/fs/hfs/bnode.c +++ b/fs/hfs/bnode.c @@ -15,48 +15,6 @@ #include "btree.h" -static inline -bool is_bnode_offset_valid(struct hfs_bnode *node, u32 off) -{ - bool is_valid = off < node->tree->node_size; - - if (!is_valid) { - pr_err("requested invalid offset: " - "NODE: id %u, type %#x, height %u, " - "node_size %u, offset %u\n", - node->this, node->type, node->height, - node->tree->node_size, off); - } - - return is_valid; -} - -static inline -u32 check_and_correct_requested_length(struct hfs_bnode *node, u32 off, u32 len) -{ - unsigned int node_size; - - if (!is_bnode_offset_valid(node, off)) - return 0; - - node_size = node->tree->node_size; - - if ((off + len) > node_size) { - u32 new_len = node_size - off; - - pr_err("requested length has been corrected: " - "NODE: id %u, type %#x, height %u, " - "node_size %u, offset %u, " - "requested_len %u, corrected_len %u\n", - node->this, node->type, node->height, - node->tree->node_size, off, len, new_len); - - return new_len; - } - - return len; -} - void hfs_bnode_read(struct hfs_bnode *node, void *buf, u32 off, u32 len) { struct page *page; @@ -518,7 +476,7 @@ struct hfs_bnode *hfs_bnode_create(struct hfs_btree *tree, u32 num) if (node) { pr_crit("new node %u already hashed?\n", num); WARN_ON(1); - return node; + return ERR_PTR(-EEXIST); } node = __hfs_bnode_create(tree, num); if (!node) diff --git a/fs/hfs/btree.c b/fs/hfs/btree.c index 2eb37a2f64e86..e8bc24c8baf1a 100644 --- a/fs/hfs/btree.c +++ b/fs/hfs/btree.c @@ -304,6 +304,12 @@ struct hfs_bnode *hfs_bmap_alloc(struct hfs_btree *tree) len = hfs_brec_lenoff(node, 2, &off16); off = off16; + if (!is_bnode_offset_valid(node, off)) { + hfs_bnode_put(node); + return ERR_PTR(-EIO); + } + len = check_and_correct_requested_length(node, off, len); + off += node->page_offset; pagep = node->page + (off >> PAGE_SHIFT); data = kmap_local_page(*pagep); diff --git a/fs/hfs/btree.h b/fs/hfs/btree.h index 99be858b24465..6032b14b1639d 100644 --- a/fs/hfs/btree.h +++ b/fs/hfs/btree.h @@ -85,6 +85,48 @@ struct hfs_find_data { }; +static inline +bool is_bnode_offset_valid(struct hfs_bnode *node, u32 off) +{ + bool is_valid = off < node->tree->node_size; + + if (!is_valid) { + pr_err("requested invalid offset: " + "NODE: id %u, type %#x, height %u, " + "node_size %u, offset %u\n", + node->this, node->type, node->height, + node->tree->node_size, off); + } + + return is_valid; +} + +static inline +u32 check_and_correct_requested_length(struct hfs_bnode *node, u32 off, u32 len) +{ + unsigned int node_size; + + if (!is_bnode_offset_valid(node, off)) + return 0; + + node_size = node->tree->node_size; + + if ((off + len) > node_size) { + u32 new_len = node_size - off; + + pr_err("requested length has been corrected: " + "NODE: id %u, type %#x, height %u, " + "node_size %u, offset %u, " + "requested_len %u, corrected_len %u\n", + node->this, node->type, node->height, + node->tree->node_size, off, len, new_len); + + return new_len; + } + + return len; +} + /* btree.c */ extern struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id, btree_keycmp keycmp); -- 2.47.3