diff options
Diffstat (limited to 'fs/cifs/smb2ops.c')
-rw-r--r-- | fs/cifs/smb2ops.c | 87 |
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 | ||
1121 | static int | ||
1122 | smb2_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 | |||
1121 | static ssize_t | 1201 | static ssize_t |
1122 | smb2_copychunk_range(const unsigned int xid, | 1202 | smb2_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 | ||
3369 | struct smb_version_operations smb21_operations = { | 3451 | struct 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 | ||
3464 | struct smb_version_operations smb30_operations = { | 3547 | struct 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 | ||
3568 | struct smb_version_operations smb311_operations = { | 3652 | struct 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 | ||
3673 | struct smb_version_values smb20_values = { | 3758 | struct smb_version_values smb20_values = { |