summaryrefslogtreecommitdiff
path: root/fs/cifs
diff options
context:
space:
mode:
authorLong Li <longli@microsoft.com>2019-05-15 14:09:05 -0700
committerSteve French <stfrench@microsoft.com>2019-05-15 22:27:53 -0500
commit2c87d6a94d162e68ca393cb87719dae8737f55c0 (patch)
treecd3f5b7d487cfcb182434229a8a0a12af740a03d /fs/cifs
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>
Diffstat (limited to 'fs/cifs')
-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,
struct kvec *iov = rqst->rq_iov;
unsigned int total_len;
int rc;
+ char *in_data_buf;
rc = smb2_plain_req_init(SMB2_IOCTL, tcon, (void **) &req, &total_len);
if (rc)
return rc;
+ if (indatalen) {
+ /*
+ * indatalen is usually small at a couple of bytes max, so
+ * just allocate through generic pool
+ */
+ in_data_buf = kmalloc(indatalen, GFP_NOFS);
+ if (!in_data_buf) {
+ cifs_small_buf_release(req);
+ return -ENOMEM;
+ }
+ memcpy(in_data_buf, in_data, indatalen);
+ }
+
req->CtlCode = cpu_to_le32(opcode);
req->PersistentFileId = persistent_fid;
req->VolatileFileId = volatile_fid;
@@ -2563,7 +2577,7 @@ SMB2_ioctl_init(struct cifs_tcon *tcon, struct smb_rqst *rqst,
cpu_to_le32(offsetof(struct smb2_ioctl_req, Buffer));
rqst->rq_nvec = 2;
iov[0].iov_len = total_len - 1;
- iov[1].iov_base = in_data;
+ iov[1].iov_base = in_data_buf;
iov[1].iov_len = indatalen;
} else {
rqst->rq_nvec = 1;
@@ -2605,8 +2619,11 @@ SMB2_ioctl_init(struct cifs_tcon *tcon, struct smb_rqst *rqst,
void
SMB2_ioctl_free(struct smb_rqst *rqst)
{
- if (rqst && rqst->rq_iov)
+ if (rqst && rqst->rq_iov) {
cifs_small_buf_release(rqst->rq_iov[0].iov_base); /* request */
+ if (rqst->rq_iov[1].iov_len)
+ kfree(rqst->rq_iov[1].iov_base);
+ }
}