diff mbox series

[WIP] query smb3 reparse tags for special files

Message ID CAH2r5mtmPxUKYYK-PbouTFpt9T8AU-41pRZu1CEO=+XLZZ+vSA@mail.gmail.com (mailing list archive)
State New, archived
Headers show
Series [WIP] query smb3 reparse tags for special files | expand

Commit Message

Steve French Oct. 22, 2020, 9:20 a.m. UTC
WSL defines special files with various reparse tags

smbfsctl.h:#define IO_REPARSE_TAG_LX_SYMLINK    0xA000001D
smbfsctl.h:#define IO_REPARSE_TAG_LX_FIFO            0x80000024
smbfsctl.h:#define IO_REPARSE_TAG_LX_CHR             0x80000025
smbfsctl.h:#define IO_REPARSE_TAG_LX_BLK             0x80000026

These also make sense for us to use more broadly because it simplifies readdir

but ... my first attempt at querying this using infolevel 33
FileReparsePointInformation (see MS-FSCC section 2.4.35) failed ...
with Windows 10 returning STATUS_NOT_SUPPORTED when querying various
reparse points (created by WSL indirectly) including fifos, symlinks
and char devices.

I can switch approaches and try to do the smb3 fsctl to query reparse
info instead but was hoping that query info would work.  Any idea if
there is another info level that would allow me to query the tag?

In any case, here is the WIP first stage of the patch - I have to add
a second patch to add the fsctl query

Comments

Aurélien Aptel Oct. 22, 2020, 11:37 a.m. UTC | #1
Steve French <smfrench@gmail.com> writes:
> smbfsctl.h:#define IO_REPARSE_TAG_LX_SYMLINK    0xA000001D
> smbfsctl.h:#define IO_REPARSE_TAG_LX_FIFO            0x80000024
> smbfsctl.h:#define IO_REPARSE_TAG_LX_CHR             0x80000025
> smbfsctl.h:#define IO_REPARSE_TAG_LX_BLK             0x80000026
>
> These also make sense for us to use more broadly because it simplifies readdir
>
> but ... my first attempt at querying this using infolevel 33
> FileReparsePointInformation (see MS-FSCC section 2.4.35) failed ...
> with Windows 10 returning STATUS_NOT_SUPPORTED when querying various
> reparse points (created by WSL indirectly) including fifos, symlinks
> and char devices.
>
> I can switch approaches and try to do the smb3 fsctl to query reparse
> info instead but was hoping that query info would work.  Any idea if
> there is another info level that would allow me to query the tag?

According to [MS-FSCC] if the file has the REPARSE_TAG attribute, the
EaSize field must be interpreted as a reparse tag for these info levels:

* FileFullDirectoryInfo
* FileBothDirectoryInfo
* FileIdFullDirectoryInfo
* FileIdBothDirectoryInfo

Otherwise we have code for querying the reparse tag in
smb2_query_symlink():

	rc = SMB2_ioctl_init(tcon, server,
			     &rqst[1], fid.persistent_fid,
			     fid.volatile_fid, FSCTL_GET_REPARSE_POINT,
			     true /* is_fctl */, NULL, 0,
			     CIFSMaxBufSize -
			     MAX_SMB2_CREATE_RESPONSE_SIZE -
			     MAX_SMB2_CLOSE_RESPONSE_SIZE);
Steve French Oct. 22, 2020, 5:14 p.m. UTC | #2
on query dir I see the EAsize set to the reparse tag as expected (in
query dir), but not on FILE_ALL_INFO (query info).

So as you indicated, there are only the query dir info levels (not
query info ones) which allow returning what we need for reparse point
special files - so will have to use fsctl as in smb2_query_symlink.


On Thu, Oct 22, 2020 at 6:37 AM Aurélien Aptel <aaptel@suse.com> wrote:
>
> Steve French <smfrench@gmail.com> writes:
> > smbfsctl.h:#define IO_REPARSE_TAG_LX_SYMLINK    0xA000001D
> > smbfsctl.h:#define IO_REPARSE_TAG_LX_FIFO            0x80000024
> > smbfsctl.h:#define IO_REPARSE_TAG_LX_CHR             0x80000025
> > smbfsctl.h:#define IO_REPARSE_TAG_LX_BLK             0x80000026
> >
> > These also make sense for us to use more broadly because it simplifies readdir
> >
> > but ... my first attempt at querying this using infolevel 33
> > FileReparsePointInformation (see MS-FSCC section 2.4.35) failed ...
> > with Windows 10 returning STATUS_NOT_SUPPORTED when querying various
> > reparse points (created by WSL indirectly) including fifos, symlinks
> > and char devices.
> >
> > I can switch approaches and try to do the smb3 fsctl to query reparse
> > info instead but was hoping that query info would work.  Any idea if
> > there is another info level that would allow me to query the tag?
>
> According to [MS-FSCC] if the file has the REPARSE_TAG attribute, the
> EaSize field must be interpreted as a reparse tag for these info levels:
>
> * FileFullDirectoryInfo
> * FileBothDirectoryInfo
> * FileIdFullDirectoryInfo
> * FileIdBothDirectoryInfo
>
> Otherwise we have code for querying the reparse tag in
> smb2_query_symlink():
>
>         rc = SMB2_ioctl_init(tcon, server,
>                              &rqst[1], fid.persistent_fid,
>                              fid.volatile_fid, FSCTL_GET_REPARSE_POINT,
>                              true /* is_fctl */, NULL, 0,
>                              CIFSMaxBufSize -
>                              MAX_SMB2_CREATE_RESPONSE_SIZE -
>                              MAX_SMB2_CLOSE_RESPONSE_SIZE);
>
> --
> Aurélien Aptel / SUSE Labs Samba Team
> GPG: 1839 CB5F 9F5B FB9B AA97  8C99 03C8 A49B 521B D5D3
> SUSE Software Solutions Germany GmbH, Maxfeldstr. 5, 90409 Nürnberg, DE
> GF: Felix Imendörffer, Mary Higgins, Sri Rasiah HRB 247165 (AG München)
>
diff mbox series

Patch

diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index b6925aeeb621..484ec2d8c5c9 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -298,6 +298,10 @@  struct smb_version_operations {
 	/* query file data from the server */
 	int (*query_file_info)(const unsigned int, struct cifs_tcon *,
 			       struct cifs_fid *, FILE_ALL_INFO *);
+	/* query reparse tag from srv to determine which type of special file */
+	int (*query_reparse_tag)(const unsigned int xid, struct cifs_tcon *tcon,
+				struct cifs_sb_info *cifs_sb, const char *path,
+				__u32 *reparse_tag);
 	/* get server index number */
 	int (*get_srv_inum)(const unsigned int, struct cifs_tcon *,
 			    struct cifs_sb_info *, const char *,
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index daec31be8571..fe20643450a1 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -916,6 +916,7 @@  cifs_get_inode_info(struct inode **inode,
 	void *smb1_backup_rsp_buf = NULL;
 	int rc = 0;
 	int tmprc = 0;
+	__u32 reparse_tag = 0;
 
 	tlink = cifs_sb_tlink(cifs_sb);
 	if (IS_ERR(tlink))
@@ -941,6 +942,16 @@  cifs_get_inode_info(struct inode **inode,
 						  full_path, tmp_data,
 						  &adjust_tz, &symlink);
 		data = tmp_data;
+
+		/*
+		 * If the file is a reparse point, it is more complicated
+		 * since we have to check if its reparse tag matches a known
+		 * special file type e.g. symlink or fifo or char etc.
+		 */
+		if ((le32_to_cpu(data->Attributes) & ATTR_REPARSE) &&
+		    (server->ops->query_reparse_tag))
+			rc = server->ops->query_reparse_tag(xid, tcon, cifs_sb,
+						full_path, &reparse_tag);
 	}
 
 	/*
diff --git a/fs/cifs/smb2inode.c b/fs/cifs/smb2inode.c
index df6212e55e10..109ec166aa6a 100644
--- a/fs/cifs/smb2inode.c
+++ b/fs/cifs/smb2inode.c
@@ -503,10 +503,26 @@  move_smb2_info_to_cifs(FILE_ALL_INFO *dst, struct smb2_file_all_info *src)
 	dst->IndexNumber1 = 0; /* we don't use it */
 }
 
+/* query reparse tag from srv to determine which type of special file */
+int smb2_query_reparse_tag(const unsigned int xid, struct cifs_tcon *tcon,
+		struct cifs_sb_info *cifs_sb, const char *path, __u32 *tag)
+{
+	int rc = 0;
+	__u32 create_options = OPEN_REPARSE_POINT;
+	struct cifsFileInfo *cfile;
+
+	cifs_get_readable_path(tcon, path, &cfile);
+
+		/* TODO update below */
+	/* rc = smb2_fsctl_get_tag(xid, tcon, cifs_sb, path,... */
+
+	return rc;
+}
+
 int
 smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
 		     struct cifs_sb_info *cifs_sb, const char *full_path,
-		     FILE_ALL_INFO *data, bool *adjust_tz, bool *symlink)
+		     FILE_ALL_INFO *data, bool *adjust_tz, bool *reparse)
 {
 	int rc;
 	struct smb2_file_all_info *smb2_data;
@@ -516,7 +532,7 @@  smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
 	struct cached_fid *cfid = NULL;
 
 	*adjust_tz = false;
-	*symlink = false;
+	*reparse = false;
 
 	smb2_data = kzalloc(sizeof(struct smb2_file_all_info) + PATH_MAX * 2,
 			    GFP_KERNEL);
@@ -548,7 +564,7 @@  smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
 			      FILE_READ_ATTRIBUTES, FILE_OPEN, create_options,
 			      ACL_NO_MODE, smb2_data, SMB2_OP_QUERY_INFO, cfile);
 	if (rc == -EOPNOTSUPP) {
-		*symlink = true;
+		*reparse = true;
 		create_options |= OPEN_REPARSE_POINT;
 
 		/* Failed on a symbolic link - query a reparse point info */
@@ -570,7 +586,7 @@  smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
 int
 smb311_posix_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
 		     struct cifs_sb_info *cifs_sb, const char *full_path,
-		     struct smb311_posix_qinfo *data, bool *adjust_tz, bool *symlink)
+		     struct smb311_posix_qinfo *data, bool *adjust_tz, bool *reparse)
 {
 	int rc;
 	__u32 create_options = 0;
@@ -578,7 +594,7 @@  smb311_posix_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
 	struct smb311_posix_qinfo *smb2_data;
 
 	*adjust_tz = false;
-	*symlink = false;
+	*reparse = false;
 
 	/* BB TODO: Make struct larger when add support for parsing owner SIDs */
 	smb2_data = kzalloc(sizeof(struct smb311_posix_qinfo),
@@ -599,7 +615,7 @@  smb311_posix_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
 			      ACL_NO_MODE, smb2_data, SMB2_OP_POSIX_QUERY_INFO, cfile);
 	if (rc == -EOPNOTSUPP) {
 		/* BB TODO: When support for special files added to Samba re-verify this path */
-		*symlink = true;
+		*reparse = true;
 		create_options |= OPEN_REPARSE_POINT;
 
 		/* Failed on a symbolic link - query a reparse point info */
diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h
index 171f54965703..14244d288b80 100644
--- a/fs/cifs/smb2pdu.h
+++ b/fs/cifs/smb2pdu.h
@@ -1691,6 +1691,11 @@  struct smb2_file_eof_info { /* encoding of request for level 10 */
 	__le64 EndOfFile; /* new end of file value */
 } __packed; /* level 20 Set */
 
+struct smb2_file_reparse_point_info {
+	__le64 IndexNumber;
+	__le32 Tag;
+} __packed;
+
 struct smb2_file_network_open_info {
 	__le64 CreationTime;
 	__le64 LastAccessTime;
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index 67c50d78caa1..d4110447ee3a 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -77,6 +77,9 @@  extern void close_shroot_lease(struct cached_fid *cfid);
 extern void close_shroot_lease_locked(struct cached_fid *cfid);
 extern void move_smb2_info_to_cifs(FILE_ALL_INFO *dst,
 				   struct smb2_file_all_info *src);
+extern int smb2_query_reparse_tag(const unsigned int xid, struct cifs_tcon *tcon,
+				struct cifs_sb_info *cifs_sb, const char *path,
+				__u32 *reparse_tag);
 extern int smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
 				struct cifs_sb_info *cifs_sb,
 				const char *full_path, FILE_ALL_INFO *data,