@@ -85,6 +85,82 @@ static int parse_posix_sids(struct cifs_open_info_data *data,
8585 return 0 ;
8686}
8787
88+ struct wsl_query_ea {
89+ __le32 next ;
90+ __u8 name_len ;
91+ __u8 name [SMB2_WSL_XATTR_NAME_LEN + 1 ];
92+ } __packed ;
93+
94+ #define NEXT_OFF cpu_to_le32(sizeof(struct wsl_query_ea))
95+
96+ static const struct wsl_query_ea wsl_query_eas [] = {
97+ { .next = NEXT_OFF , .name_len = SMB2_WSL_XATTR_NAME_LEN , .name = SMB2_WSL_XATTR_UID , },
98+ { .next = NEXT_OFF , .name_len = SMB2_WSL_XATTR_NAME_LEN , .name = SMB2_WSL_XATTR_GID , },
99+ { .next = NEXT_OFF , .name_len = SMB2_WSL_XATTR_NAME_LEN , .name = SMB2_WSL_XATTR_MODE , },
100+ { .next = 0 , .name_len = SMB2_WSL_XATTR_NAME_LEN , .name = SMB2_WSL_XATTR_DEV , },
101+ };
102+
103+ static int check_wsl_eas (struct kvec * rsp_iov )
104+ {
105+ struct smb2_file_full_ea_info * ea ;
106+ struct smb2_query_info_rsp * rsp = rsp_iov -> iov_base ;
107+ unsigned long addr ;
108+ u32 outlen , next ;
109+ u16 vlen ;
110+ u8 nlen ;
111+ u8 * end ;
112+
113+ outlen = le32_to_cpu (rsp -> OutputBufferLength );
114+ if (outlen < SMB2_WSL_MIN_QUERY_EA_RESP_SIZE ||
115+ outlen > SMB2_WSL_MAX_QUERY_EA_RESP_SIZE )
116+ return - EINVAL ;
117+
118+ ea = (void * )((u8 * )rsp_iov -> iov_base +
119+ le16_to_cpu (rsp -> OutputBufferOffset ));
120+ end = (u8 * )rsp_iov -> iov_base + rsp_iov -> iov_len ;
121+ for (;;) {
122+ if ((u8 * )ea > end - sizeof (* ea ))
123+ return - EINVAL ;
124+
125+ nlen = ea -> ea_name_length ;
126+ vlen = le16_to_cpu (ea -> ea_value_length );
127+ if (nlen != SMB2_WSL_XATTR_NAME_LEN ||
128+ (u8 * )ea + nlen + 1 + vlen > end )
129+ return - EINVAL ;
130+
131+ switch (vlen ) {
132+ case 4 :
133+ if (strncmp (ea -> ea_data , SMB2_WSL_XATTR_UID , nlen ) &&
134+ strncmp (ea -> ea_data , SMB2_WSL_XATTR_GID , nlen ) &&
135+ strncmp (ea -> ea_data , SMB2_WSL_XATTR_MODE , nlen ))
136+ return - EINVAL ;
137+ break ;
138+ case 8 :
139+ if (strncmp (ea -> ea_data , SMB2_WSL_XATTR_DEV , nlen ))
140+ return - EINVAL ;
141+ break ;
142+ case 0 :
143+ if (!strncmp (ea -> ea_data , SMB2_WSL_XATTR_UID , nlen ) ||
144+ !strncmp (ea -> ea_data , SMB2_WSL_XATTR_GID , nlen ) ||
145+ !strncmp (ea -> ea_data , SMB2_WSL_XATTR_MODE , nlen ) ||
146+ !strncmp (ea -> ea_data , SMB2_WSL_XATTR_DEV , nlen ))
147+ break ;
148+ fallthrough ;
149+ default :
150+ return - EINVAL ;
151+ }
152+
153+ next = le32_to_cpu (ea -> next_entry_offset );
154+ if (!next )
155+ break ;
156+ if (!IS_ALIGNED (next , 4 ) ||
157+ check_add_overflow ((unsigned long )ea , next , & addr ))
158+ return - EINVAL ;
159+ ea = (void * )addr ;
160+ }
161+ return 0 ;
162+ }
163+
88164/*
89165 * note: If cfile is passed, the reference to it is dropped here.
90166 * So make sure that you do not reuse cfile after return from this func.
@@ -119,7 +195,7 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
119195 __u8 delete_pending [8 ] = {1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 };
120196 unsigned int size [2 ];
121197 void * data [2 ];
122- int len ;
198+ unsigned int len ;
123199 int retries = 0 , cur_sleep = 1 ;
124200
125201replay_again :
@@ -476,6 +552,39 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
476552 trace_smb3_get_reparse_compound_enter (xid , ses -> Suid ,
477553 tcon -> tid , full_path );
478554 break ;
555+ case SMB2_OP_QUERY_WSL_EA :
556+ rqst [num_rqst ].rq_iov = & vars -> ea_iov ;
557+ rqst [num_rqst ].rq_nvec = 1 ;
558+
559+ if (cfile ) {
560+ rc = SMB2_query_info_init (tcon , server ,
561+ & rqst [num_rqst ],
562+ cfile -> fid .persistent_fid ,
563+ cfile -> fid .volatile_fid ,
564+ FILE_FULL_EA_INFORMATION ,
565+ SMB2_O_INFO_FILE , 0 ,
566+ SMB2_WSL_MAX_QUERY_EA_RESP_SIZE ,
567+ sizeof (wsl_query_eas ),
568+ (void * )wsl_query_eas );
569+ } else {
570+ rc = SMB2_query_info_init (tcon , server ,
571+ & rqst [num_rqst ],
572+ COMPOUND_FID ,
573+ COMPOUND_FID ,
574+ FILE_FULL_EA_INFORMATION ,
575+ SMB2_O_INFO_FILE , 0 ,
576+ SMB2_WSL_MAX_QUERY_EA_RESP_SIZE ,
577+ sizeof (wsl_query_eas ),
578+ (void * )wsl_query_eas );
579+ }
580+ if (!rc && (!cfile || num_rqst > 1 )) {
581+ smb2_set_next_command (tcon , & rqst [num_rqst ]);
582+ smb2_set_related (& rqst [num_rqst ]);
583+ } else if (rc ) {
584+ goto finished ;
585+ }
586+ num_rqst ++ ;
587+ break ;
479588 default :
480589 cifs_dbg (VFS , "Invalid command\n" );
481590 rc = - EINVAL ;
@@ -665,11 +774,32 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
665774 memset (iov , 0 , sizeof (* iov ));
666775 resp_buftype [i + 1 ] = CIFS_NO_BUFFER ;
667776 } else {
668- trace_smb3_set_reparse_compound_err (xid , ses -> Suid ,
777+ trace_smb3_set_reparse_compound_err (xid , ses -> Suid ,
669778 tcon -> tid , rc );
670779 }
671780 SMB2_ioctl_free (& rqst [num_rqst ++ ]);
672781 break ;
782+ case SMB2_OP_QUERY_WSL_EA :
783+ if (!rc ) {
784+ idata = in_iov [i ].iov_base ;
785+ qi_rsp = rsp_iov [i + 1 ].iov_base ;
786+ data [0 ] = (u8 * )qi_rsp + le16_to_cpu (qi_rsp -> OutputBufferOffset );
787+ size [0 ] = le32_to_cpu (qi_rsp -> OutputBufferLength );
788+ rc = check_wsl_eas (& rsp_iov [i + 1 ]);
789+ if (!rc ) {
790+ memcpy (idata -> wsl .eas , data [0 ], size [0 ]);
791+ idata -> wsl .eas_len = size [0 ];
792+ }
793+ }
794+ if (!rc ) {
795+ trace_smb3_query_wsl_ea_compound_done (xid , ses -> Suid ,
796+ tcon -> tid );
797+ } else {
798+ trace_smb3_query_wsl_ea_compound_err (xid , ses -> Suid ,
799+ tcon -> tid , rc );
800+ }
801+ SMB2_query_info_free (& rqst [num_rqst ++ ]);
802+ break ;
673803 }
674804 }
675805 SMB2_close_free (& rqst [num_rqst ]);
@@ -737,11 +867,11 @@ int smb2_query_path_info(const unsigned int xid,
737867 struct cifsFileInfo * cfile ;
738868 struct cached_fid * cfid = NULL ;
739869 struct smb2_hdr * hdr ;
740- struct kvec in_iov [2 ], out_iov [3 ] = {};
870+ struct kvec in_iov [3 ], out_iov [3 ] = {};
741871 int out_buftype [3 ] = {};
742- int cmds [2 ];
872+ int cmds [3 ];
743873 bool islink ;
744- int i , num_cmds ;
874+ int i , num_cmds = 0 ;
745875 int rc , rc2 ;
746876
747877 data -> adjust_tz = false;
@@ -774,21 +904,22 @@ int smb2_query_path_info(const unsigned int xid,
774904 close_cached_dir (cfid );
775905 return rc ;
776906 }
777- cmds [0 ] = SMB2_OP_QUERY_INFO ;
907+ cmds [num_cmds ++ ] = SMB2_OP_QUERY_INFO ;
778908 } else {
779- cmds [0 ] = SMB2_OP_POSIX_QUERY_INFO ;
909+ cmds [num_cmds ++ ] = SMB2_OP_POSIX_QUERY_INFO ;
780910 }
781911
782912 in_iov [0 ].iov_base = data ;
783913 in_iov [0 ].iov_len = sizeof (* data );
784914 in_iov [1 ] = in_iov [0 ];
915+ in_iov [2 ] = in_iov [0 ];
785916
786917 cifs_get_readable_path (tcon , full_path , & cfile );
787918 oparms = CIFS_OPARMS (cifs_sb , tcon , full_path , FILE_READ_ATTRIBUTES ,
788919 FILE_OPEN , create_options , ACL_NO_MODE );
789920 rc = smb2_compound_op (xid , tcon , cifs_sb , full_path ,
790- & oparms , in_iov , cmds , 1 , cfile ,
791- out_iov , out_buftype , NULL );
921+ & oparms , in_iov , cmds , num_cmds ,
922+ cfile , out_iov , out_buftype , NULL );
792923 hdr = out_iov [0 ].iov_base ;
793924 /*
794925 * If first iov is unset, then SMB session was dropped or we've got a
@@ -808,17 +939,18 @@ int smb2_query_path_info(const unsigned int xid,
808939 if (rc || !data -> reparse_point )
809940 goto out ;
810941
811- if (data -> reparse .tag == IO_REPARSE_TAG_SYMLINK ) {
812- /* symlink already parsed in create response */
813- num_cmds = 1 ;
814- } else {
815- cmds [1 ] = SMB2_OP_GET_REPARSE ;
816- num_cmds = 2 ;
817- }
942+ cmds [num_cmds ++ ] = SMB2_OP_QUERY_WSL_EA ;
943+ /*
944+ * Skip SMB2_OP_GET_REPARSE if symlink already parsed in create
945+ * response.
946+ */
947+ if (data -> reparse .tag != IO_REPARSE_TAG_SYMLINK )
948+ cmds [num_cmds ++ ] = SMB2_OP_GET_REPARSE ;
949+
818950 oparms = CIFS_OPARMS (cifs_sb , tcon , full_path ,
819- FILE_READ_ATTRIBUTES , FILE_OPEN ,
820- create_options | OPEN_REPARSE_POINT ,
821- ACL_NO_MODE );
951+ FILE_READ_ATTRIBUTES | FILE_READ_EA ,
952+ FILE_OPEN , create_options |
953+ OPEN_REPARSE_POINT , ACL_NO_MODE );
822954 cifs_get_readable_path (tcon , full_path , & cfile );
823955 rc = smb2_compound_op (xid , tcon , cifs_sb , full_path ,
824956 & oparms , in_iov , cmds , num_cmds ,
0 commit comments