Message ID | 20241006090548.30053-1-pali@kernel.org (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | cifs: Add support for parsing WSL-style symlinks | expand |
On Tuesday 08 October 2024 04:21:30 kernel test robot wrote: > Hi Pali, > > kernel test robot noticed the following build warnings: > > [auto build test WARNING on cifs/for-next] > [also build test WARNING on linus/master v6.12-rc2 next-20241004] > [If your patch is applied to the wrong git tree, kindly drop us a note. > And when submitting patch, we suggest to use '--base' as documented in > https://git-scm.com/docs/git-format-patch#_base_tree_information] > > url: https://github.com/intel-lab-lkp/linux/commits/Pali-Roh-r/cifs-Add-support-for-parsing-WSL-style-symlinks/20241006-170802 > base: git://git.samba.org/sfrench/cifs-2.6.git for-next > patch link: https://lore.kernel.org/r/20241006090548.30053-1-pali%40kernel.org > patch subject: [PATCH] cifs: Add support for parsing WSL-style symlinks > config: x86_64-randconfig-122-20241008 (https://download.01.org/0day-ci/archive/20241008/202410080458.o4vvmJkR-lkp@intel.com/config) > compiler: clang version 18.1.8 (https://github.com/llvm/llvm-project 3b5b5c1ec4a3095ab096dd780e84d7ab81f3d7ff) > reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20241008/202410080458.o4vvmJkR-lkp@intel.com/reproduce) > > If you fix the issue in a separate patch/commit (i.e. not just a new version of > the same patch/commit), kindly add following tags > | Reported-by: kernel test robot <lkp@intel.com> > | Closes: https://lore.kernel.org/oe-kbuild-all/202410080458.o4vvmJkR-lkp@intel.com/ > > sparse warnings: (new ones prefixed by >>) > >> fs/smb/client/reparse.c:676:45: sparse: sparse: incorrect type in argument 4 (different base types) @@ expected unsigned short [usertype] *pwcs @@ got restricted __le16 [usertype] *[assigned] symname_utf16 @@ > fs/smb/client/reparse.c:676:45: sparse: expected unsigned short [usertype] *pwcs > fs/smb/client/reparse.c:676:45: sparse: got restricted __le16 [usertype] *[assigned] symname_utf16 > > vim +676 fs/smb/client/reparse.c > > 646 > 647 static int parse_reparse_wsl_symlink(struct reparse_wsl_symlink_data_buffer *buf, > 648 struct cifs_sb_info *cifs_sb, > 649 struct cifs_open_info_data *data) > 650 { > 651 int len = le16_to_cpu(buf->ReparseDataLength); > 652 int symname_utf8_len; > 653 __le16 *symname_utf16; > 654 int symname_utf16_len; > 655 > 656 if (len <= sizeof(buf->Flags)) { > 657 cifs_dbg(VFS, "srv returned malformed wsl symlink buffer\n"); > 658 return -EIO; > 659 } > 660 > 661 /* PathBuffer is in UTF-8 but without trailing null-term byte */ > 662 symname_utf8_len = len - sizeof(buf->Flags); > 663 /* > 664 * Check that buffer does not contain null byte > 665 * because Linux cannot process symlink with null byte. > 666 */ > 667 if (strnlen(buf->PathBuffer, symname_utf8_len) != symname_utf8_len) { > 668 cifs_dbg(VFS, "srv returned null byte in wsl symlink target location\n"); > 669 return -EIO; > 670 } > 671 symname_utf16 = kzalloc(symname_utf8_len * 2, GFP_KERNEL); > 672 if (!symname_utf16) > 673 return -ENOMEM; > 674 symname_utf16_len = utf8s_to_utf16s(buf->PathBuffer, symname_utf8_len, > 675 UTF16_LITTLE_ENDIAN, > > 676 symname_utf16, symname_utf8_len * 2); Hello, I'm not sure if there is a real problem or it is just a false-positive report. Please look at it. I saw that in cifs code is common pattern to use __le16* type for UTF-16-LE string. Kernel nls library function utf8s_to_utf16s for output buffer is expecting wchar_t* type, also for the case when it is encoding to UTF-16-LE (requested by UTF16_LITTLE_ENDIAN). And cifs_strndup_from_utf16 for input UTF-16-LE string is using u8* type. So what kind of type for symname_utf16 buffer should be used? It stores UTF-16-LE string. Type u8*, u16*, __le16*, wchar_t* or short*? I guess that it should be possible to mute this report by adding another explicit cast and call utf8s_to_utf16s() with "(wchar_t*)symname_utf16" as 4th parameter. > 677 if (symname_utf16_len < 0) { > 678 kfree(symname_utf16); > 679 return symname_utf16_len; > 680 } > 681 symname_utf16_len *= 2; /* utf8s_to_utf16s() returns number of u16 items, not byte length */ > 682 > 683 data->symlink_target = cifs_strndup_from_utf16((u8 *)symname_utf16, > 684 symname_utf16_len, true, > 685 cifs_sb->local_nls); > 686 kfree(symname_utf16); > 687 if (!data->symlink_target) > 688 return -ENOMEM; > 689 > 690 return 0; > 691 } > 692 > > -- > 0-DAY CI Kernel Test Service > https://github.com/intel/lkp-tests/wiki
diff --git a/fs/smb/client/reparse.c b/fs/smb/client/reparse.c index a577b2d2a4fc..6e9d914bac41 100644 --- a/fs/smb/client/reparse.c +++ b/fs/smb/client/reparse.c @@ -875,6 +875,52 @@ static int parse_reparse_symlink(struct reparse_symlink_data_buffer *sym, cifs_sb); } +static int parse_reparse_wsl_symlink(struct reparse_wsl_symlink_data_buffer *buf, + struct cifs_sb_info *cifs_sb, + struct cifs_open_info_data *data) +{ + int len = le16_to_cpu(buf->ReparseDataLength); + int symname_utf8_len; + __le16 *symname_utf16; + int symname_utf16_len; + + if (len <= sizeof(buf->Flags)) { + cifs_dbg(VFS, "srv returned malformed wsl symlink buffer\n"); + return -EIO; + } + + /* PathBuffer is in UTF-8 but without trailing null-term byte */ + symname_utf8_len = len - sizeof(buf->Flags); + /* + * Check that buffer does not contain null byte + * because Linux cannot process symlink with null byte. + */ + if (strnlen(buf->PathBuffer, symname_utf8_len) != symname_utf8_len) { + cifs_dbg(VFS, "srv returned null byte in wsl symlink target location\n"); + return -EIO; + } + symname_utf16 = kzalloc(symname_utf8_len * 2, GFP_KERNEL); + if (!symname_utf16) + return -ENOMEM; + symname_utf16_len = utf8s_to_utf16s(buf->PathBuffer, symname_utf8_len, + UTF16_LITTLE_ENDIAN, + symname_utf16, symname_utf8_len * 2); + if (symname_utf16_len < 0) { + kfree(symname_utf16); + return symname_utf16_len; + } + symname_utf16_len *= 2; /* utf8s_to_utf16s() returns number of u16 items, not byte length */ + + data->symlink_target = cifs_strndup_from_utf16((u8 *)symname_utf16, + symname_utf16_len, true, + cifs_sb->local_nls); + kfree(symname_utf16); + if (!data->symlink_target) + return -ENOMEM; + + return 0; +} + int parse_reparse_point(struct reparse_data_buffer *buf, u32 plen, struct cifs_sb_info *cifs_sb, const char *full_path, @@ -894,6 +940,9 @@ int parse_reparse_point(struct reparse_data_buffer *buf, (struct reparse_symlink_data_buffer *)buf, plen, unicode, cifs_sb, full_path, data); case IO_REPARSE_TAG_LX_SYMLINK: + return parse_reparse_wsl_symlink( + (struct reparse_wsl_symlink_data_buffer *)buf, + cifs_sb, data); case IO_REPARSE_TAG_AF_UNIX: case IO_REPARSE_TAG_LX_FIFO: case IO_REPARSE_TAG_LX_CHR: diff --git a/fs/smb/common/smb2pdu.h b/fs/smb/common/smb2pdu.h index c769f9dbc0b4..275184c31a89 100644 --- a/fs/smb/common/smb2pdu.h +++ b/fs/smb/common/smb2pdu.h @@ -1552,6 +1552,15 @@ struct reparse_symlink_data_buffer { /* See MS-FSCC 2.1.2.6 and cifspdu.h for struct reparse_posix_data */ +/* For IO_REPARSE_TAG_LX_SYMLINK */ +struct reparse_wsl_symlink_data_buffer { + __le32 ReparseTag; + __le16 ReparseDataLength; + __u16 Reserved; + __le32 Flags; + __u8 PathBuffer[]; /* Variable Length UTF-8 string without nul-term */ +} __packed; + struct validate_negotiate_info_req { __le32 Capabilities; __u8 Guid[SMB2_CLIENT_GUID_SIZE];
Linux CIFS client currently does not implement readlink() for WSL-style symlinks. It is only able to detect that file is of WSL-style symlink, but is not able to read target symlink location. Add this missing functionality and implement support for parsing content of WSL-style symlink. The important note is that symlink target location stored for WSL symlink reparse point (IO_REPARSE_TAG_LX_SYMLINK) is in UTF-8 encoding instead of UTF-16 (which is used in whole SMB protocol and also in all other symlink styles). So for proper locale/cp support it is needed to do conversion from UTF-8 to local_nls. Signed-off-by: Pali Rohár <pali@kernel.org> --- fs/smb/client/reparse.c | 49 +++++++++++++++++++++++++++++++++++++++++ fs/smb/common/smb2pdu.h | 9 ++++++++ 2 files changed, 58 insertions(+)