]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.9-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 22 Mar 2018 20:32:48 +0000 (21:32 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 22 Mar 2018 20:32:48 +0000 (21:32 +0100)
added patches:
usb-gadget-f_hid-fix-move-in-request-allocation-to-set_alt.patch

queue-4.9/ib-mlx5-fix-out-of-bounds-read-in-create_raw_packet_qp_rq.patch
queue-4.9/series
queue-4.9/usb-gadget-f_hid-fix-move-in-request-allocation-to-set_alt.patch [new file with mode: 0644]

index eb3f1fb3df4a5a27935d99d1686ddd7af920af30..bacd8f6e49f2b2b5fcc9c42d8f03145a731a4860 100644 (file)
@@ -122,8 +122,8 @@ Signed-off-by: Doug Ledford <dledford@redhat.com>
 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 
 ---
- drivers/infiniband/hw/mlx5/qp.c |   2++++++++++++++++-------
- 1 file changed, 16 insertions(+), 7 deletions(-)
+ drivers/infiniband/hw/mlx5/qp.c |   24 +++++++++++++++++-------
+ 1 file changed, 17 insertions(+), 7 deletions(-)
 
 --- a/drivers/infiniband/hw/mlx5/qp.c
 +++ b/drivers/infiniband/hw/mlx5/qp.c
@@ -196,3 +196,11 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
        } else {
                err = mlx5_core_create_qp(dev->mdev, &base->mqp, in, inlen);
        }
+@@ -1796,6 +1805,7 @@ err_create:
+       else if (qp->create_type == MLX5_QP_KERNEL)
+               destroy_qp_kernel(dev, qp);
++err:
+       kvfree(in);
+       return err;
+ }
index bcfdcd40b6825f38a5e21d8e9637d23a7ca51acc..7d51ab8ebb9e80f17df3eb0d121254cc14a3edcb 100644 (file)
@@ -174,3 +174,4 @@ ib-mlx5-fix-out-of-bounds-read-in-create_raw_packet_qp_rq.patch
 clk-migrate-the-count-of-orphaned-clocks-at-init.patch
 rdma-ucma-fix-access-to-non-initialized-cm_id-object.patch
 rdma-ucma-don-t-allow-join-attempts-for-unsupported-af-family.patch
+usb-gadget-f_hid-fix-move-in-request-allocation-to-set_alt.patch
diff --git a/queue-4.9/usb-gadget-f_hid-fix-move-in-request-allocation-to-set_alt.patch b/queue-4.9/usb-gadget-f_hid-fix-move-in-request-allocation-to-set_alt.patch
new file mode 100644 (file)
index 0000000..62dbfce
--- /dev/null
@@ -0,0 +1,230 @@
+From 749494b6bdbbaf0899aa1c62a1ad74cd747bce47 Mon Sep 17 00:00:00 2001
+From: Krzysztof Opasiak <kopasiak90@gmail.com>
+Date: Tue, 24 Jan 2017 03:27:24 +0100
+Subject: usb: gadget: f_hid: fix: Move IN request allocation to set_alt()
+
+From: Krzysztof Opasiak <kopasiak90@gmail.com>
+
+commit 749494b6bdbbaf0899aa1c62a1ad74cd747bce47 upstream.
+
+Since commit: ba1582f22231 ("usb: gadget: f_hid: use alloc_ep_req()")
+we cannot allocate any requests in bind() as we check if we should
+align request buffer based on endpoint descriptor which is assigned
+in set_alt().
+
+Allocating request in bind() function causes a NULL pointer
+dereference.
+
+This commit moves allocation of IN request from bind() to set_alt()
+to prevent this issue.
+
+Fixes: ba1582f22231 ("usb: gadget: f_hid: use alloc_ep_req()")
+Cc: stable@vger.kernel.org
+Tested-by: David Lechner <david@lechnology.com>
+Signed-off-by: Krzysztof Opasiak <k.opasiak@samsung.com>
+Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
+Cc: Bin Liu <b-liu@ti.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/gadget/function/f_hid.c |   89 +++++++++++++++++++++++++++---------
+ 1 file changed, 67 insertions(+), 22 deletions(-)
+
+--- a/drivers/usb/gadget/function/f_hid.c
++++ b/drivers/usb/gadget/function/f_hid.c
+@@ -284,6 +284,7 @@ static ssize_t f_hidg_write(struct file
+                           size_t count, loff_t *offp)
+ {
+       struct f_hidg *hidg  = file->private_data;
++      struct usb_request *req;
+       unsigned long flags;
+       ssize_t status = -ENOMEM;
+@@ -293,7 +294,7 @@ static ssize_t f_hidg_write(struct file
+       spin_lock_irqsave(&hidg->write_spinlock, flags);
+ #define WRITE_COND (!hidg->write_pending)
+-
++try_again:
+       /* write queue */
+       while (!WRITE_COND) {
+               spin_unlock_irqrestore(&hidg->write_spinlock, flags);
+@@ -308,6 +309,7 @@ static ssize_t f_hidg_write(struct file
+       }
+       hidg->write_pending = 1;
++      req = hidg->req;
+       count  = min_t(unsigned, count, hidg->report_length);
+       spin_unlock_irqrestore(&hidg->write_spinlock, flags);
+@@ -320,24 +322,38 @@ static ssize_t f_hidg_write(struct file
+               goto release_write_pending;
+       }
+-      hidg->req->status   = 0;
+-      hidg->req->zero     = 0;
+-      hidg->req->length   = count;
+-      hidg->req->complete = f_hidg_req_complete;
+-      hidg->req->context  = hidg;
++      spin_lock_irqsave(&hidg->write_spinlock, flags);
++
++      /* we our function has been disabled by host */
++      if (!hidg->req) {
++              free_ep_req(hidg->in_ep, hidg->req);
++              /*
++               * TODO
++               * Should we fail with error here?
++               */
++              goto try_again;
++      }
++
++      req->status   = 0;
++      req->zero     = 0;
++      req->length   = count;
++      req->complete = f_hidg_req_complete;
++      req->context  = hidg;
+       status = usb_ep_queue(hidg->in_ep, hidg->req, GFP_ATOMIC);
+       if (status < 0) {
+               ERROR(hidg->func.config->cdev,
+                       "usb_ep_queue error on int endpoint %zd\n", status);
+-              goto release_write_pending;
++              goto release_write_pending_unlocked;
+       } else {
+               status = count;
+       }
++      spin_unlock_irqrestore(&hidg->write_spinlock, flags);
+       return status;
+ release_write_pending:
+       spin_lock_irqsave(&hidg->write_spinlock, flags);
++release_write_pending_unlocked:
+       hidg->write_pending = 0;
+       spin_unlock_irqrestore(&hidg->write_spinlock, flags);
+@@ -541,12 +557,23 @@ static void hidg_disable(struct usb_func
+               kfree(list);
+       }
+       spin_unlock_irqrestore(&hidg->read_spinlock, flags);
++
++      spin_lock_irqsave(&hidg->write_spinlock, flags);
++      if (!hidg->write_pending) {
++              free_ep_req(hidg->in_ep, hidg->req);
++              hidg->write_pending = 1;
++      }
++
++      hidg->req = NULL;
++      spin_unlock_irqrestore(&hidg->write_spinlock, flags);
+ }
+ static int hidg_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
+ {
+       struct usb_composite_dev                *cdev = f->config->cdev;
+       struct f_hidg                           *hidg = func_to_hidg(f);
++      struct usb_request                      *req_in = NULL;
++      unsigned long                           flags;
+       int i, status = 0;
+       VDBG(cdev, "hidg_set_alt intf:%d alt:%d\n", intf, alt);
+@@ -567,6 +594,12 @@ static int hidg_set_alt(struct usb_funct
+                       goto fail;
+               }
+               hidg->in_ep->driver_data = hidg;
++
++              req_in = hidg_alloc_ep_req(hidg->in_ep, hidg->report_length);
++              if (!req_in) {
++                      status = -ENOMEM;
++                      goto disable_ep_in;
++              }
+       }
+@@ -578,12 +611,12 @@ static int hidg_set_alt(struct usb_funct
+                                           hidg->out_ep);
+               if (status) {
+                       ERROR(cdev, "config_ep_by_speed FAILED!\n");
+-                      goto fail;
++                      goto free_req_in;
+               }
+               status = usb_ep_enable(hidg->out_ep);
+               if (status < 0) {
+                       ERROR(cdev, "Enable OUT endpoint FAILED!\n");
+-                      goto fail;
++                      goto free_req_in;
+               }
+               hidg->out_ep->driver_data = hidg;
+@@ -599,17 +632,37 @@ static int hidg_set_alt(struct usb_funct
+                               req->context  = hidg;
+                               status = usb_ep_queue(hidg->out_ep, req,
+                                                     GFP_ATOMIC);
+-                              if (status)
++                              if (status) {
+                                       ERROR(cdev, "%s queue req --> %d\n",
+                                               hidg->out_ep->name, status);
++                                      free_ep_req(hidg->out_ep, req);
++                              }
+                       } else {
+-                              usb_ep_disable(hidg->out_ep);
+                               status = -ENOMEM;
+-                              goto fail;
++                              goto disable_out_ep;
+                       }
+               }
+       }
++      if (hidg->in_ep != NULL) {
++              spin_lock_irqsave(&hidg->write_spinlock, flags);
++              hidg->req = req_in;
++              hidg->write_pending = 0;
++              spin_unlock_irqrestore(&hidg->write_spinlock, flags);
++
++              wake_up(&hidg->write_queue);
++      }
++      return 0;
++disable_out_ep:
++      usb_ep_disable(hidg->out_ep);
++free_req_in:
++      if (req_in)
++              free_ep_req(hidg->in_ep, req_in);
++
++disable_ep_in:
++      if (hidg->in_ep)
++              usb_ep_disable(hidg->in_ep);
++
+ fail:
+       return status;
+ }
+@@ -658,12 +711,6 @@ static int hidg_bind(struct usb_configur
+               goto fail;
+       hidg->out_ep = ep;
+-      /* preallocate request and buffer */
+-      status = -ENOMEM;
+-      hidg->req = alloc_ep_req(hidg->in_ep, hidg->report_length);
+-      if (!hidg->req)
+-              goto fail;
+-
+       /* set descriptor dynamic values */
+       hidg_interface_desc.bInterfaceSubClass = hidg->bInterfaceSubClass;
+       hidg_interface_desc.bInterfaceProtocol = hidg->bInterfaceProtocol;
+@@ -690,6 +737,8 @@ static int hidg_bind(struct usb_configur
+               goto fail;
+       spin_lock_init(&hidg->write_spinlock);
++      hidg->write_pending = 1;
++      hidg->req = NULL;
+       spin_lock_init(&hidg->read_spinlock);
+       init_waitqueue_head(&hidg->write_queue);
+       init_waitqueue_head(&hidg->read_queue);
+@@ -954,10 +1003,6 @@ static void hidg_unbind(struct usb_confi
+       device_destroy(hidg_class, MKDEV(major, hidg->minor));
+       cdev_del(&hidg->cdev);
+-      /* disable/free request and end point */
+-      usb_ep_disable(hidg->in_ep);
+-      free_ep_req(hidg->in_ep, hidg->req);
+-
+       usb_free_all_descriptors(f);
+ }