diff options
| -rw-r--r-- | fs/cifs/smb2ops.c | 62 |
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); |
