[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