fs/hfs/bfind.c | 2 +- fs/hfs/extent.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-)
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@syzkaller.appspotmail.com
Signed-off-by: Gianfranco Trad <gianf.trad@gmail.com>
---
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
© 2016 - 2024 Red Hat, Inc.