summaryrefslogtreecommitdiffstats
path: root/fs/cifs/smb2ops.c
diff options
context:
space:
mode:
authorRonnie Sahlberg <lsahlber@redhat.com>2018-10-07 20:19:58 -0400
committerSteve French <stfrench@microsoft.com>2018-10-23 22:16:05 -0400
commitf5b05d622a3e99e6a97a189fe500414be802a05c (patch)
tree173d227ce653e9a9ee4fbaffb4a7f4c7e2ea715e /fs/cifs/smb2ops.c
parent8c1beb9801293b175cfa0341e5df89581a87dc02 (diff)
cifs: add IOCTL for QUERY_INFO passthrough to userspace
This allows userspace tools to query the raw info levels for cifs files and process the response in userspace. In particular this is useful for many of those data where there is no corresponding native data structure in linux. For example querying the security descriptor for a file and extract the SIDs. 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.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 = {