[lvc-project] [PATCH] ocfs2: fix directory entry check in ocfs2_search_dirblock()
Joseph Qi
joseph.qi at linux.alibaba.com
Thu Nov 28 06:27:45 MSK 2024
On 11/20/24 1:07 AM, Dmitry Antipov wrote:
> 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.
>
> Reported-by: syzbot+b9704899e166798d57c9 at syzkaller.appspotmail.com
> Closes: https://syzkaller.appspot.com/bug?extid=b9704899e166798d57c9
> Fixes: ccd979bdbce9 ("[PATCH] OCFS2: The Second Oracle Cluster Filesystem")
> Signed-off-by: Dmitry Antipov <dmantipov at yandex.ru>
> ---
> fs/ocfs2/dir.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/fs/ocfs2/dir.c b/fs/ocfs2/dir.c
> index 213206ebdd58..7a8040a47e82 100644
> --- a/fs/ocfs2/dir.c
> +++ b/fs/ocfs2/dir.c
> @@ -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;
> }
This is caused by a crafted image, and de->rec_len will be checked when
ocfs2_add_entry().
It seems we can make the check here more precisely by using
OCFS2_DIR_REC_LEN().Something like:
de_len > OCFS2_DIR_REC_LEN(de->name_len)
Thanks,
Joseph
More information about the lvc-project
mailing list