Skip to content

Commit c7efac7

Browse files
paliSteve French
authored and
Steve French
committed
cifs: Fix support for WSL-style symlinks
MS-FSCC in section 2.1.2.7 LX SYMLINK REPARSE_DATA_BUFFER now contains documentation about WSL symlink reparse point buffers. https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/68337353-9153-4ee1-ac6b-419839c3b7ad Fix the struct reparse_wsl_symlink_data_buffer to reflect buffer fields according to the MS-FSCC documentation. Fix the Linux SMB client to correctly fill the WSL symlink reparse point buffer when creaing new WSL-style symlink. There was a mistake during filling the data part of the reparse point buffer. It should starts with bytes "\x02\x00\x00\x00" (which represents version 2) but this constant was written as number 0x02000000 encoded in little endian, which resulted bytes "\x00\x00\x00\x02". This change is fixing this mistake. Fixes: 4e2043b ("cifs: Add support for creating WSL-style symlinks") Signed-off-by: Pali Rohár <[email protected]> Signed-off-by: Steve French <[email protected]>
1 parent b365b9d commit c7efac7

File tree

2 files changed

+19
-12
lines changed

2 files changed

+19
-12
lines changed

fs/smb/client/reparse.c

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -542,12 +542,12 @@ static int wsl_set_reparse_buf(struct reparse_data_buffer **buf,
542542
kfree(symname_utf16);
543543
return -ENOMEM;
544544
}
545-
/* Flag 0x02000000 is unknown, but all wsl symlinks have this value */
546-
symlink_buf->Flags = cpu_to_le32(0x02000000);
547-
/* PathBuffer is in UTF-8 but without trailing null-term byte */
545+
/* Version field must be set to 2 (MS-FSCC 2.1.2.7) */
546+
symlink_buf->Version = cpu_to_le32(2);
547+
/* Target for Version 2 is in UTF-8 but without trailing null-term byte */
548548
symname_utf8_len = utf16s_to_utf8s((wchar_t *)symname_utf16, symname_utf16_len/2,
549549
UTF16_LITTLE_ENDIAN,
550-
symlink_buf->PathBuffer,
550+
symlink_buf->Target,
551551
symname_utf8_maxlen);
552552
*buf = (struct reparse_data_buffer *)symlink_buf;
553553
buf_len = sizeof(struct reparse_wsl_symlink_data_buffer) + symname_utf8_len;
@@ -1016,29 +1016,36 @@ static int parse_reparse_wsl_symlink(struct reparse_wsl_symlink_data_buffer *buf
10161016
struct cifs_open_info_data *data)
10171017
{
10181018
int len = le16_to_cpu(buf->ReparseDataLength);
1019+
int data_offset = offsetof(typeof(*buf), Target) - offsetof(typeof(*buf), Version);
10191020
int symname_utf8_len;
10201021
__le16 *symname_utf16;
10211022
int symname_utf16_len;
10221023

1023-
if (len <= sizeof(buf->Flags)) {
1024+
if (len <= data_offset) {
10241025
cifs_dbg(VFS, "srv returned malformed wsl symlink buffer\n");
10251026
return -EIO;
10261027
}
10271028

1028-
/* PathBuffer is in UTF-8 but without trailing null-term byte */
1029-
symname_utf8_len = len - sizeof(buf->Flags);
1029+
/* MS-FSCC 2.1.2.7 defines layout of the Target field only for Version 2. */
1030+
if (le32_to_cpu(buf->Version) != 2) {
1031+
cifs_dbg(VFS, "srv returned unsupported wsl symlink version %u\n", le32_to_cpu(buf->Version));
1032+
return -EIO;
1033+
}
1034+
1035+
/* Target for Version 2 is in UTF-8 but without trailing null-term byte */
1036+
symname_utf8_len = len - data_offset;
10301037
/*
10311038
* Check that buffer does not contain null byte
10321039
* because Linux cannot process symlink with null byte.
10331040
*/
1034-
if (strnlen(buf->PathBuffer, symname_utf8_len) != symname_utf8_len) {
1041+
if (strnlen(buf->Target, symname_utf8_len) != symname_utf8_len) {
10351042
cifs_dbg(VFS, "srv returned null byte in wsl symlink target location\n");
10361043
return -EIO;
10371044
}
10381045
symname_utf16 = kzalloc(symname_utf8_len * 2, GFP_KERNEL);
10391046
if (!symname_utf16)
10401047
return -ENOMEM;
1041-
symname_utf16_len = utf8s_to_utf16s(buf->PathBuffer, symname_utf8_len,
1048+
symname_utf16_len = utf8s_to_utf16s(buf->Target, symname_utf8_len,
10421049
UTF16_LITTLE_ENDIAN,
10431050
(wchar_t *) symname_utf16, symname_utf8_len * 2);
10441051
if (symname_utf16_len < 0) {

fs/smb/common/smb2pdu.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1567,13 +1567,13 @@ struct reparse_nfs_data_buffer {
15671567
__u8 DataBuffer[];
15681568
} __packed;
15691569

1570-
/* For IO_REPARSE_TAG_LX_SYMLINK */
1570+
/* For IO_REPARSE_TAG_LX_SYMLINK - see MS-FSCC 2.1.2.7 */
15711571
struct reparse_wsl_symlink_data_buffer {
15721572
__le32 ReparseTag;
15731573
__le16 ReparseDataLength;
15741574
__u16 Reserved;
1575-
__le32 Flags;
1576-
__u8 PathBuffer[]; /* Variable Length UTF-8 string without nul-term */
1575+
__le32 Version; /* Always 2 */
1576+
__u8 Target[]; /* Variable Length UTF-8 string without nul-term */
15771577
} __packed;
15781578

15791579
struct validate_negotiate_info_req {

0 commit comments

Comments
 (0)