From: Greg Kroah-Hartman Date: Thu, 22 Mar 2018 20:32:48 +0000 (+0100) Subject: 4.9-stable patches X-Git-Tag: v3.18.102~7 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=1ef332ae899858bc0ee70efa45a8ecbbc17bce64;p=thirdparty%2Fkernel%2Fstable-queue.git 4.9-stable patches added patches: usb-gadget-f_hid-fix-move-in-request-allocation-to-set_alt.patch --- diff --git a/queue-4.9/ib-mlx5-fix-out-of-bounds-read-in-create_raw_packet_qp_rq.patch b/queue-4.9/ib-mlx5-fix-out-of-bounds-read-in-create_raw_packet_qp_rq.patch index eb3f1fb3df4..bacd8f6e49f 100644 --- a/queue-4.9/ib-mlx5-fix-out-of-bounds-read-in-create_raw_packet_qp_rq.patch +++ b/queue-4.9/ib-mlx5-fix-out-of-bounds-read-in-create_raw_packet_qp_rq.patch @@ -122,8 +122,8 @@ Signed-off-by: Doug Ledford Signed-off-by: Greg Kroah-Hartman --- - drivers/infiniband/hw/mlx5/qp.c | 23 ++++++++++++++++------- - 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 } 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; + } diff --git a/queue-4.9/series b/queue-4.9/series index bcfdcd40b68..7d51ab8ebb9 100644 --- a/queue-4.9/series +++ b/queue-4.9/series @@ -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 index 00000000000..62dbfce7f2e --- /dev/null +++ b/queue-4.9/usb-gadget-f_hid-fix-move-in-request-allocation-to-set_alt.patch @@ -0,0 +1,230 @@ +From 749494b6bdbbaf0899aa1c62a1ad74cd747bce47 Mon Sep 17 00:00:00 2001 +From: Krzysztof Opasiak +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 + +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 +Signed-off-by: Krzysztof Opasiak +Signed-off-by: Felipe Balbi +Cc: Bin Liu +Signed-off-by: Greg Kroah-Hartman + +--- + 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); + } +