ocfs2: fix directory entry check in ocfs2_search_dirblock()

Syzbot has reported the following KASAN splat:

BUG: KASAN: slab-use-after-free in ocfs2_search_dirblock+0x26b/0x830
Read of size 1 at addr ffff888012009982 by task repro/5388
...
Call Trace:
 <TASK>
 dump_stack_lvl+0x241/0x360
 ? __pfx_dump_stack_lvl+0x10/0x10
 ? __pfx__printk+0x10/0x10
 ? _printk+0xd5/0x120
 ? __virt_addr_valid+0x183/0x530
 ? __virt_addr_valid+0x183/0x530
 print_report+0x169/0x550
 ? __virt_addr_valid+0x183/0x530
 ? __virt_addr_valid+0x183/0x530
 ? __virt_addr_valid+0x45f/0x530
 ? __phys_addr+0xba/0x170
 ? ocfs2_search_dirblock+0x26b/0x830
 kasan_report+0x143/0x180
 ? ocfs2_search_dirblock+0x26b/0x830
 ocfs2_search_dirblock+0x26b/0x830
 ? ocfs2_read_inode_block+0x14c/0x1e0
 ? __pfx_ocfs2_search_dirblock+0x10/0x10
 ? validate_chain+0x11e/0x5900
 ocfs2_find_entry+0x1169/0x2780
 ? mark_lock+0x9a/0x350
 ? __lock_acquire+0x137a/0x2040
 ? __pfx_ocfs2_find_entry+0x10/0x10
 ? __pfx_lock_acquire+0x10/0x10
 ? ocfs2_inode_lock_full_nested+0x17b/0x1c10
 ? __pfx_lock_release+0x10/0x10
 ? do_raw_spin_lock+0x14f/0x370
 ? do_raw_spin_unlock+0x58/0x8b0
 ? _raw_spin_unlock+0x28/0x50
 ? ocfs2_inode_lock_full_nested+0xb2f/0x1c10
 ? __pfx_ocfs2_inode_lock_full_nested+0x10/0x10
 ocfs2_find_files_on_disk+0xff/0x360
 ocfs2_lookup_ino_from_name+0xb1/0x1e0
 ? __pfx_ocfs2_lookup_ino_from_name+0x10/0x10
 ocfs2_lookup+0x292/0xa60
 ? __pfx_ocfs2_lookup+0x10/0x10
 ? from_kgid+0x1a7/0x730
 ? make_vfsgid+0x46/0x90
 ? HAS_UNMAPPED_ID+0xf9/0x150
 ? inode_permission+0xff/0x460
 ? __pfx_ocfs2_permission+0x10/0x10
 ? bpf_lsm_inode_create+0x9/0x10
 ? security_inode_create+0xc2/0x110
 ? __pfx_ocfs2_lookup+0x10/0x10
 path_openat+0x11ce/0x3470
 ? __pfx_path_openat+0x10/0x10
 do_filp_open+0x235/0x490
 ? __pfx_do_filp_open+0x10/0x10
 ? _raw_spin_unlock+0x28/0x50
 ? alloc_fd+0x5a1/0x640
 do_sys_openat2+0x13e/0x1d0
 ? mntput_no_expire+0xc2/0x850
 ? __pfx_do_sys_openat2+0x10/0x10
 ? __pfx_mntput_no_expire+0x10/0x10
 __x64_sys_openat+0x247/0x2a0
 ? __pfx___x64_sys_openat+0x10/0x10
 ? do_syscall_64+0x100/0x230
 ? do_syscall_64+0xb6/0x230
 do_syscall_64+0xf3/0x230
 entry_SYSCALL_64_after_hwframe+0x77/0x7f
...
 </TASK>

This happens when 'ocfs2_search_dirblock()' makes an attempt to jump over
(presumably invalid) on-disk directory entry which size exceeds
'sizeof(struct ocfs2_dir_entry)', thus touching memory used by others
(including the previously freed one).  So just bail out if such a
directory entry is found.

Link: https://lkml.kernel.org/r/20241119170745.464799-1-dmantipov@yandex.ru
Fixes: ccd979bdbc ("[PATCH] OCFS2: The Second Oracle Cluster Filesystem")
Reported-by: syzbot+b9704899e166798d57c9@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=b9704899e166798d57c9
Signed-off-by: Dmitry Antipov <dmantipov@yandex.ru>
Cc: Mark Fasheh <mark@fasheh.com>
Cc: Joel Becker <jlbec@evilplan.org>
Cc: Junxiao Bi <junxiao.bi@oracle.com>
Cc: Joseph Qi <jiangqi903@gmail.com>
Cc: Changwei Ge <gechangwei@live.cn>
Cc: Jun Piao <piaojun@huawei.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
This commit is contained in:
Dmitry Antipov 2024-11-19 20:07:45 +03:00 committed by Andrew Morton
parent d3ac65d274
commit cb11e33358

View File

@ -378,7 +378,7 @@ static inline int ocfs2_search_dirblock(struct buffer_head *bh,
/* prevent looping on a bad block */
de_len = le16_to_cpu(de->rec_len);
if (de_len <= 0) {
if (de_len <= 0 || de_len > sizeof(*de)) {
ret = -1;
goto bail;
}