summaryrefslogtreecommitdiffstats
path: root/fs/cifs/smb2ops.c
diff options
context:
space:
mode:
authorRonnie Sahlberg <lsahlber@redhat.com>2018-10-16 15:47:58 -0400
committerSteve French <stfrench@microsoft.com>2018-10-23 22:16:05 -0400
commit8d8b26e58432cb2840048b9f8aea286be6f75de5 (patch)
tree0434bc93a5769be50353d7407a68c9d85dff0588 /fs/cifs/smb2ops.c
parent3b7960caceafdfc2cdfe2850487f8d091eb41144 (diff)
cifs: add support for ioctl on directories
We do not call cifs_open_file() for directories and thus we do not have a pSMBFile we can extract the FIDs from. Solve this by instead always using a compounded open/query/close for the passthrough ioctl. Signed-off-by: Ronnie Sahlberg <lsahlber@redhat.com> Signed-off-by: Steve French <stfrench@microsoft.com>
Diffstat (limited to 'fs/cifs/smb2ops.c')
-rw-r--r--fs/cifs/smb2ops.c85
1 files changed, 65 insertions, 20 deletions
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index 8472cb0ae06c..e35a753eca20 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -1120,22 +1120,31 @@ req_res_key_exit:
1120 1120
1121static int 1121static int
1122smb2_ioctl_query_info(const unsigned int xid, 1122smb2_ioctl_query_info(const unsigned int xid,
1123 struct cifsFileInfo *file, 1123 struct cifs_tcon *tcon,
1124 __le16 *path, int is_dir,
1124 unsigned long p) 1125 unsigned long p)
1125{ 1126{
1126 struct cifs_tcon *tcon = tlink_tcon(file->tlink);
1127 struct cifs_ses *ses = tcon->ses; 1127 struct cifs_ses *ses = tcon->ses;
1128 char __user *arg = (char __user *)p; 1128 char __user *arg = (char __user *)p;
1129 struct smb_query_info qi; 1129 struct smb_query_info qi;
1130 struct smb_query_info __user *pqi; 1130 struct smb_query_info __user *pqi;
1131 int rc = 0; 1131 int rc = 0;
1132 int flags = 0; 1132 int flags = 0;
1133 struct smb_rqst rqst;
1134 struct kvec iov[1];
1135 struct kvec rsp_iov;
1136 int resp_buftype = CIFS_NO_BUFFER;
1137 struct smb2_query_info_rsp *rsp = NULL; 1133 struct smb2_query_info_rsp *rsp = NULL;
1138 void *buffer; 1134 void *buffer = NULL;
1135 struct smb_rqst rqst[3];
1136 int resp_buftype[3];
1137 struct kvec rsp_iov[3];
1138 struct kvec open_iov[SMB2_CREATE_IOV_SIZE];
1139 struct cifs_open_parms oparms;
1140 u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
1141 struct cifs_fid fid;
1142 struct kvec qi_iov[1];
1143 struct kvec close_iov[1];
1144
1145 memset(rqst, 0, sizeof(rqst));
1146 resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER;
1147 memset(rsp_iov, 0, sizeof(rsp_iov));
1139 1148
1140 if (copy_from_user(&qi, arg, sizeof(struct smb_query_info))) 1149 if (copy_from_user(&qi, arg, sizeof(struct smb_query_info)))
1141 return -EFAULT; 1150 return -EFAULT;
@@ -1155,31 +1164,62 @@ smb2_ioctl_query_info(const unsigned int xid,
1155 1164
1156 if (copy_from_user(buffer, arg + sizeof(struct smb_query_info), 1165 if (copy_from_user(buffer, arg + sizeof(struct smb_query_info),
1157 qi.output_buffer_length)) { 1166 qi.output_buffer_length)) {
1158 kfree(buffer); 1167 rc = -EFAULT;
1159 return -EFAULT; 1168 goto iqinf_exit;
1160 } 1169 }
1161 1170
1162 memset(&rqst, 0, sizeof(struct smb_rqst)); 1171 /* Open */
1163 memset(&iov, 0, sizeof(iov)); 1172 memset(&open_iov, 0, sizeof(open_iov));
1164 rqst.rq_iov = iov; 1173 rqst[0].rq_iov = open_iov;
1165 rqst.rq_nvec = 1; 1174 rqst[0].rq_nvec = SMB2_CREATE_IOV_SIZE;
1175
1176 memset(&oparms, 0, sizeof(oparms));
1177 oparms.tcon = tcon;
1178 oparms.desired_access = FILE_READ_ATTRIBUTES | READ_CONTROL;
1179 oparms.disposition = FILE_OPEN;
1180 if (is_dir)
1181 oparms.create_options = CREATE_NOT_FILE;
1182 else
1183 oparms.create_options = CREATE_NOT_DIR;
1184 oparms.fid = &fid;
1185 oparms.reconnect = false;
1186
1187 rc = SMB2_open_init(tcon, &rqst[0], &oplock, &oparms, path);
1188 if (rc)
1189 goto iqinf_exit;
1190 smb2_set_next_command(ses->server, &rqst[0]);
1166 1191
1167 rc = SMB2_query_info_init(tcon, &rqst, file->fid.persistent_fid, 1192 /* Query */
1168 file->fid.volatile_fid, 1193 memset(&qi_iov, 0, sizeof(qi_iov));
1194 rqst[1].rq_iov = qi_iov;
1195 rqst[1].rq_nvec = 1;
1196
1197 rc = SMB2_query_info_init(tcon, &rqst[1], COMPOUND_FID, COMPOUND_FID,
1169 qi.file_info_class, qi.info_type, 1198 qi.file_info_class, qi.info_type,
1170 qi.additional_information, 1199 qi.additional_information,
1171 qi.input_buffer_length, 1200 qi.input_buffer_length,
1172 qi.output_buffer_length, buffer); 1201 qi.output_buffer_length, buffer);
1173 kfree(buffer);
1174 if (rc) 1202 if (rc)
1175 goto iqinf_exit; 1203 goto iqinf_exit;
1204 smb2_set_next_command(ses->server, &rqst[1]);
1205 smb2_set_related(&rqst[1]);
1176 1206
1177 rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov); 1207 /* Close */
1178 rsp = (struct smb2_query_info_rsp *)rsp_iov.iov_base; 1208 memset(&close_iov, 0, sizeof(close_iov));
1209 rqst[2].rq_iov = close_iov;
1210 rqst[2].rq_nvec = 1;
1211
1212 rc = SMB2_close_init(tcon, &rqst[2], COMPOUND_FID, COMPOUND_FID);
1179 if (rc) 1213 if (rc)
1180 goto iqinf_exit; 1214 goto iqinf_exit;
1215 smb2_set_related(&rqst[2]);
1181 1216
1217 rc = compound_send_recv(xid, ses, flags, 3, rqst,
1218 resp_buftype, rsp_iov);
1219 if (rc)
1220 goto iqinf_exit;
1182 pqi = (struct smb_query_info __user *)arg; 1221 pqi = (struct smb_query_info __user *)arg;
1222 rsp = (struct smb2_query_info_rsp *)rsp_iov[1].iov_base;
1183 if (le32_to_cpu(rsp->OutputBufferLength) < qi.input_buffer_length) 1223 if (le32_to_cpu(rsp->OutputBufferLength) < qi.input_buffer_length)
1184 qi.input_buffer_length = le32_to_cpu(rsp->OutputBufferLength); 1224 qi.input_buffer_length = le32_to_cpu(rsp->OutputBufferLength);
1185 if (copy_to_user(&pqi->input_buffer_length, &qi.input_buffer_length, 1225 if (copy_to_user(&pqi->input_buffer_length, &qi.input_buffer_length,
@@ -1193,8 +1233,13 @@ smb2_ioctl_query_info(const unsigned int xid,
1193 } 1233 }
1194 1234
1195 iqinf_exit: 1235 iqinf_exit:
1196 SMB2_query_info_free(&rqst); 1236 kfree(buffer);
1197 free_rsp_buf(resp_buftype, rsp); 1237 SMB2_open_free(&rqst[0]);
1238 SMB2_query_info_free(&rqst[1]);
1239 SMB2_close_free(&rqst[2]);
1240 free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base);
1241 free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base);
1242 free_rsp_buf(resp_buftype[2], rsp_iov[2].iov_base);
1198 return rc; 1243 return rc;
1199} 1244}
1200 1245