* [PATCH] cifs: Add support for parsing WSL-style symlinks
@ 2024-10-06 9:05 Pali Rohár
[not found] ` <202410080458.o4vvmJkR-lkp@intel.com>
2024-11-25 21:24 ` Steve French
0 siblings, 2 replies; 4+ messages in thread
From: Pali Rohár @ 2024-10-06 9:05 UTC (permalink / raw)
To: Steve French, Paulo Alcantara, Ronnie Sahlberg; +Cc: linux-cifs, linux-kernel
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(+)
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];
--
2.20.1
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH] cifs: Add support for parsing WSL-style symlinks
[not found] ` <202410080458.o4vvmJkR-lkp@intel.com>
@ 2024-10-07 21:34 ` Pali Rohár
0 siblings, 0 replies; 4+ messages in thread
From: Pali Rohár @ 2024-10-07 21:34 UTC (permalink / raw)
To: kernel test robot; +Cc: oe-kbuild-all, Steve French, linux-cifs
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
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] cifs: Add support for parsing WSL-style symlinks
2024-10-06 9:05 [PATCH] cifs: Add support for parsing WSL-style symlinks Pali Rohár
[not found] ` <202410080458.o4vvmJkR-lkp@intel.com>
@ 2024-11-25 21:24 ` Steve French
2024-11-25 22:25 ` Pali Rohár
1 sibling, 1 reply; 4+ messages in thread
From: Steve French @ 2024-11-25 21:24 UTC (permalink / raw)
To: Pali Rohár
Cc: Steve French, Paulo Alcantara, Ronnie Sahlberg, linux-cifs,
linux-kernel
This patch
commit 06a7adf318a30bdcfa1222ed6d2640e6bb266d7b
Author: Pali Rohár <pali@kernel.org>
Date: Sat Sep 28 13:21:24 2024 +0200
cifs: Add support for parsing WSL-style symlinks
led to compile warning:
CC [M] fs/smb/client/reparse.o
CHECK fs/smb/client/reparse.c
fs/smb/client/reparse.c:679:45: warning: incorrect type in argument 4
(different base types)
fs/smb/client/reparse.c:679:45: expected unsigned short [usertype] *pwcs
fs/smb/client/reparse.c:679:45: got restricted __le16 [usertype]
*[assigned] symname_utf16
Let me know if updated version needed
On Sun, Oct 6, 2024 at 4:07 AM Pali Rohár <pali@kernel.org> wrote:
>
> 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(+)
>
> 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];
> --
> 2.20.1
>
>
--
Thanks,
Steve
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] cifs: Add support for parsing WSL-style symlinks
2024-11-25 21:24 ` Steve French
@ 2024-11-25 22:25 ` Pali Rohár
0 siblings, 0 replies; 4+ messages in thread
From: Pali Rohár @ 2024-11-25 22:25 UTC (permalink / raw)
To: Steve French
Cc: Steve French, Paulo Alcantara, Ronnie Sahlberg, linux-cifs,
linux-kernel
On Monday 25 November 2024 15:24:03 Steve French wrote:
> This patch
>
> commit 06a7adf318a30bdcfa1222ed6d2640e6bb266d7b
> Author: Pali Rohár <pali@kernel.org>
> Date: Sat Sep 28 13:21:24 2024 +0200
>
> cifs: Add support for parsing WSL-style symlinks
>
>
> led to compile warning:
>
> CC [M] fs/smb/client/reparse.o
> CHECK fs/smb/client/reparse.c
> fs/smb/client/reparse.c:679:45: warning: incorrect type in argument 4
> (different base types)
> fs/smb/client/reparse.c:679:45: expected unsigned short [usertype] *pwcs
> fs/smb/client/reparse.c:679:45: got restricted __le16 [usertype]
> *[assigned] symname_utf16
>
>
> Let me know if updated version needed
I have already reacted for this problem more than month ago:
https://lore.kernel.org/oe-kbuild-all/20241007213401.bsfqwlb4c2k6ynlr@pali/
But nobody on the list replied :-( So I do not know what is the best way
to handle this issue.
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2024-11-25 22:25 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-10-06 9:05 [PATCH] cifs: Add support for parsing WSL-style symlinks Pali Rohár
[not found] ` <202410080458.o4vvmJkR-lkp@intel.com>
2024-10-07 21:34 ` Pali Rohár
2024-11-25 21:24 ` Steve French
2024-11-25 22:25 ` Pali Rohár
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox