aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs/smb2ops.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/cifs/smb2ops.c')
-rw-r--r--fs/cifs/smb2ops.c87
1 files changed, 86 insertions, 1 deletions
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index b744221f685d..c6c6450d0f38 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -1118,6 +1118,86 @@ req_res_key_exit:
1118 return rc; 1118 return rc;
1119} 1119}
1120 1120
1121static int
1122smb2_ioctl_query_info(const unsigned int xid,
1123 struct cifsFileInfo *file,
1124 unsigned long p)
1125{
1126 struct cifs_tcon *tcon = tlink_tcon(file->tlink);
1127 struct cifs_ses *ses = tcon->ses;
1128 char __user *arg = (char __user *)p;
1129 struct smb_query_info qi;
1130 struct smb_query_info __user *pqi;
1131 int rc = 0;
1132 int flags = 0;
1133 struct smb_rqst rqst;
1134 struct kvec iov[1];
1135 struct kvec rsp_iov;
1136 int resp_buftype;
1137 struct smb2_query_info_rsp *rsp = NULL;
1138 void *buffer;
1139
1140 if (copy_from_user(&qi, arg, sizeof(struct smb_query_info)))
1141 return -EFAULT;
1142
1143 if (qi.output_buffer_length > 1024)
1144 return -EINVAL;
1145
1146 if (!ses || !(ses->server))
1147 return -EIO;
1148
1149 if (smb3_encryption_required(tcon))
1150 flags |= CIFS_TRANSFORM_REQ;
1151
1152 buffer = kmalloc(qi.output_buffer_length, GFP_KERNEL);
1153 if (buffer == NULL)
1154 return -ENOMEM;
1155
1156 if (copy_from_user(buffer, arg + sizeof(struct smb_query_info),
1157 qi.output_buffer_length)) {
1158 kfree(buffer);
1159 return -EFAULT;
1160 }
1161
1162 memset(&rqst, 0, sizeof(struct smb_rqst));
1163 memset(&iov, 0, sizeof(iov));
1164 rqst.rq_iov = iov;
1165 rqst.rq_nvec = 1;
1166
1167 rc = SMB2_query_info_init(tcon, &rqst, file->fid.persistent_fid,
1168 file->fid.volatile_fid,
1169 qi.file_info_class, qi.info_type,
1170 qi.additional_information,
1171 qi.input_buffer_length,
1172 qi.output_buffer_length, buffer);
1173 kfree(buffer);
1174 if (rc)
1175 goto iqinf_exit;
1176
1177 rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov);
1178 rsp = (struct smb2_query_info_rsp *)rsp_iov.iov_base;
1179 if (rc)
1180 goto iqinf_exit;
1181
1182 pqi = (struct smb_query_info __user *)arg;
1183 if (le32_to_cpu(rsp->OutputBufferLength) < qi.input_buffer_length)
1184 qi.input_buffer_length = le32_to_cpu(rsp->OutputBufferLength);
1185 if (copy_to_user(&pqi->input_buffer_length, &qi.input_buffer_length,
1186 sizeof(qi.input_buffer_length))) {
1187 rc = -EFAULT;
1188 goto iqinf_exit;
1189 }
1190 if (copy_to_user(pqi + 1, rsp->Buffer, qi.input_buffer_length)) {
1191 rc = -EFAULT;
1192 goto iqinf_exit;
1193 }
1194
1195 iqinf_exit:
1196 SMB2_query_info_free(&rqst);
1197 free_rsp_buf(resp_buftype, rsp);
1198 return rc;
1199}
1200
1121static ssize_t 1201static ssize_t
1122smb2_copychunk_range(const unsigned int xid, 1202smb2_copychunk_range(const unsigned int xid,
1123 struct cifsFileInfo *srcfile, 1203 struct cifsFileInfo *srcfile,
@@ -1697,7 +1777,8 @@ smb2_queryfs(const unsigned int xid, struct cifs_tcon *tcon,
1697 rc = SMB2_query_info_init(tcon, &rqst[1], COMPOUND_FID, COMPOUND_FID, 1777 rc = SMB2_query_info_init(tcon, &rqst[1], COMPOUND_FID, COMPOUND_FID,
1698 FS_FULL_SIZE_INFORMATION, 1778 FS_FULL_SIZE_INFORMATION,
1699 SMB2_O_INFO_FILESYSTEM, 0, 1779 SMB2_O_INFO_FILESYSTEM, 0,
1700 sizeof(struct smb2_fs_full_size_info)); 1780 sizeof(struct smb2_fs_full_size_info), 0,
1781 NULL);
1701 if (rc) 1782 if (rc)
1702 goto qfs_exit; 1783 goto qfs_exit;
1703 smb2_set_next_command(server, &rqst[1]); 1784 smb2_set_next_command(server, &rqst[1]);
@@ -3364,6 +3445,7 @@ struct smb_version_operations smb20_operations = {
3364 .set_acl = set_smb2_acl, 3445 .set_acl = set_smb2_acl,
3365#endif /* CIFS_ACL */ 3446#endif /* CIFS_ACL */
3366 .next_header = smb2_next_header, 3447 .next_header = smb2_next_header,
3448 .ioctl_query_info = smb2_ioctl_query_info,
3367}; 3449};
3368 3450
3369struct smb_version_operations smb21_operations = { 3451struct smb_version_operations smb21_operations = {
@@ -3459,6 +3541,7 @@ struct smb_version_operations smb21_operations = {
3459 .set_acl = set_smb2_acl, 3541 .set_acl = set_smb2_acl,
3460#endif /* CIFS_ACL */ 3542#endif /* CIFS_ACL */
3461 .next_header = smb2_next_header, 3543 .next_header = smb2_next_header,
3544 .ioctl_query_info = smb2_ioctl_query_info,
3462}; 3545};
3463 3546
3464struct smb_version_operations smb30_operations = { 3547struct smb_version_operations smb30_operations = {
@@ -3563,6 +3646,7 @@ struct smb_version_operations smb30_operations = {
3563 .set_acl = set_smb2_acl, 3646 .set_acl = set_smb2_acl,
3564#endif /* CIFS_ACL */ 3647#endif /* CIFS_ACL */
3565 .next_header = smb2_next_header, 3648 .next_header = smb2_next_header,
3649 .ioctl_query_info = smb2_ioctl_query_info,
3566}; 3650};
3567 3651
3568struct smb_version_operations smb311_operations = { 3652struct smb_version_operations smb311_operations = {
@@ -3668,6 +3752,7 @@ struct smb_version_operations smb311_operations = {
3668 .set_acl = set_smb2_acl, 3752 .set_acl = set_smb2_acl,
3669#endif /* CIFS_ACL */ 3753#endif /* CIFS_ACL */
3670 .next_header = smb2_next_header, 3754 .next_header = smb2_next_header,
3755 .ioctl_query_info = smb2_ioctl_query_info,
3671}; 3756};
3672 3757
3673struct smb_version_values smb20_values = { 3758struct smb_version_values smb20_values = {