Commit 2c87d6a9 authored by Long Li's avatar Long Li Committed by Steve French

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: default avatarLong Li <longli@microsoft.com>
Signed-off-by: default avatarSteve French <stfrench@microsoft.com>
Reviewed-by: default avatarPavel Shilovsky <pshilov@microsoft.com>
Reviewed-by: default avatarRonnie sahlberg <lsahlber@redhat.com>
parent 3b249115
...@@ -2538,11 +2538,25 @@ SMB2_ioctl_init(struct cifs_tcon *tcon, struct smb_rqst *rqst, ...@@ -2538,11 +2538,25 @@ SMB2_ioctl_init(struct cifs_tcon *tcon, struct smb_rqst *rqst,
struct kvec *iov = rqst->rq_iov; struct kvec *iov = rqst->rq_iov;
unsigned int total_len; unsigned int total_len;
int rc; int rc;
char *in_data_buf;
rc = smb2_plain_req_init(SMB2_IOCTL, tcon, (void **) &req, &total_len); rc = smb2_plain_req_init(SMB2_IOCTL, tcon, (void **) &req, &total_len);
if (rc) if (rc)
return 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->CtlCode = cpu_to_le32(opcode);
req->PersistentFileId = persistent_fid; req->PersistentFileId = persistent_fid;
req->VolatileFileId = volatile_fid; req->VolatileFileId = volatile_fid;
...@@ -2563,7 +2577,7 @@ SMB2_ioctl_init(struct cifs_tcon *tcon, struct smb_rqst *rqst, ...@@ -2563,7 +2577,7 @@ SMB2_ioctl_init(struct cifs_tcon *tcon, struct smb_rqst *rqst,
cpu_to_le32(offsetof(struct smb2_ioctl_req, Buffer)); cpu_to_le32(offsetof(struct smb2_ioctl_req, Buffer));
rqst->rq_nvec = 2; rqst->rq_nvec = 2;
iov[0].iov_len = total_len - 1; 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; iov[1].iov_len = indatalen;
} else { } else {
rqst->rq_nvec = 1; rqst->rq_nvec = 1;
...@@ -2605,8 +2619,11 @@ SMB2_ioctl_init(struct cifs_tcon *tcon, struct smb_rqst *rqst, ...@@ -2605,8 +2619,11 @@ SMB2_ioctl_init(struct cifs_tcon *tcon, struct smb_rqst *rqst,
void void
SMB2_ioctl_free(struct smb_rqst *rqst) 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 */ 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);
}
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment