aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLong Li <longli@microsoft.com>2019-05-15 17:09:05 -0400
committerSteve French <stfrench@microsoft.com>2019-05-15 23:27:53 -0400
commit2c87d6a94d162e68ca393cb87719dae8737f55c0 (patch)
treecd3f5b7d487cfcb182434229a8a0a12af740a03d
parent3b249115719ba2cb56d3f92ee7492e033059d3f3 (diff)
cifs: Allocate memory for all iovs in smb2_ioctl
An IOCTL uses up to 2 iovs. The 1st iov is the command itself, the 2nd iov is optional data for that command. The 1st iov is always allocated on the heap but the 2nd iov may point to a variable on the stack. This will trigger an error when passing the 2nd iov for RDMA I/O. Fix this by allocating a buffer for the 2nd iov. Signed-off-by: Long Li <longli@microsoft.com> Signed-off-by: Steve French <stfrench@microsoft.com> Reviewed-by: Pavel Shilovsky <pshilov@microsoft.com> Reviewed-by: Ronnie sahlberg <lsahlber@redhat.com>
-rw-r--r--fs/cifs/smb2pdu.c21
1 files changed, 19 insertions, 2 deletions
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index 29f011d8d8e2..710ceb875161 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -2538,11 +2538,25 @@ SMB2_ioctl_init(struct cifs_tcon *tcon, struct smb_rqst *rqst,
2538 struct kvec *iov = rqst->rq_iov; 2538 struct kvec *iov = rqst->rq_iov;
2539 unsigned int total_len; 2539 unsigned int total_len;
2540 int rc; 2540 int rc;
2541 char *in_data_buf;
2541 2542
2542 rc = smb2_plain_req_init(SMB2_IOCTL, tcon, (void **) &req, &total_len); 2543 rc = smb2_plain_req_init(SMB2_IOCTL, tcon, (void **) &req, &total_len);
2543 if (rc) 2544 if (rc)
2544 return rc; 2545 return rc;
2545 2546
2547 if (indatalen) {
2548 /*
2549 * indatalen is usually small at a couple of bytes max, so
2550 * just allocate through generic pool
2551 */
2552 in_data_buf = kmalloc(indatalen, GFP_NOFS);
2553 if (!in_data_buf) {
2554 cifs_small_buf_release(req);
2555 return -ENOMEM;
2556 }
2557 memcpy(in_data_buf, in_data, indatalen);
2558 }
2559
2546 req->CtlCode = cpu_to_le32(opcode); 2560 req->CtlCode = cpu_to_le32(opcode);
2547 req->PersistentFileId = persistent_fid; 2561 req->PersistentFileId = persistent_fid;
2548 req->VolatileFileId = volatile_fid; 2562 req->VolatileFileId = volatile_fid;
@@ -2563,7 +2577,7 @@ SMB2_ioctl_init(struct cifs_tcon *tcon, struct smb_rqst *rqst,
2563 cpu_to_le32(offsetof(struct smb2_ioctl_req, Buffer)); 2577 cpu_to_le32(offsetof(struct smb2_ioctl_req, Buffer));
2564 rqst->rq_nvec = 2; 2578 rqst->rq_nvec = 2;
2565 iov[0].iov_len = total_len - 1; 2579 iov[0].iov_len = total_len - 1;
2566 iov[1].iov_base = in_data; 2580 iov[1].iov_base = in_data_buf;
2567 iov[1].iov_len = indatalen; 2581 iov[1].iov_len = indatalen;
2568 } else { 2582 } else {
2569 rqst->rq_nvec = 1; 2583 rqst->rq_nvec = 1;
@@ -2605,8 +2619,11 @@ SMB2_ioctl_init(struct cifs_tcon *tcon, struct smb_rqst *rqst,
2605void 2619void
2606SMB2_ioctl_free(struct smb_rqst *rqst) 2620SMB2_ioctl_free(struct smb_rqst *rqst)
2607{ 2621{
2608 if (rqst && rqst->rq_iov) 2622 if (rqst && rqst->rq_iov) {
2609 cifs_small_buf_release(rqst->rq_iov[0].iov_base); /* request */ 2623 cifs_small_buf_release(rqst->rq_iov[0].iov_base); /* request */
2624 if (rqst->rq_iov[1].iov_len)
2625 kfree(rqst->rq_iov[1].iov_base);
2626 }
2610} 2627}
2611 2628
2612 2629