]> Git Repo - linux.git/commitdiff
cifs: Allocate memory for all iovs in smb2_ioctl
authorLong Li <[email protected]>
Wed, 15 May 2019 21:09:05 +0000 (14:09 -0700)
committerSteve French <[email protected]>
Thu, 16 May 2019 03:27:53 +0000 (22:27 -0500)
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 <[email protected]>
Signed-off-by: Steve French <[email protected]>
Reviewed-by: Pavel Shilovsky <[email protected]>
Reviewed-by: Ronnie sahlberg <[email protected]>
fs/cifs/smb2pdu.c

index 29f011d8d8e2a4ec54731909de25d7c985b55493..710ceb875161a5a70e67f9af0e95f5b53b7b5284 100644 (file)
@@ -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);
+       }
 }
 
 
This page took 0.081563 seconds and 4 git commands to generate.