aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRonnie Sahlberg <lsahlber@redhat.com>2019-03-14 19:07:22 -0400
committerSteve French <stfrench@microsoft.com>2019-03-14 20:32:36 -0400
commitf5778c398713692a16150ae96e5c8270bab8399f (patch)
tree76715ad8a0cb3e63cdbfde81c12ef379ee654f3c
parentf16994797ea89e572b27f41c554aeac6b1c16048 (diff)
SMB3: Allow SMB3 FSCTL queries to be sent to server from tools
For debugging purposes we often have to be able to query additional information only available via SMB3 FSCTL from the server from user space tools (e.g. like cifs-utils's smbinfo). See MS-FSCC and MS-SMB2 protocol specifications for more details. Signed-off-by: Ronnie Sahlberg <lsahlber@redhat.com> Signed-off-by: Steve French <stfrench@microsoft.com>
-rw-r--r--fs/cifs/smb2ops.c62
1 files changed, 46 insertions, 16 deletions
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index 1c8d3684bb8b..1022a3771e14 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -1330,7 +1330,8 @@ smb2_ioctl_query_info(const unsigned int xid,
1330 struct smb_query_info __user *pqi; 1330 struct smb_query_info __user *pqi;
1331 int rc = 0; 1331 int rc = 0;
1332 int flags = 0; 1332 int flags = 0;
1333 struct smb2_query_info_rsp *rsp = NULL; 1333 struct smb2_query_info_rsp *qi_rsp = NULL;
1334 struct smb2_ioctl_rsp *io_rsp = NULL;
1334 void *buffer = NULL; 1335 void *buffer = NULL;
1335 struct smb_rqst rqst[3]; 1336 struct smb_rqst rqst[3];
1336 int resp_buftype[3]; 1337 int resp_buftype[3];
@@ -1340,6 +1341,7 @@ smb2_ioctl_query_info(const unsigned int xid,
1340 u8 oplock = SMB2_OPLOCK_LEVEL_NONE; 1341 u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
1341 struct cifs_fid fid; 1342 struct cifs_fid fid;
1342 struct kvec qi_iov[1]; 1343 struct kvec qi_iov[1];
1344 struct kvec io_iov[SMB2_IOCTL_IOV_SIZE];
1343 struct kvec close_iov[1]; 1345 struct kvec close_iov[1];
1344 1346
1345 memset(rqst, 0, sizeof(rqst)); 1347 memset(rqst, 0, sizeof(rqst));
@@ -1394,8 +1396,16 @@ smb2_ioctl_query_info(const unsigned int xid,
1394 /* Can eventually relax perm check since server enforces too */ 1396 /* Can eventually relax perm check since server enforces too */
1395 if (!capable(CAP_SYS_ADMIN)) 1397 if (!capable(CAP_SYS_ADMIN))
1396 rc = -EPERM; 1398 rc = -EPERM;
1397 else /* TBD: Add code to compound FSCTL */ 1399 else {
1398 rc = -EOPNOTSUPP; 1400 memset(&io_iov, 0, sizeof(io_iov));
1401 rqst[1].rq_iov = io_iov;
1402 rqst[1].rq_nvec = SMB2_IOCTL_IOV_SIZE;
1403
1404 rc = SMB2_ioctl_init(tcon, &rqst[1],
1405 COMPOUND_FID, COMPOUND_FID,
1406 qi.info_type, true, NULL,
1407 0);
1408 }
1399 } else if (qi.flags == PASSTHRU_QUERY_INFO) { 1409 } else if (qi.flags == PASSTHRU_QUERY_INFO) {
1400 memset(&qi_iov, 0, sizeof(qi_iov)); 1410 memset(&qi_iov, 0, sizeof(qi_iov));
1401 rqst[1].rq_iov = qi_iov; 1411 rqst[1].rq_iov = qi_iov;
@@ -1430,24 +1440,44 @@ smb2_ioctl_query_info(const unsigned int xid,
1430 resp_buftype, rsp_iov); 1440 resp_buftype, rsp_iov);
1431 if (rc) 1441 if (rc)
1432 goto iqinf_exit; 1442 goto iqinf_exit;
1433 pqi = (struct smb_query_info __user *)arg; 1443 if (qi.flags & PASSTHRU_FSCTL) {
1434 rsp = (struct smb2_query_info_rsp *)rsp_iov[1].iov_base; 1444 pqi = (struct smb_query_info __user *)arg;
1435 if (le32_to_cpu(rsp->OutputBufferLength) < qi.input_buffer_length) 1445 io_rsp = (struct smb2_ioctl_rsp *)rsp_iov[1].iov_base;
1436 qi.input_buffer_length = le32_to_cpu(rsp->OutputBufferLength); 1446 if (le32_to_cpu(io_rsp->OutputCount) < qi.input_buffer_length)
1437 if (copy_to_user(&pqi->input_buffer_length, &qi.input_buffer_length, 1447 qi.input_buffer_length = le32_to_cpu(io_rsp->OutputCount);
1438 sizeof(qi.input_buffer_length))) { 1448 if (copy_to_user(&pqi->input_buffer_length, &qi.input_buffer_length,
1439 rc = -EFAULT; 1449 sizeof(qi.input_buffer_length))) {
1440 goto iqinf_exit; 1450 rc = -EFAULT;
1441 } 1451 goto iqinf_exit;
1442 if (copy_to_user(pqi + 1, rsp->Buffer, qi.input_buffer_length)) { 1452 }
1443 rc = -EFAULT; 1453 if (copy_to_user(pqi + 1, &io_rsp[1], qi.input_buffer_length)) {
1444 goto iqinf_exit; 1454 rc = -EFAULT;
1455 goto iqinf_exit;
1456 }
1457 } else {
1458 pqi = (struct smb_query_info __user *)arg;
1459 qi_rsp = (struct smb2_query_info_rsp *)rsp_iov[1].iov_base;
1460 if (le32_to_cpu(qi_rsp->OutputBufferLength) < qi.input_buffer_length)
1461 qi.input_buffer_length = le32_to_cpu(qi_rsp->OutputBufferLength);
1462 if (copy_to_user(&pqi->input_buffer_length, &qi.input_buffer_length,
1463 sizeof(qi.input_buffer_length))) {
1464 rc = -EFAULT;
1465 goto iqinf_exit;
1466 }
1467 if (copy_to_user(pqi + 1, qi_rsp->Buffer, qi.input_buffer_length)) {
1468 rc = -EFAULT;
1469 goto iqinf_exit;
1470 }
1445 } 1471 }
1446 1472
1447 iqinf_exit: 1473 iqinf_exit:
1448 kfree(buffer); 1474 kfree(buffer);
1449 SMB2_open_free(&rqst[0]); 1475 SMB2_open_free(&rqst[0]);
1450 SMB2_query_info_free(&rqst[1]); 1476 if (qi.flags & PASSTHRU_FSCTL)
1477 SMB2_ioctl_free(&rqst[1]);
1478 else
1479 SMB2_query_info_free(&rqst[1]);
1480
1451 SMB2_close_free(&rqst[2]); 1481 SMB2_close_free(&rqst[2]);
1452 free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base); 1482 free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base);
1453 free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base); 1483 free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base);