Discussion:
Distinguishing between different types of reparse point symlinks
Steve French
2013-09-27 05:58:05 UTC
Permalink
I have to make some minor fixes to the patch below to account for
little endian specific fields in symlink reparse point structure, but
it does fix the problem ("ls -l" to windows 8 or later share which has
multiple types of reparse points in the same directory, not all of
which are NTFS symlinks).

From: Steve French <smfrench-***@public.gmane.org>
Date: Thu, 26 Sep 2013 19:49:14 -0500
Subject: [PATCH] [CIFS] do not treat non-symlink reparse points as valid
symlinks

Windows 8 and later can create NFS symlinks (within reparse points)
which we were assuming were normal NTFS symlinks and thus reporting
corrupt paths for. Add check for reparse points to make sure that
they really are normal symlinks before we try to parse the pathname.

This fixes commit d244bf2dfbebfded05f494ffd53659fa7b1e32c1
which implemented follow link for non-Unix CIFS mounts

CC: Stable <stable-DgEjT+Ai2ygdnm+***@public.gmane.org>
Reviewed-by: Andrew Bartlett <abartlet-***@public.gmane.org>
Signed-off-by: Steve French <smfrench-***@public.gmane.org>
---
fs/cifs/cifspdu.h | 2 +-
fs/cifs/cifssmb.c | 9 +++++++--
fs/cifs/smbfsctl.h | 14 ++++++++++++++
3 files changed, 22 insertions(+), 3 deletions(-)

diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h
index a630475..5f295f3 100644
--- a/fs/cifs/cifspdu.h
+++ b/fs/cifs/cifspdu.h
@@ -1491,7 +1491,7 @@ struct file_notify_information {
__u8 FileName[0];
} __attribute__((packed));

-struct reparse_data {
+struct reparse_symlink_data {
__u32 ReparseTag;
__u16 ReparseDataLength;
__u16 Reserved;
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 4baf359..0bf7635 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -3088,7 +3088,7 @@ CIFSSMBQuerySymLink(const unsigned int xid,
struct cifs_tcon *tcon,
bool is_unicode;
unsigned int sub_len;
char *sub_start;
- struct reparse_data *reparse_buf;
+ struct reparse_symlink_data *reparse_buf;
__u32 data_offset, data_count;
char *end_of_smb;

@@ -3137,12 +3137,17 @@ CIFSSMBQuerySymLink(const unsigned int xid,
struct cifs_tcon *tcon,
goto qreparse_out;
}
end_of_smb = 2 + get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
- reparse_buf = (struct reparse_data *)
+ reparse_buf = (struct reparse_symlink_data *)
((char *)&pSMBr->hdr.Protocol + data_offset);
if ((char *)reparse_buf >= end_of_smb) {
rc = -EIO;
goto qreparse_out;
}
+ if (reparse_buf->ReparseTag != IO_REPARSE_TAG_SYMLINK) {
+ rc = -EOPNOTSUPP;
+ goto qreparse_out;
+ }
+
if ((reparse_buf->PathBuffer + reparse_buf->PrintNameOffset +
reparse_buf->PrintNameLength) > end_of_smb) {
cifs_dbg(FYI, "reparse buf beyond SMB\n");
diff --git a/fs/cifs/smbfsctl.h b/fs/cifs/smbfsctl.h
index d952ee4..3a10e1c 100644
--- a/fs/cifs/smbfsctl.h
+++ b/fs/cifs/smbfsctl.h
@@ -97,9 +97,23 @@
#define FSCTL_QUERY_NETWORK_INTERFACE_INFO 0x001401FC /* BB add struct */
#define FSCTL_SRV_READ_HASH 0x001441BB /* BB add struct */

+/* See FSCC 2.1.2.5 */
#define IO_REPARSE_TAG_MOUNT_POINT 0xA0000003
#define IO_REPARSE_TAG_HSM 0xC0000004
#define IO_REPARSE_TAG_SIS 0x80000007
+#define IO_REPARSE_TAG_HSM2 0x80000006
+#define IO_REPARSE_TAG_DRIVER_EXTENDER 0x80000005
+/* Used by the DFS filter. See MS-DFSC */
+#define IO_REPARSE_TAG_DFS 0x8000000A
+/* Used by the DFS filter See MS-DFSC */
+#define IO_REPARSE_TAG_DFSR 0x80000012
+#define IO_REPARSE_TAG_FILTER_MANAGER 0x8000000B
+/* See section MS-FSCC 2.1.2.4 */
+#define IO_REPARSE_TAG_SYMLINK 0xA000000C
+#define IO_REPARSE_TAG_DEDUP 0x80000013
+#define IO_REPARSE_APPXSTREAM 0xC0000014
+/* NFS symlinks, Win 8/SMB3 and later */
+#define IO_REPARSE_TAG_NFS 0xA0000014

/* fsctl flags */
/* If Flags is set to this value, the request is an FSCTL not ioctl request */
--
1.7.11.7
--
Thanks,

Steve
Pavel Shilovsky
2013-09-27 06:13:39 UTC
Permalink
Post by Steve French
I have to make some minor fixes to the patch below to account for
little endian specific fields in symlink reparse point structure, but
it does fix the problem ("ls -l" to windows 8 or later share which has
multiple types of reparse points in the same directory, not all of
which are NTFS symlinks).
Date: Thu, 26 Sep 2013 19:49:14 -0500
Subject: [PATCH] [CIFS] do not treat non-symlink reparse points as valid
symlinks
Windows 8 and later can create NFS symlinks (within reparse points)
which we were assuming were normal NTFS symlinks and thus reporting
corrupt paths for. Add check for reparse points to make sure that
they really are normal symlinks before we try to parse the pathname.
This fixes commit d244bf2dfbebfded05f494ffd53659fa7b1e32c1
which implemented follow link for non-Unix CIFS mounts
---
fs/cifs/cifspdu.h | 2 +-
fs/cifs/cifssmb.c | 9 +++++++--
fs/cifs/smbfsctl.h | 14 ++++++++++++++
3 files changed, 22 insertions(+), 3 deletions(-)
diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h
index a630475..5f295f3 100644
--- a/fs/cifs/cifspdu.h
+++ b/fs/cifs/cifspdu.h
@@ -1491,7 +1491,7 @@ struct file_notify_information {
__u8 FileName[0];
} __attribute__((packed));
-struct reparse_data {
+struct reparse_symlink_data {
__u32 ReparseTag;
__u16 ReparseDataLength;
__u16 Reserved;
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 4baf359..0bf7635 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -3088,7 +3088,7 @@ CIFSSMBQuerySymLink(const unsigned int xid,
struct cifs_tcon *tcon,
bool is_unicode;
unsigned int sub_len;
char *sub_start;
- struct reparse_data *reparse_buf;
+ struct reparse_symlink_data *reparse_buf;
__u32 data_offset, data_count;
char *end_of_smb;
@@ -3137,12 +3137,17 @@ CIFSSMBQuerySymLink(const unsigned int xid,
struct cifs_tcon *tcon,
goto qreparse_out;
}
end_of_smb = 2 + get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
- reparse_buf = (struct reparse_data *)
+ reparse_buf = (struct reparse_symlink_data *)
((char *)&pSMBr->hdr.Protocol + data_offset);
if ((char *)reparse_buf >= end_of_smb) {
rc = -EIO;
goto qreparse_out;
}
+ if (reparse_buf->ReparseTag != IO_REPARSE_TAG_SYMLINK) {
+ rc = -EOPNOTSUPP;
+ goto qreparse_out;
+ }
+
Shouldn't we do the same things for SMB2?
Post by Steve French
if ((reparse_buf->PathBuffer + reparse_buf->PrintNameOffset +
reparse_buf->PrintNameLength) > end_of_smb) {
cifs_dbg(FYI, "reparse buf beyond SMB\n");
diff --git a/fs/cifs/smbfsctl.h b/fs/cifs/smbfsctl.h
index d952ee4..3a10e1c 100644
--- a/fs/cifs/smbfsctl.h
+++ b/fs/cifs/smbfsctl.h
@@ -97,9 +97,23 @@
#define FSCTL_QUERY_NETWORK_INTERFACE_INFO 0x001401FC /* BB add struct */
#define FSCTL_SRV_READ_HASH 0x001441BB /* BB add struct */
+/* See FSCC 2.1.2.5 */
#define IO_REPARSE_TAG_MOUNT_POINT 0xA0000003
#define IO_REPARSE_TAG_HSM 0xC0000004
#define IO_REPARSE_TAG_SIS 0x80000007
+#define IO_REPARSE_TAG_HSM2 0x80000006
+#define IO_REPARSE_TAG_DRIVER_EXTENDER 0x80000005
+/* Used by the DFS filter. See MS-DFSC */
+#define IO_REPARSE_TAG_DFS 0x8000000A
+/* Used by the DFS filter See MS-DFSC */
+#define IO_REPARSE_TAG_DFSR 0x80000012
+#define IO_REPARSE_TAG_FILTER_MANAGER 0x8000000B
+/* See section MS-FSCC 2.1.2.4 */
+#define IO_REPARSE_TAG_SYMLINK 0xA000000C
+#define IO_REPARSE_TAG_DEDUP 0x80000013
+#define IO_REPARSE_APPXSTREAM 0xC0000014
+/* NFS symlinks, Win 8/SMB3 and later */
+#define IO_REPARSE_TAG_NFS 0xA0000014
/* fsctl flags */
/* If Flags is set to this value, the request is an FSCTL not ioctl request */
--
1.7.11.7
--
Thanks,
Steve
--
To unsubscribe from this list: send the line "unsubscribe linux-cifs" in
More majordomo info at http://vger.kernel.org/majordomo-info.html
--
Best regards,
Pavel Shilovsky.
Loading...