Syzbot reports a KMSAN uninit-value bug in __hfs_cache_extent [1]. Crash report is as such: loop0: detected capacity change from 0 to 64 ===================================================== BUG: KMSAN: uninit-value in __hfs_ext_read_extent fs/hfs/extent.c:160 [inline] BUG: KMSAN: uninit-value in __hfs_ext_cache_extent+0x69f/0x7e0 fs/hfs/extent.c:179 __hfs_ext_read_extent fs/hfs/extent.c:160 [inline] __hfs_ext_cache_extent+0x69f/0x7e0 fs/hfs/extent.c:179 hfs_ext_read_extent fs/hfs/extent.c:202 [inline] hfs_get_block+0x733/0xf50 fs/hfs/extent.c:366 __block_write_begin_int+0xa6b/0x2f80 fs/buffer.c:2121 Which comes from ptr not being zero-initialized before assigning it to fd->search_key. Hence, use kzalloc in hfs_find_init(). However, this is not enough as by re-running reproducer the following crash report is produced: loop0: detected capacity change from 0 to 64 ===================================================== BUG: KMSAN: uninit-value in __hfs_ext_read_extent fs/hfs/extent.c:163 [inline] BUG: KMSAN: uninit-value in __hfs_ext_cache_extent+0x779/0x7e0 fs/hfs/extent.c:179 __hfs_ext_read_extent fs/hfs/extent.c:163 [inline] __hfs_ext_cache_extent+0x779/0x7e0 fs/hfs/extent.c:179 [...] Local variable fd.i created at: hfs_ext_read_extent fs/hfs/extent.c:193 [inline] hfs_get_block+0x295/0xf50 fs/hfs/extent.c:366 __block_write_begin_int+0xa6b/0x2f80 fs/buffer.c:2121 This condition is triggered by a non-handled escape path in bdinf.c:__hfs_brec_find() which do not initialize the remaining fields in fd: hfs_ext_read_extent -> __hfs_ext_read_extent() -> hfs_brec_find(). In hfs_brec_find(): !ndix branch -> -ENOENT returned without initializing the remaining fd fields in the subsequent __hfs_brec_find() helper call. Once returning to __hfs_ext_read_extent() ensure that this escape path is handled to mitigate use of uninit fd fields causing the KMSAN bug. Reproducer does not trigger KMSAN bug anymore [2], but rather a kernel BUG at fs/hfs/inode.c:444: default: BUG(); return -EIO; which seems unrelated to the initial KMSAN bug reported, rather to subsequent write operations tried by the reproducer with other faulty options, immediately raising macro BUG() instead of just returning -EIO. [1] https://syzkaller.appspot.com/bug?extid=d395b0c369e492a17530 [2] https://syzkaller.appspot.com/x/report.txt?x=12922640580000 Reported-by: syzbot+d395b0c369e492a17530@xxxxxxxxxxxxxxxxxxxxxxxxx Signed-off-by: Gianfranco Trad <gianf.trad@xxxxxxxxx> --- fs/hfs/bfind.c | 2 +- fs/hfs/extent.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/fs/hfs/bfind.c b/fs/hfs/bfind.c index ef9498a6e88a..69f93200366d 100644 --- a/fs/hfs/bfind.c +++ b/fs/hfs/bfind.c @@ -18,7 +18,7 @@ int hfs_find_init(struct hfs_btree *tree, struct hfs_find_data *fd) fd->tree = tree; fd->bnode = NULL; - ptr = kmalloc(tree->max_key_len * 2 + 4, GFP_KERNEL); + ptr = kzalloc(tree->max_key_len * 2 + 4, GFP_KERNEL); if (!ptr) return -ENOMEM; fd->search_key = ptr; diff --git a/fs/hfs/extent.c b/fs/hfs/extent.c index 4a0ce131e233..14fd0a7bca14 100644 --- a/fs/hfs/extent.c +++ b/fs/hfs/extent.c @@ -160,6 +160,8 @@ static inline int __hfs_ext_read_extent(struct hfs_find_data *fd, struct hfs_ext if (fd->key->ext.FNum != fd->search_key->ext.FNum || fd->key->ext.FkType != fd->search_key->ext.FkType) return -ENOENT; + if (!fd->tree->root && res == -ENOENT) + return -ENOENT; if (fd->entrylength != sizeof(hfs_extent_rec)) return -EIO; hfs_bnode_read(fd->bnode, extent, fd->entryoffset, sizeof(hfs_extent_rec)); -- 2.43.0