smb: client: fix one-byte OOB read in smb2_parse_native_symlink()

When parsing a share-root relative native symlink, memcpy copies
smb_target+1 (skipping the leading separator) but uses
strlen(smb_target)+1 as the length, reading one byte past the
allocated buffer.

This fixes the following KASAN splat when accessing an SMB symlink
with a target of '\a\b':

  BUG: KASAN: slab-out-of-bounds in smb2_parse_native_symlink+0x4f5/0xca0
  Read of size 5 at addr ffff88800878fe21 by task netfsfuzz-execu/1
  CPU: 1 UID: 0 PID: 1 Comm: netfsfuzz-execu Tainted: G N
  7.2.0-11943-g2709dd5ae32f-dirty #1 PREEMPT(lazy)
  Hardware name: QEMU Ubuntu 24.04 PC v2 (i440FX + PIIX, arch_caps fix,
  1996)
  Call Trace:
   <TASK>
   dump_stack_lvl+0x7b/0xa0
   print_report+0xd0/0x630
   kasan_report+0xe5/0x120
   kasan_check_range+0x105/0x1b0
   __asan_memcpy+0x23/0x60
   smb2_parse_native_symlink+0x4f5/0xca0
   parse_reparse_point+0x68a/0x1530
   reparse_info_to_fattr+0x752/0xa20
   cifs_get_fattr+0x873/0x15b0
   cifs_get_inode_info+0xc0/0x310
   cifs_lookup+0x308/0xa70
   __lookup_slow+0x122/0x2b0
   lookup_slow+0x50/0x70
   path_lookupat+0x525/0xaf0
   filename_lookup+0x1f2/0x550
   vfs_statx+0xd1/0x1a0
   vfs_fstatat+0x65/0xc0
   __do_sys_newfstatat+0x9a/0x120
   do_syscall_64+0xdd/0x4a0
   entry_SYSCALL_64_after_hwframe+0x77/0x7f

Reported-by: Yuanfu Xie <yuanfuxie@stu.pku.edu.cn>
Fixes: 723f4ef904 ("cifs: Fix parsing native symlinks relative to the export")
Suggested-by: Pali Rohar <pali@kernel.org>
Reviewed-by: Pali Rohar <pali@kernel.org>
Reviewed-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Paulo Alcantara <pc@manguebit.org>
Cc: Ronnie Sahlberg <ronniesahlberg@gmail.com>
Cc: Shyam Prasad N <sprasad@microsoft.com>
Cc: Tom Talpey <tom@talpey.com>
Cc: Bharath SM <bharathsm@microsoft.com>
Cc: stable@vger.kernel.org
This commit is contained in:
Paulo Alcantara 2026-09-09 17:02:40 -03:00
parent d05045177a
commit cb26524ef4

View File

@ -971,7 +971,8 @@ int smb2_parse_native_symlink(char **target, const char *buf, unsigned int len,
linux_target[i*3 + 1] = '.';
linux_target[i*3 + 2] = sep;
}
memcpy(linux_target + levels*3, smb_target+1, smb_target_len); /* +1 to skip leading sep */
/* +1 to skip leading sep */
memcpy(linux_target + levels*3, smb_target+1, smb_target_len-1);
} else {
/*
* This is either an absolute symlink in POSIX-style format