Skip to content

Commit

Permalink
cifs: Allocate memory for all iovs in smb2_ioctl
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Long Li authored and Steve French committed May 16, 2019
1 parent 3b24911 commit 2c87d6a
Showing 1 changed file with 19 additions and 2 deletions.
21 changes: 19 additions & 2 deletions fs/cifs/smb2pdu.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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);
}
}


Expand Down

0 comments on commit 2c87d6a

Please sign in to comment.