Re: [SECURITY] [PATCH V3] hfsplus: fix slab-out-of-bounds read in hfsplus_uni2asc()

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Tue, 2025-09-09 at 11:13 +0800, Kang Chen wrote:
> BUG: KASAN: slab-out-of-bounds in hfsplus_uni2asc+0xa71/0xb90
> fs/hfsplus/unicode.c:186
> Read of size 2 at addr ffff8880289ef218 by task syz.6.248/14290
> 
> CPU: 0 UID: 0 PID: 14290 Comm: syz.6.248 Not tainted 6.16.4 #1
> PREEMPT(full)
> Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.15.0-1
> 04/01/2014
> Call Trace:
>  <TASK>
>  __dump_stack lib/dump_stack.c:94 [inline]
>  dump_stack_lvl+0x116/0x1b0 lib/dump_stack.c:120
>  print_address_description mm/kasan/report.c:378 [inline]
>  print_report+0xca/0x5f0 mm/kasan/report.c:482
>  kasan_report+0xca/0x100 mm/kasan/report.c:595
>  hfsplus_uni2asc+0xa71/0xb90 fs/hfsplus/unicode.c:186
>  hfsplus_listxattr+0x5b6/0xbd0 fs/hfsplus/xattr.c:738
>  vfs_listxattr+0xbe/0x140 fs/xattr.c:493
>  listxattr+0xee/0x190 fs/xattr.c:924
>  filename_listxattr fs/xattr.c:958 [inline]
>  path_listxattrat+0x143/0x360 fs/xattr.c:988
>  do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
>  do_syscall_64+0xcb/0x4c0 arch/x86/entry/syscall_64.c:94
>  entry_SYSCALL_64_after_hwframe+0x77/0x7f
> RIP: 0033:0x7fe0e9fae16d
> Code: 02 b8 ff ff ff ff c3 66 0f 1f 44 00 00 f3 0f 1e fa 48 89 f8 48
> 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48>
> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 a8 ff ff ff f7 d8 64 89 01 48
> RSP: 002b:00007fe0eae67f98 EFLAGS: 00000246 ORIG_RAX:
> 00000000000000c3
> RAX: ffffffffffffffda RBX: 00007fe0ea205fa0 RCX: 00007fe0e9fae16d
> RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000200000000000
> RBP: 00007fe0ea0480f0 R08: 0000000000000000 R09: 0000000000000000
> R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000
> R13: 00007fe0ea206038 R14: 00007fe0ea205fa0 R15: 00007fe0eae48000
>  </TASK>
> 
> Allocated by task 14290:
>  kasan_save_stack+0x24/0x50 mm/kasan/common.c:47
>  kasan_save_track+0x14/0x30 mm/kasan/common.c:68
>  poison_kmalloc_redzone mm/kasan/common.c:377 [inline]
>  __kasan_kmalloc+0xaa/0xb0 mm/kasan/common.c:394
>  kasan_kmalloc include/linux/kasan.h:260 [inline]
>  __do_kmalloc_node mm/slub.c:4333 [inline]
>  __kmalloc_noprof+0x219/0x540 mm/slub.c:4345
>  kmalloc_noprof include/linux/slab.h:909 [inline]
>  hfsplus_find_init+0x95/0x1f0 fs/hfsplus/bfind.c:21
>  hfsplus_listxattr+0x331/0xbd0 fs/hfsplus/xattr.c:697
>  vfs_listxattr+0xbe/0x140 fs/xattr.c:493
>  listxattr+0xee/0x190 fs/xattr.c:924
>  filename_listxattr fs/xattr.c:958 [inline]
>  path_listxattrat+0x143/0x360 fs/xattr.c:988
>  do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
>  do_syscall_64+0xcb/0x4c0 arch/x86/entry/syscall_64.c:94
>  entry_SYSCALL_64_after_hwframe+0x77/0x7f
> 
> When hfsplus_uni2asc is called from hfsplus_listxattr,
> it actually passes in a struct hfsplus_attr_unistr*.
> The size of the corresponding structure is different from that of
> hfsplus_unistr,
> so the previous fix (94458781aee6) is insufficient.
> The pointer on the unicode buffer is still going beyond the allocated
> memory.
> 
> This patch introduces two warpper functions hfsplus_uni2asc_xattr_str
> and
> hfsplus_uni2asc_str to process two unicode buffers,
> struct hfsplus_attr_unistr* and struct hfsplus_unistr* respectively.
> When ustrlen value is bigger than the allocated memory size,
> the ustrlen value is limited to an safe size.
> 
> Fixes: 94458781aee6 ("hfsplus: fix slab-out-of-bounds read in
> hfsplus_uni2asc()")
> Signed-off-by: Kang Chen <k.chen@xxxxxxxxxxxxxxxx>
> ---
> V2 -> V1: change struct pointer type to pass compiler
> V3 -> V2: complete the commit message and use two warpper functions

Looks good.

Reviewed-by: Viacheslav Dubeyko <slava@xxxxxxxxxxx>

Thanks,
Slava.

> 
>  fs/hfsplus/dir.c        |  2 +-
>  fs/hfsplus/hfsplus_fs.h |  8 ++++++--
>  fs/hfsplus/unicode.c    | 24 +++++++++++++++++++-----
>  fs/hfsplus/xattr.c      |  6 +++---
>  4 files changed, 29 insertions(+), 11 deletions(-)
> 
> diff --git a/fs/hfsplus/dir.c b/fs/hfsplus/dir.c
> index 876bbb80fb4d..1b3e27a0d5e0 100644
> --- a/fs/hfsplus/dir.c
> +++ b/fs/hfsplus/dir.c
> @@ -204,7 +204,7 @@ static int hfsplus_readdir(struct file *file,
> struct dir_context *ctx)
>  			fd.entrylength);
>  		type = be16_to_cpu(entry.type);
>  		len = NLS_MAX_CHARSET_SIZE * HFSPLUS_MAX_STRLEN;
> -		err = hfsplus_uni2asc(sb, &fd.key->cat.name, strbuf,
> &len);
> +		err = hfsplus_uni2asc_str(sb, &fd.key->cat.name,
> strbuf, &len);
>  		if (err)
>  			goto out;
>  		if (type == HFSPLUS_FOLDER) {
> diff --git a/fs/hfsplus/hfsplus_fs.h b/fs/hfsplus/hfsplus_fs.h
> index 96a5c24813dd..2311e4be4e86 100644
> --- a/fs/hfsplus/hfsplus_fs.h
> +++ b/fs/hfsplus/hfsplus_fs.h
> @@ -521,8 +521,12 @@ int hfsplus_strcasecmp(const struct
> hfsplus_unistr *s1,
>  		       const struct hfsplus_unistr *s2);
>  int hfsplus_strcmp(const struct hfsplus_unistr *s1,
>  		   const struct hfsplus_unistr *s2);
> -int hfsplus_uni2asc(struct super_block *sb, const struct
> hfsplus_unistr *ustr,
> -		    char *astr, int *len_p);
> +int hfsplus_uni2asc_str(struct super_block *sb,
> +			const struct hfsplus_unistr *ustr, char
> *astr,
> +			int *len_p);
> +int hfsplus_uni2asc_xattr_str(struct super_block *sb,
> +			      const struct hfsplus_attr_unistr
> *ustr,
> +			      char *astr, int *len_p);
>  int hfsplus_asc2uni(struct super_block *sb, struct hfsplus_unistr
> *ustr,
>  		    int max_unistr_len, const char *astr, int len);
>  int hfsplus_hash_dentry(const struct dentry *dentry, struct qstr
> *str);
> diff --git a/fs/hfsplus/unicode.c b/fs/hfsplus/unicode.c
> index 36b6cf2a3abb..862ba27f1628 100644
> --- a/fs/hfsplus/unicode.c
> +++ b/fs/hfsplus/unicode.c
> @@ -119,9 +119,8 @@ static u16 *hfsplus_compose_lookup(u16 *p, u16
> cc)
>  	return NULL;
>  }
>  
> -int hfsplus_uni2asc(struct super_block *sb,
> -		const struct hfsplus_unistr *ustr,
> -		char *astr, int *len_p)
> +static int hfsplus_uni2asc(struct super_block *sb, const struct
> hfsplus_unistr *ustr,
> +		    int max_len, char *astr, int *len_p)
>  {
>  	const hfsplus_unichr *ip;
>  	struct nls_table *nls = HFSPLUS_SB(sb)->nls;
> @@ -134,8 +133,8 @@ int hfsplus_uni2asc(struct super_block *sb,
>  	ip = ustr->unicode;
>  
>  	ustrlen = be16_to_cpu(ustr->length);
> -	if (ustrlen > HFSPLUS_MAX_STRLEN) {
> -		ustrlen = HFSPLUS_MAX_STRLEN;
> +	if (ustrlen > max_len) {
> +		ustrlen = max_len;
>  		pr_err("invalid length %u has been corrected to
> %d\n",
>  			be16_to_cpu(ustr->length), ustrlen);
>  	}
> @@ -256,6 +255,21 @@ int hfsplus_uni2asc(struct super_block *sb,
>  	return res;
>  }
>  
> +inline int hfsplus_uni2asc_str(struct super_block *sb,
> +			       const struct hfsplus_unistr *ustr,
> char *astr,
> +			       int *len_p)
> +{
> +	return hfsplus_uni2asc(sb, ustr, HFSPLUS_MAX_STRLEN, astr,
> len_p);
> +}
> +
> +inline int hfsplus_uni2asc_xattr_str(struct super_block *sb,
> +				     const struct
> hfsplus_attr_unistr *ustr,
> +				     char *astr, int *len_p)
> +{
> +	return hfsplus_uni2asc(sb, (const struct hfsplus_unistr
> *)ustr,
> +			       HFSPLUS_ATTR_MAX_STRLEN, astr,
> len_p);
> +}
> +
>  /*
>   * Convert one or more ASCII characters into a single unicode
> character.
>   * Returns the number of ASCII characters corresponding to the
> unicode char.
> diff --git a/fs/hfsplus/xattr.c b/fs/hfsplus/xattr.c
> index 18dc3d254d21..c951fa9835aa 100644
> --- a/fs/hfsplus/xattr.c
> +++ b/fs/hfsplus/xattr.c
> @@ -735,9 +735,9 @@ ssize_t hfsplus_listxattr(struct dentry *dentry,
> char *buffer, size_t size)
>  			goto end_listxattr;
>  
>  		xattr_name_len = NLS_MAX_CHARSET_SIZE *
> HFSPLUS_ATTR_MAX_STRLEN;
> -		if (hfsplus_uni2asc(inode->i_sb,
> -			(const struct hfsplus_unistr *)&fd.key-
> >attr.key_name,
> -					strbuf, &xattr_name_len)) {
> +		if (hfsplus_uni2asc_xattr_str(inode->i_sb,
> +					      &fd.key-
> >attr.key_name, strbuf,
> +					      &xattr_name_len)) {
>  			pr_err("unicode conversion failed\n");
>  			res = -EIO;
>  			goto end_listxattr;





[Index of Archives]     [Linux Ext4 Filesystem]     [Union Filesystem]     [Filesystem Testing]     [Ceph Users]     [Ecryptfs]     [NTFS 3]     [AutoFS]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux Cachefs]     [Reiser Filesystem]     [Linux RAID]     [NTFS 3]     [Samba]     [Device Mapper]     [CEPH Development]

  Powered by Linux