fs/hfsplus/catalog.c | 1 + 1 file changed, 1 insertion(+)
Syzbot reported a KMSAN uninit-value issue in hfsplus_strcasecmp() during
filesystem mount operations. The root cause is that hfsplus_find_cat()
declares a local hfsplus_cat_entry variable without initialization before
passing it to hfs_brec_read().
If hfs_brec_read() doesn't completely fill the entire structure (e.g., when
the on-disk data is shorter than sizeof(hfsplus_cat_entry)), the padding
bytes in tmp.thread.nodeName remain uninitialized. These uninitialized
bytes are then copied by hfsplus_cat_build_key_uni() into the search key,
and subsequently accessed by hfsplus_strcasecmp() during catalog lookups,
triggering the KMSAN warning.
Fix this by zeroing the tmp variable before use to ensure all padding
bytes are initialized.
Reported-by: syzbot+d80abb5b890d39261e72@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=d80abb5b890d39261e72
Tested-by: syzbot+d80abb5b890d39261e72@syzkaller.appspotmail.com
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Signed-off-by: Deepanshu Kartikey <kartikey406@gmail.com>
---
fs/hfsplus/catalog.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/fs/hfsplus/catalog.c b/fs/hfsplus/catalog.c
index 02c1eee4a4b8..9c75d1736427 100644
--- a/fs/hfsplus/catalog.c
+++ b/fs/hfsplus/catalog.c
@@ -199,6 +199,7 @@ int hfsplus_find_cat(struct super_block *sb, u32 cnid,
u16 type;
hfsplus_cat_build_key_with_cnid(sb, fd->search_key, cnid);
+ memset(&tmp, 0, sizeof(tmp));
err = hfs_brec_read(fd, &tmp, sizeof(hfsplus_cat_entry));
if (err)
return err;
--
2.43.0
On Tue, 2026-01-20 at 10:41 +0530, Deepanshu Kartikey wrote:
> Syzbot reported a KMSAN uninit-value issue in hfsplus_strcasecmp() during
> filesystem mount operations. The root cause is that hfsplus_find_cat()
> declares a local hfsplus_cat_entry variable without initialization before
> passing it to hfs_brec_read().
>
> If hfs_brec_read() doesn't completely fill the entire structure (e.g., when
> the on-disk data is shorter than sizeof(hfsplus_cat_entry)), the padding
> bytes in tmp.thread.nodeName remain uninitialized. These uninitialized
> bytes are then copied by hfsplus_cat_build_key_uni() into the search key,
> and subsequently accessed by hfsplus_strcasecmp() during catalog lookups,
> triggering the KMSAN warning.
Frankly speaking, I don't quite follow what is wrong with current logic from
your explanation. Only, struct hfsplus_cat_thread contains nodeName string. And
hfsplus_strcasecmp() can try to compare some strings only for Catalog thread
type. But hfs_brec_read() should read namely only this type of Catalog File
record. So, I cannot imagine how likewise issue could happen. Could you explain
the issue more clearly? How uninitiliazed nodeName strings can be used for
comparison? How does it happened? Because, struct hfsplus_cat_thread is the
biggest item in hfsplus_cat_entry union. The struct hfsplus_cat_file and struct
hfsplus_cat_folder don't contain any strings and strings cannot be used for
comparison in these structures case. But struct hfsplus_cat_thread should be
read completely with the string.
>
> Fix this by zeroing the tmp variable before use to ensure all padding
> bytes are initialized.
>
> Reported-by: syzbot+d80abb5b890d39261e72@syzkaller.appspotmail.com
> Closes: https://syzkaller.appspot.com/bug?extid=d80abb5b890d39261e72
> Tested-by: syzbot+d80abb5b890d39261e72@syzkaller.appspotmail.com
> Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
> Signed-off-by: Deepanshu Kartikey <kartikey406@gmail.com>
> ---
> fs/hfsplus/catalog.c | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/fs/hfsplus/catalog.c b/fs/hfsplus/catalog.c
> index 02c1eee4a4b8..9c75d1736427 100644
> --- a/fs/hfsplus/catalog.c
> +++ b/fs/hfsplus/catalog.c
> @@ -199,6 +199,7 @@ int hfsplus_find_cat(struct super_block *sb, u32 cnid,
> u16 type;
>
> hfsplus_cat_build_key_with_cnid(sb, fd->search_key, cnid);
> + memset(&tmp, 0, sizeof(tmp));
What's about of using initialization:
hfsplus_cat_entry tmp = {0};
instead of using memset()?
Thanks,
Slava.
> err = hfs_brec_read(fd, &tmp, sizeof(hfsplus_cat_entry));
> if (err)
> return err;
On Wed, Jan 21, 2026 at 3:59 AM Viacheslav Dubeyko
<Slava.Dubeyko@ibm.com> wrote:
> Frankly speaking, I don't quite follow what is wrong with current logic from
> your explanation. Only, struct hfsplus_cat_thread contains nodeName string. And
> hfsplus_strcasecmp() can try to compare some strings only for Catalog thread
> type. But hfs_brec_read() should read namely only this type of Catalog File
> record. So, I cannot imagine how likewise issue could happen. Could you explain
> the issue more clearly? How uninitiliazed nodeName strings can be used for
> comparison? How does it happened? Because, struct hfsplus_cat_thread is the
> biggest item in hfsplus_cat_entry union. The struct hfsplus_cat_file and struct
> hfsplus_cat_folder don't contain any strings and strings cannot be used for
> comparison in these structures case. But struct hfsplus_cat_thread should be
> read completely with the string.
Hi Slava,
Thank you for the review.
Regarding your question about how uninitialized data is used: You're correct
that in normal operation, hfs_brec_read() should fully read the catalog
thread record. However, the KMSAN report from syzbot shows that uninitialized
data is being accessed.
Looking at the code flow and the KMSAN stack trace:
1. tmp is declared on the stack without initialization in hfsplus_find_cat()
2. hfs_brec_read() is called to fill it from disk
3. With a corrupted/malformed filesystem image (which syzbot fuzzes),
hfs_brec_read() may read partial or invalid data
4. The tmp.thread.nodeName.unicode array may not be fully populated
5. hfsplus_cat_build_key_uni() copies from this array based on nodeName.length
6. hfsplus_strcasecmp() then reads these bytes and passes them to case_fold()
7. case_fold() uses the value as an array index: hfsplus_case_fold_table[c >> 8]
8. KMSAN detects this uninitialized value being used as an array index
The KMSAN report explicitly shows the uninit-value originates from the
uninitialized tmp variable and propagates through the code path. The
initialization ensures that even with corrupted filesystem images, we use
zeros instead of random stack data.
Syzbot has confirmed that the fix resolves the issue:
https://syzkaller.appspot.com/bug?extid=d80abb5b890d39261e72
I will update the patch to use = {0} initialization as you suggested.
Thanks,
Deepanshu
© 2016 - 2026 Red Hat, Inc.