Skip to content

Commit f5b05d6

Browse files
Ronnie SahlbergSteve French
Ronnie Sahlberg
authored and
Steve French
committed
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 <[email protected]> Signed-off-by: Steve French <[email protected]>
1 parent 8c1beb9 commit f5b05d6

File tree

7 files changed

+134
-11
lines changed

7 files changed

+134
-11
lines changed

fs/cifs/cifs_ioctl.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,19 @@ struct smb_snapshot_array {
4343
/* snapshots[]; */
4444
} __packed;
4545

46+
struct smb_query_info {
47+
__u32 info_type;
48+
__u32 file_info_class;
49+
__u32 additional_information;
50+
__u32 flags;
51+
__u32 input_buffer_length;
52+
__u32 output_buffer_length;
53+
/* char buffer[]; */
54+
} __packed;
55+
4656
#define CIFS_IOCTL_MAGIC 0xCF
4757
#define CIFS_IOC_COPYCHUNK_FILE _IOW(CIFS_IOCTL_MAGIC, 3, int)
4858
#define CIFS_IOC_SET_INTEGRITY _IO(CIFS_IOCTL_MAGIC, 4)
4959
#define CIFS_IOC_GET_MNT_INFO _IOR(CIFS_IOCTL_MAGIC, 5, struct smb_mnt_fs_info)
5060
#define CIFS_ENUMERATE_SNAPSHOTS _IOR(CIFS_IOCTL_MAGIC, 6, struct smb_snapshot_array)
61+
#define CIFS_QUERY_INFO _IOWR(CIFS_IOCTL_MAGIC, 7, struct smb_query_info)

fs/cifs/cifsglob.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -465,6 +465,10 @@ struct smb_version_operations {
465465
enum securityEnum (*select_sectype)(struct TCP_Server_Info *,
466466
enum securityEnum);
467467
int (*next_header)(char *);
468+
/* ioctl passthrough for query_info */
469+
int (*ioctl_query_info)(const unsigned int xid,
470+
struct cifsFileInfo *file,
471+
unsigned long p);
468472
};
469473

470474
struct smb_version_values {

fs/cifs/ioctl.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,24 @@
3434
#include "cifs_ioctl.h"
3535
#include <linux/btrfs.h>
3636

37+
static long cifs_ioctl_query_info(unsigned int xid, struct file *filep,
38+
unsigned long p)
39+
{
40+
struct cifsFileInfo *pSMBFile = filep->private_data;
41+
struct cifs_tcon *tcon;
42+
43+
cifs_dbg(FYI, "%s %p\n", __func__, pSMBFile);
44+
if (pSMBFile == NULL)
45+
return -EISDIR;
46+
tcon = tlink_tcon(pSMBFile->tlink);
47+
48+
if (tcon->ses->server->ops->ioctl_query_info)
49+
return tcon->ses->server->ops->ioctl_query_info(
50+
xid, pSMBFile, p);
51+
else
52+
return -EOPNOTSUPP;
53+
}
54+
3755
static long cifs_ioctl_copychunk(unsigned int xid, struct file *dst_file,
3856
unsigned long srcfd)
3957
{
@@ -194,6 +212,9 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
194212
case CIFS_IOC_COPYCHUNK_FILE:
195213
rc = cifs_ioctl_copychunk(xid, filep, arg);
196214
break;
215+
case CIFS_QUERY_INFO:
216+
rc = cifs_ioctl_query_info(xid, filep, arg);
217+
break;
197218
case CIFS_IOC_SET_INTEGRITY:
198219
if (pSMBFile == NULL)
199220
break;

fs/cifs/smb2inode.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
110110
COMPOUND_FID, FILE_ALL_INFORMATION,
111111
SMB2_O_INFO_FILE, 0,
112112
sizeof(struct smb2_file_all_info) +
113-
PATH_MAX * 2);
113+
PATH_MAX * 2, 0, NULL);
114114
smb2_set_next_command(server, &rqst[num_rqst]);
115115
smb2_set_related(&rqst[num_rqst++]);
116116
break;

fs/cifs/smb2ops.c

Lines changed: 86 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1118,6 +1118,86 @@ SMB2_request_res_key(const unsigned int xid, struct cifs_tcon *tcon,
11181118
return rc;
11191119
}
11201120

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+
11211201
static ssize_t
11221202
smb2_copychunk_range(const unsigned int xid,
11231203
struct cifsFileInfo *srcfile,
@@ -1697,7 +1777,8 @@ smb2_queryfs(const unsigned int xid, struct cifs_tcon *tcon,
16971777
rc = SMB2_query_info_init(tcon, &rqst[1], COMPOUND_FID, COMPOUND_FID,
16981778
FS_FULL_SIZE_INFORMATION,
16991779
SMB2_O_INFO_FILESYSTEM, 0,
1700-
sizeof(struct smb2_fs_full_size_info));
1780+
sizeof(struct smb2_fs_full_size_info), 0,
1781+
NULL);
17011782
if (rc)
17021783
goto qfs_exit;
17031784
smb2_set_next_command(server, &rqst[1]);
@@ -3364,6 +3445,7 @@ struct smb_version_operations smb20_operations = {
33643445
.set_acl = set_smb2_acl,
33653446
#endif /* CIFS_ACL */
33663447
.next_header = smb2_next_header,
3448+
.ioctl_query_info = smb2_ioctl_query_info,
33673449
};
33683450

33693451
struct smb_version_operations smb21_operations = {
@@ -3459,6 +3541,7 @@ struct smb_version_operations smb21_operations = {
34593541
.set_acl = set_smb2_acl,
34603542
#endif /* CIFS_ACL */
34613543
.next_header = smb2_next_header,
3544+
.ioctl_query_info = smb2_ioctl_query_info,
34623545
};
34633546

34643547
struct smb_version_operations smb30_operations = {
@@ -3563,6 +3646,7 @@ struct smb_version_operations smb30_operations = {
35633646
.set_acl = set_smb2_acl,
35643647
#endif /* CIFS_ACL */
35653648
.next_header = smb2_next_header,
3649+
.ioctl_query_info = smb2_ioctl_query_info,
35663650
};
35673651

35683652
struct smb_version_operations smb311_operations = {
@@ -3668,6 +3752,7 @@ struct smb_version_operations smb311_operations = {
36683752
.set_acl = set_smb2_acl,
36693753
#endif /* CIFS_ACL */
36703754
.next_header = smb2_next_header,
3755+
.ioctl_query_info = smb2_ioctl_query_info,
36713756
};
36723757

36733758
struct smb_version_values smb20_values = {

fs/cifs/smb2pdu.c

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2651,7 +2651,7 @@ int
26512651
SMB2_query_info_init(struct cifs_tcon *tcon, struct smb_rqst *rqst,
26522652
u64 persistent_fid, u64 volatile_fid,
26532653
u8 info_class, u8 info_type, u32 additional_info,
2654-
size_t output_len)
2654+
size_t output_len, size_t input_len, void *input)
26552655
{
26562656
struct smb2_query_info_req *req;
26572657
struct kvec *iov = rqst->rq_iov;
@@ -2669,16 +2669,17 @@ SMB2_query_info_init(struct cifs_tcon *tcon, struct smb_rqst *rqst,
26692669
req->VolatileFileId = volatile_fid;
26702670
req->AdditionalInformation = cpu_to_le32(additional_info);
26712671

2672-
/*
2673-
* We do not use the input buffer (do not send extra byte)
2674-
*/
2675-
req->InputBufferOffset = 0;
2676-
26772672
req->OutputBufferLength = cpu_to_le32(output_len);
2673+
if (input_len) {
2674+
req->InputBufferLength = cpu_to_le32(input_len);
2675+
/* total_len for smb query request never close to le16 max */
2676+
req->InputBufferOffset = cpu_to_le16(total_len - 1);
2677+
memcpy(req->Buffer, input, input_len);
2678+
}
26782679

26792680
iov[0].iov_base = (char *)req;
26802681
/* 1 for Buffer */
2681-
iov[0].iov_len = total_len - 1;
2682+
iov[0].iov_len = total_len - 1 + input_len;
26822683
return 0;
26832684
}
26842685

@@ -2718,7 +2719,7 @@ query_info(const unsigned int xid, struct cifs_tcon *tcon,
27182719

27192720
rc = SMB2_query_info_init(tcon, &rqst, persistent_fid, volatile_fid,
27202721
info_class, info_type, additional_info,
2721-
output_len);
2722+
output_len, 0, NULL);
27222723
if (rc)
27232724
goto qinf_exit;
27242725

fs/cifs/smb2proto.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,8 @@ extern int SMB2_query_info(const unsigned int xid, struct cifs_tcon *tcon,
163163
extern int SMB2_query_info_init(struct cifs_tcon *tcon, struct smb_rqst *rqst,
164164
u64 persistent_fid, u64 volatile_fid,
165165
u8 info_class, u8 info_type,
166-
u32 additional_info, size_t output_len);
166+
u32 additional_info, size_t output_len,
167+
size_t input_len, void *input);
167168
extern void SMB2_query_info_free(struct smb_rqst *rqst);
168169
extern int SMB2_query_acl(const unsigned int xid, struct cifs_tcon *tcon,
169170
u64 persistent_file_id, u64 volatile_file_id,

0 commit comments

Comments
 (0)