@@ -85,6 +85,82 @@ static int parse_posix_sids(struct cifs_open_info_data *data,
85
85
return 0 ;
86
86
}
87
87
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
+
88
164
/*
89
165
* note: If cfile is passed, the reference to it is dropped here.
90
166
* 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,
119
195
__u8 delete_pending [8 ] = {1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 };
120
196
unsigned int size [2 ];
121
197
void * data [2 ];
122
- int len ;
198
+ unsigned int len ;
123
199
int retries = 0 , cur_sleep = 1 ;
124
200
125
201
replay_again :
@@ -476,6 +552,39 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
476
552
trace_smb3_get_reparse_compound_enter (xid , ses -> Suid ,
477
553
tcon -> tid , full_path );
478
554
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 ;
479
588
default :
480
589
cifs_dbg (VFS , "Invalid command\n" );
481
590
rc = - EINVAL ;
@@ -665,11 +774,32 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
665
774
memset (iov , 0 , sizeof (* iov ));
666
775
resp_buftype [i + 1 ] = CIFS_NO_BUFFER ;
667
776
} else {
668
- trace_smb3_set_reparse_compound_err (xid , ses -> Suid ,
777
+ trace_smb3_set_reparse_compound_err (xid , ses -> Suid ,
669
778
tcon -> tid , rc );
670
779
}
671
780
SMB2_ioctl_free (& rqst [num_rqst ++ ]);
672
781
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 ;
673
803
}
674
804
}
675
805
SMB2_close_free (& rqst [num_rqst ]);
@@ -737,11 +867,11 @@ int smb2_query_path_info(const unsigned int xid,
737
867
struct cifsFileInfo * cfile ;
738
868
struct cached_fid * cfid = NULL ;
739
869
struct smb2_hdr * hdr ;
740
- struct kvec in_iov [2 ], out_iov [3 ] = {};
870
+ struct kvec in_iov [3 ], out_iov [3 ] = {};
741
871
int out_buftype [3 ] = {};
742
- int cmds [2 ];
872
+ int cmds [3 ];
743
873
bool islink ;
744
- int i , num_cmds ;
874
+ int i , num_cmds = 0 ;
745
875
int rc , rc2 ;
746
876
747
877
data -> adjust_tz = false;
@@ -774,21 +904,22 @@ int smb2_query_path_info(const unsigned int xid,
774
904
close_cached_dir (cfid );
775
905
return rc ;
776
906
}
777
- cmds [0 ] = SMB2_OP_QUERY_INFO ;
907
+ cmds [num_cmds ++ ] = SMB2_OP_QUERY_INFO ;
778
908
} else {
779
- cmds [0 ] = SMB2_OP_POSIX_QUERY_INFO ;
909
+ cmds [num_cmds ++ ] = SMB2_OP_POSIX_QUERY_INFO ;
780
910
}
781
911
782
912
in_iov [0 ].iov_base = data ;
783
913
in_iov [0 ].iov_len = sizeof (* data );
784
914
in_iov [1 ] = in_iov [0 ];
915
+ in_iov [2 ] = in_iov [0 ];
785
916
786
917
cifs_get_readable_path (tcon , full_path , & cfile );
787
918
oparms = CIFS_OPARMS (cifs_sb , tcon , full_path , FILE_READ_ATTRIBUTES ,
788
919
FILE_OPEN , create_options , ACL_NO_MODE );
789
920
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 );
792
923
hdr = out_iov [0 ].iov_base ;
793
924
/*
794
925
* 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,
808
939
if (rc || !data -> reparse_point )
809
940
goto out ;
810
941
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
+
818
950
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 );
822
954
cifs_get_readable_path (tcon , full_path , & cfile );
823
955
rc = smb2_compound_op (xid , tcon , cifs_sb , full_path ,
824
956
& oparms , in_iov , cmds , num_cmds ,
0 commit comments