From: Greg Kroah-Hartman Date: Fri, 26 Jan 2018 09:36:14 +0000 (+0100) Subject: 4.4-stable patches X-Git-Tag: v4.4.114~30 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=f104820cf84a0185e8ab4b56dbbd3121592c587a;p=thirdparty%2Fkernel%2Fstable-queue.git 4.4-stable patches added patches: input-trackpoint-force-3-buttons-if-0-button-is-reported.patch usb-usbip-fix-possible-deadlocks-reported-by-lockdep.patch usbip-fix-stub_rx-get_pipe-to-validate-endpoint-number.patch usbip-fix-stub_rx-harden-cmd_submit-path-to-handle-malicious-input.patch usbip-prevent-leaking-socket-pointer-address-in-messages.patch --- diff --git a/queue-4.4/input-trackpoint-force-3-buttons-if-0-button-is-reported.patch b/queue-4.4/input-trackpoint-force-3-buttons-if-0-button-is-reported.patch new file mode 100644 index 00000000000..5e8958dc047 --- /dev/null +++ b/queue-4.4/input-trackpoint-force-3-buttons-if-0-button-is-reported.patch @@ -0,0 +1,45 @@ +From f5d07b9e98022d50720e38aa936fc11c67868ece Mon Sep 17 00:00:00 2001 +From: Aaron Ma +Date: Fri, 19 Jan 2018 09:43:39 -0800 +Subject: Input: trackpoint - force 3 buttons if 0 button is reported + +From: Aaron Ma + +commit f5d07b9e98022d50720e38aa936fc11c67868ece upstream. + +Lenovo introduced trackpoint compatible sticks with minimum PS/2 commands. +They supposed to reply with 0x02, 0x03, or 0x04 in response to the +"Read Extended ID" command, so we would know not to try certain extended +commands. Unfortunately even some trackpoints reporting the original IBM +version (0x01 firmware 0x0e) now respond with incorrect data to the "Get +Extended Buttons" command: + + thinkpad_acpi: ThinkPad BIOS R0DET87W (1.87 ), EC unknown + thinkpad_acpi: Lenovo ThinkPad E470, model 20H1004SGE + + psmouse serio2: trackpoint: IBM TrackPoint firmware: 0x0e, buttons: 0/0 + +Since there are no trackpoints without buttons, let's assume the trackpoint +has 3 buttons when we get 0 response to the extended buttons query. + +Signed-off-by: Aaron Ma +Fixes: https://bugzilla.kernel.org/show_bug.cgi?id=196253 +Signed-off-by: Dmitry Torokhov +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/input/mouse/trackpoint.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/input/mouse/trackpoint.c ++++ b/drivers/input/mouse/trackpoint.c +@@ -383,6 +383,9 @@ int trackpoint_detect(struct psmouse *ps + if (trackpoint_read(&psmouse->ps2dev, TP_EXT_BTN, &button_info)) { + psmouse_warn(psmouse, "failed to get extended button data, assuming 3 buttons\n"); + button_info = 0x33; ++ } else if (!button_info) { ++ psmouse_warn(psmouse, "got 0 in extended button data, assuming 3 buttons\n"); ++ button_info = 0x33; + } + + psmouse->private = kzalloc(sizeof(struct trackpoint_data), GFP_KERNEL); diff --git a/queue-4.4/series b/queue-4.4/series index f2c8569a331..bd614e2fe2a 100644 --- a/queue-4.4/series +++ b/queue-4.4/series @@ -45,3 +45,8 @@ reiserfs-don-t-clear-sgid-when-inheriting-acls.patch fs-fcntl-f_setown-avoid-undefined-behaviour.patch scsi-libiscsi-fix-shifting-of-did_requeue-host-byte.patch revert-module-add-retpoline-tag-to-vermagic.patch +input-trackpoint-force-3-buttons-if-0-button-is-reported.patch +usb-usbip-fix-possible-deadlocks-reported-by-lockdep.patch +usbip-fix-stub_rx-get_pipe-to-validate-endpoint-number.patch +usbip-fix-stub_rx-harden-cmd_submit-path-to-handle-malicious-input.patch +usbip-prevent-leaking-socket-pointer-address-in-messages.patch diff --git a/queue-4.4/usb-usbip-fix-possible-deadlocks-reported-by-lockdep.patch b/queue-4.4/usb-usbip-fix-possible-deadlocks-reported-by-lockdep.patch new file mode 100644 index 00000000000..1ecf3a9cfee --- /dev/null +++ b/queue-4.4/usb-usbip-fix-possible-deadlocks-reported-by-lockdep.patch @@ -0,0 +1,621 @@ +From 21619792d1eca7e772ca190ba68588e57f29595b Mon Sep 17 00:00:00 2001 +From: Andrew Goodbody +Date: Tue, 2 Feb 2016 17:36:39 +0000 +Subject: usb: usbip: Fix possible deadlocks reported by lockdep + +From: Andrew Goodbody + +commit 21619792d1eca7e772ca190ba68588e57f29595b upstream. + +Change spin_lock calls to spin_lock_irqsave to prevent +attmpted recursive lock taking in interrupt context. + +This patch fixes Bug 109351 + https://bugzilla.kernel.org/show_bug.cgi?id=109351 + +Signed-off-by: Andrew Goodbody +Signed-off-by: Shuah Khan +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/usbip/usbip_event.c | 5 +- + drivers/usb/usbip/vhci_hcd.c | 88 +++++++++++++++++++++++----------------- + drivers/usb/usbip/vhci_rx.c | 30 +++++++------ + drivers/usb/usbip/vhci_sysfs.c | 19 +++++--- + drivers/usb/usbip/vhci_tx.c | 14 +++--- + 5 files changed, 91 insertions(+), 65 deletions(-) + +--- a/drivers/usb/usbip/usbip_event.c ++++ b/drivers/usb/usbip/usbip_event.c +@@ -117,11 +117,12 @@ EXPORT_SYMBOL_GPL(usbip_event_add); + int usbip_event_happened(struct usbip_device *ud) + { + int happened = 0; ++ unsigned long flags; + +- spin_lock(&ud->lock); ++ spin_lock_irqsave(&ud->lock, flags); + if (ud->event != 0) + happened = 1; +- spin_unlock(&ud->lock); ++ spin_unlock_irqrestore(&ud->lock, flags); + + return happened; + } +--- a/drivers/usb/usbip/vhci_hcd.c ++++ b/drivers/usb/usbip/vhci_hcd.c +@@ -121,9 +121,11 @@ static void dump_port_status_diff(u32 pr + + void rh_port_connect(int rhport, enum usb_device_speed speed) + { ++ unsigned long flags; ++ + usbip_dbg_vhci_rh("rh_port_connect %d\n", rhport); + +- spin_lock(&the_controller->lock); ++ spin_lock_irqsave(&the_controller->lock, flags); + + the_controller->port_status[rhport] |= USB_PORT_STAT_CONNECTION + | (1 << USB_PORT_FEAT_C_CONNECTION); +@@ -139,22 +141,24 @@ void rh_port_connect(int rhport, enum us + break; + } + +- spin_unlock(&the_controller->lock); ++ spin_unlock_irqrestore(&the_controller->lock, flags); + + usb_hcd_poll_rh_status(vhci_to_hcd(the_controller)); + } + + static void rh_port_disconnect(int rhport) + { ++ unsigned long flags; ++ + usbip_dbg_vhci_rh("rh_port_disconnect %d\n", rhport); + +- spin_lock(&the_controller->lock); ++ spin_lock_irqsave(&the_controller->lock, flags); + + the_controller->port_status[rhport] &= ~USB_PORT_STAT_CONNECTION; + the_controller->port_status[rhport] |= + (1 << USB_PORT_FEAT_C_CONNECTION); + +- spin_unlock(&the_controller->lock); ++ spin_unlock_irqrestore(&the_controller->lock, flags); + usb_hcd_poll_rh_status(vhci_to_hcd(the_controller)); + } + +@@ -182,13 +186,14 @@ static int vhci_hub_status(struct usb_hc + int retval; + int rhport; + int changed = 0; ++ unsigned long flags; + + retval = DIV_ROUND_UP(VHCI_NPORTS + 1, 8); + memset(buf, 0, retval); + + vhci = hcd_to_vhci(hcd); + +- spin_lock(&vhci->lock); ++ spin_lock_irqsave(&vhci->lock, flags); + if (!HCD_HW_ACCESSIBLE(hcd)) { + usbip_dbg_vhci_rh("hw accessible flag not on?\n"); + goto done; +@@ -209,7 +214,7 @@ static int vhci_hub_status(struct usb_hc + usb_hcd_resume_root_hub(hcd); + + done: +- spin_unlock(&vhci->lock); ++ spin_unlock_irqrestore(&vhci->lock, flags); + return changed ? retval : 0; + } + +@@ -236,6 +241,7 @@ static int vhci_hub_control(struct usb_h + struct vhci_hcd *dum; + int retval = 0; + int rhport; ++ unsigned long flags; + + u32 prev_port_status[VHCI_NPORTS]; + +@@ -254,7 +260,7 @@ static int vhci_hub_control(struct usb_h + + dum = hcd_to_vhci(hcd); + +- spin_lock(&dum->lock); ++ spin_lock_irqsave(&dum->lock, flags); + + /* store old status and compare now and old later */ + if (usbip_dbg_flag_vhci_rh) { +@@ -408,7 +414,7 @@ static int vhci_hub_control(struct usb_h + } + usbip_dbg_vhci_rh(" bye\n"); + +- spin_unlock(&dum->lock); ++ spin_unlock_irqrestore(&dum->lock, flags); + + return retval; + } +@@ -431,6 +437,7 @@ static void vhci_tx_urb(struct urb *urb) + { + struct vhci_device *vdev = get_vdev(urb->dev); + struct vhci_priv *priv; ++ unsigned long flags; + + if (!vdev) { + pr_err("could not get virtual device"); +@@ -443,7 +450,7 @@ static void vhci_tx_urb(struct urb *urb) + return; + } + +- spin_lock(&vdev->priv_lock); ++ spin_lock_irqsave(&vdev->priv_lock, flags); + + priv->seqnum = atomic_inc_return(&the_controller->seqnum); + if (priv->seqnum == 0xffff) +@@ -457,7 +464,7 @@ static void vhci_tx_urb(struct urb *urb) + list_add_tail(&priv->list, &vdev->priv_tx); + + wake_up(&vdev->waitq_tx); +- spin_unlock(&vdev->priv_lock); ++ spin_unlock_irqrestore(&vdev->priv_lock, flags); + } + + static int vhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, +@@ -466,15 +473,16 @@ static int vhci_urb_enqueue(struct usb_h + struct device *dev = &urb->dev->dev; + int ret = 0; + struct vhci_device *vdev; ++ unsigned long flags; + + /* patch to usb_sg_init() is in 2.5.60 */ + BUG_ON(!urb->transfer_buffer && urb->transfer_buffer_length); + +- spin_lock(&the_controller->lock); ++ spin_lock_irqsave(&the_controller->lock, flags); + + if (urb->status != -EINPROGRESS) { + dev_err(dev, "URB already unlinked!, status %d\n", urb->status); +- spin_unlock(&the_controller->lock); ++ spin_unlock_irqrestore(&the_controller->lock, flags); + return urb->status; + } + +@@ -486,7 +494,7 @@ static int vhci_urb_enqueue(struct usb_h + vdev->ud.status == VDEV_ST_ERROR) { + dev_err(dev, "enqueue for inactive port %d\n", vdev->rhport); + spin_unlock(&vdev->ud.lock); +- spin_unlock(&the_controller->lock); ++ spin_unlock_irqrestore(&the_controller->lock, flags); + return -ENODEV; + } + spin_unlock(&vdev->ud.lock); +@@ -559,14 +567,14 @@ static int vhci_urb_enqueue(struct usb_h + + out: + vhci_tx_urb(urb); +- spin_unlock(&the_controller->lock); ++ spin_unlock_irqrestore(&the_controller->lock, flags); + + return 0; + + no_need_xmit: + usb_hcd_unlink_urb_from_ep(hcd, urb); + no_need_unlink: +- spin_unlock(&the_controller->lock); ++ spin_unlock_irqrestore(&the_controller->lock, flags); + if (!ret) + usb_hcd_giveback_urb(vhci_to_hcd(the_controller), + urb, urb->status); +@@ -623,14 +631,15 @@ static int vhci_urb_dequeue(struct usb_h + { + struct vhci_priv *priv; + struct vhci_device *vdev; ++ unsigned long flags; + +- spin_lock(&the_controller->lock); ++ spin_lock_irqsave(&the_controller->lock, flags); + + priv = urb->hcpriv; + if (!priv) { + /* URB was never linked! or will be soon given back by + * vhci_rx. */ +- spin_unlock(&the_controller->lock); ++ spin_unlock_irqrestore(&the_controller->lock, flags); + return -EIDRM; + } + +@@ -639,7 +648,7 @@ static int vhci_urb_dequeue(struct usb_h + + ret = usb_hcd_check_unlink_urb(hcd, urb, status); + if (ret) { +- spin_unlock(&the_controller->lock); ++ spin_unlock_irqrestore(&the_controller->lock, flags); + return ret; + } + } +@@ -664,10 +673,10 @@ static int vhci_urb_dequeue(struct usb_h + */ + usb_hcd_unlink_urb_from_ep(hcd, urb); + +- spin_unlock(&the_controller->lock); ++ spin_unlock_irqrestore(&the_controller->lock, flags); + usb_hcd_giveback_urb(vhci_to_hcd(the_controller), urb, + urb->status); +- spin_lock(&the_controller->lock); ++ spin_lock_irqsave(&the_controller->lock, flags); + + } else { + /* tcp connection is alive */ +@@ -679,7 +688,7 @@ static int vhci_urb_dequeue(struct usb_h + unlink = kzalloc(sizeof(struct vhci_unlink), GFP_ATOMIC); + if (!unlink) { + spin_unlock(&vdev->priv_lock); +- spin_unlock(&the_controller->lock); ++ spin_unlock_irqrestore(&the_controller->lock, flags); + usbip_event_add(&vdev->ud, VDEV_EVENT_ERROR_MALLOC); + return -ENOMEM; + } +@@ -698,7 +707,7 @@ static int vhci_urb_dequeue(struct usb_h + spin_unlock(&vdev->priv_lock); + } + +- spin_unlock(&the_controller->lock); ++ spin_unlock_irqrestore(&the_controller->lock, flags); + + usbip_dbg_vhci_hc("leave\n"); + return 0; +@@ -707,8 +716,9 @@ static int vhci_urb_dequeue(struct usb_h + static void vhci_device_unlink_cleanup(struct vhci_device *vdev) + { + struct vhci_unlink *unlink, *tmp; ++ unsigned long flags; + +- spin_lock(&the_controller->lock); ++ spin_lock_irqsave(&the_controller->lock, flags); + spin_lock(&vdev->priv_lock); + + list_for_each_entry_safe(unlink, tmp, &vdev->unlink_tx, list) { +@@ -742,19 +752,19 @@ static void vhci_device_unlink_cleanup(s + list_del(&unlink->list); + + spin_unlock(&vdev->priv_lock); +- spin_unlock(&the_controller->lock); ++ spin_unlock_irqrestore(&the_controller->lock, flags); + + usb_hcd_giveback_urb(vhci_to_hcd(the_controller), urb, + urb->status); + +- spin_lock(&the_controller->lock); ++ spin_lock_irqsave(&the_controller->lock, flags); + spin_lock(&vdev->priv_lock); + + kfree(unlink); + } + + spin_unlock(&vdev->priv_lock); +- spin_unlock(&the_controller->lock); ++ spin_unlock_irqrestore(&the_controller->lock, flags); + } + + /* +@@ -821,8 +831,9 @@ static void vhci_shutdown_connection(str + static void vhci_device_reset(struct usbip_device *ud) + { + struct vhci_device *vdev = container_of(ud, struct vhci_device, ud); ++ unsigned long flags; + +- spin_lock(&ud->lock); ++ spin_lock_irqsave(&ud->lock, flags); + + vdev->speed = 0; + vdev->devid = 0; +@@ -836,14 +847,16 @@ static void vhci_device_reset(struct usb + } + ud->status = VDEV_ST_NULL; + +- spin_unlock(&ud->lock); ++ spin_unlock_irqrestore(&ud->lock, flags); + } + + static void vhci_device_unusable(struct usbip_device *ud) + { +- spin_lock(&ud->lock); ++ unsigned long flags; ++ ++ spin_lock_irqsave(&ud->lock, flags); + ud->status = VDEV_ST_ERROR; +- spin_unlock(&ud->lock); ++ spin_unlock_irqrestore(&ud->lock, flags); + } + + static void vhci_device_init(struct vhci_device *vdev) +@@ -933,12 +946,13 @@ static int vhci_get_frame_number(struct + static int vhci_bus_suspend(struct usb_hcd *hcd) + { + struct vhci_hcd *vhci = hcd_to_vhci(hcd); ++ unsigned long flags; + + dev_dbg(&hcd->self.root_hub->dev, "%s\n", __func__); + +- spin_lock(&vhci->lock); ++ spin_lock_irqsave(&vhci->lock, flags); + hcd->state = HC_STATE_SUSPENDED; +- spin_unlock(&vhci->lock); ++ spin_unlock_irqrestore(&vhci->lock, flags); + + return 0; + } +@@ -947,15 +961,16 @@ static int vhci_bus_resume(struct usb_hc + { + struct vhci_hcd *vhci = hcd_to_vhci(hcd); + int rc = 0; ++ unsigned long flags; + + dev_dbg(&hcd->self.root_hub->dev, "%s\n", __func__); + +- spin_lock(&vhci->lock); ++ spin_lock_irqsave(&vhci->lock, flags); + if (!HCD_HW_ACCESSIBLE(hcd)) + rc = -ESHUTDOWN; + else + hcd->state = HC_STATE_RUNNING; +- spin_unlock(&vhci->lock); ++ spin_unlock_irqrestore(&vhci->lock, flags); + + return rc; + } +@@ -1053,17 +1068,18 @@ static int vhci_hcd_suspend(struct platf + int rhport = 0; + int connected = 0; + int ret = 0; ++ unsigned long flags; + + hcd = platform_get_drvdata(pdev); + +- spin_lock(&the_controller->lock); ++ spin_lock_irqsave(&the_controller->lock, flags); + + for (rhport = 0; rhport < VHCI_NPORTS; rhport++) + if (the_controller->port_status[rhport] & + USB_PORT_STAT_CONNECTION) + connected += 1; + +- spin_unlock(&the_controller->lock); ++ spin_unlock_irqrestore(&the_controller->lock, flags); + + if (connected > 0) { + dev_info(&pdev->dev, +--- a/drivers/usb/usbip/vhci_rx.c ++++ b/drivers/usb/usbip/vhci_rx.c +@@ -71,10 +71,11 @@ static void vhci_recv_ret_submit(struct + { + struct usbip_device *ud = &vdev->ud; + struct urb *urb; ++ unsigned long flags; + +- spin_lock(&vdev->priv_lock); ++ spin_lock_irqsave(&vdev->priv_lock, flags); + urb = pickup_urb_and_free_priv(vdev, pdu->base.seqnum); +- spin_unlock(&vdev->priv_lock); ++ spin_unlock_irqrestore(&vdev->priv_lock, flags); + + if (!urb) { + pr_err("cannot find a urb of seqnum %u max seqnum %d\n", +@@ -103,9 +104,9 @@ static void vhci_recv_ret_submit(struct + + usbip_dbg_vhci_rx("now giveback urb %u\n", pdu->base.seqnum); + +- spin_lock(&the_controller->lock); ++ spin_lock_irqsave(&the_controller->lock, flags); + usb_hcd_unlink_urb_from_ep(vhci_to_hcd(the_controller), urb); +- spin_unlock(&the_controller->lock); ++ spin_unlock_irqrestore(&the_controller->lock, flags); + + usb_hcd_giveback_urb(vhci_to_hcd(the_controller), urb, urb->status); + +@@ -116,8 +117,9 @@ static struct vhci_unlink *dequeue_pendi + struct usbip_header *pdu) + { + struct vhci_unlink *unlink, *tmp; ++ unsigned long flags; + +- spin_lock(&vdev->priv_lock); ++ spin_lock_irqsave(&vdev->priv_lock, flags); + + list_for_each_entry_safe(unlink, tmp, &vdev->unlink_rx, list) { + pr_info("unlink->seqnum %lu\n", unlink->seqnum); +@@ -126,12 +128,12 @@ static struct vhci_unlink *dequeue_pendi + unlink->seqnum); + list_del(&unlink->list); + +- spin_unlock(&vdev->priv_lock); ++ spin_unlock_irqrestore(&vdev->priv_lock, flags); + return unlink; + } + } + +- spin_unlock(&vdev->priv_lock); ++ spin_unlock_irqrestore(&vdev->priv_lock, flags); + + return NULL; + } +@@ -141,6 +143,7 @@ static void vhci_recv_ret_unlink(struct + { + struct vhci_unlink *unlink; + struct urb *urb; ++ unsigned long flags; + + usbip_dump_header(pdu); + +@@ -151,9 +154,9 @@ static void vhci_recv_ret_unlink(struct + return; + } + +- spin_lock(&vdev->priv_lock); ++ spin_lock_irqsave(&vdev->priv_lock, flags); + urb = pickup_urb_and_free_priv(vdev, unlink->unlink_seqnum); +- spin_unlock(&vdev->priv_lock); ++ spin_unlock_irqrestore(&vdev->priv_lock, flags); + + if (!urb) { + /* +@@ -170,9 +173,9 @@ static void vhci_recv_ret_unlink(struct + urb->status = pdu->u.ret_unlink.status; + pr_info("urb->status %d\n", urb->status); + +- spin_lock(&the_controller->lock); ++ spin_lock_irqsave(&the_controller->lock, flags); + usb_hcd_unlink_urb_from_ep(vhci_to_hcd(the_controller), urb); +- spin_unlock(&the_controller->lock); ++ spin_unlock_irqrestore(&the_controller->lock, flags); + + usb_hcd_giveback_urb(vhci_to_hcd(the_controller), urb, + urb->status); +@@ -184,10 +187,11 @@ static void vhci_recv_ret_unlink(struct + static int vhci_priv_tx_empty(struct vhci_device *vdev) + { + int empty = 0; ++ unsigned long flags; + +- spin_lock(&vdev->priv_lock); ++ spin_lock_irqsave(&vdev->priv_lock, flags); + empty = list_empty(&vdev->priv_rx); +- spin_unlock(&vdev->priv_lock); ++ spin_unlock_irqrestore(&vdev->priv_lock, flags); + + return empty; + } +--- a/drivers/usb/usbip/vhci_sysfs.c ++++ b/drivers/usb/usbip/vhci_sysfs.c +@@ -32,10 +32,11 @@ static ssize_t status_show(struct device + { + char *s = out; + int i = 0; ++ unsigned long flags; + + BUG_ON(!the_controller || !out); + +- spin_lock(&the_controller->lock); ++ spin_lock_irqsave(&the_controller->lock, flags); + + /* + * output example: +@@ -74,7 +75,7 @@ static ssize_t status_show(struct device + spin_unlock(&vdev->ud.lock); + } + +- spin_unlock(&the_controller->lock); ++ spin_unlock_irqrestore(&the_controller->lock, flags); + + return out - s; + } +@@ -84,11 +85,12 @@ static DEVICE_ATTR_RO(status); + static int vhci_port_disconnect(__u32 rhport) + { + struct vhci_device *vdev; ++ unsigned long flags; + + usbip_dbg_vhci_sysfs("enter\n"); + + /* lock */ +- spin_lock(&the_controller->lock); ++ spin_lock_irqsave(&the_controller->lock, flags); + + vdev = port_to_vdev(rhport); + +@@ -98,14 +100,14 @@ static int vhci_port_disconnect(__u32 rh + + /* unlock */ + spin_unlock(&vdev->ud.lock); +- spin_unlock(&the_controller->lock); ++ spin_unlock_irqrestore(&the_controller->lock, flags); + + return -EINVAL; + } + + /* unlock */ + spin_unlock(&vdev->ud.lock); +- spin_unlock(&the_controller->lock); ++ spin_unlock_irqrestore(&the_controller->lock, flags); + + usbip_event_add(&vdev->ud, VDEV_EVENT_DOWN); + +@@ -181,6 +183,7 @@ static ssize_t store_attach(struct devic + int sockfd = 0; + __u32 rhport = 0, devid = 0, speed = 0; + int err; ++ unsigned long flags; + + /* + * @rhport: port number of vhci_hcd +@@ -206,14 +209,14 @@ static ssize_t store_attach(struct devic + /* now need lock until setting vdev status as used */ + + /* begin a lock */ +- spin_lock(&the_controller->lock); ++ spin_lock_irqsave(&the_controller->lock, flags); + vdev = port_to_vdev(rhport); + spin_lock(&vdev->ud.lock); + + if (vdev->ud.status != VDEV_ST_NULL) { + /* end of the lock */ + spin_unlock(&vdev->ud.lock); +- spin_unlock(&the_controller->lock); ++ spin_unlock_irqrestore(&the_controller->lock, flags); + + sockfd_put(socket); + +@@ -232,7 +235,7 @@ static ssize_t store_attach(struct devic + vdev->ud.status = VDEV_ST_NOTASSIGNED; + + spin_unlock(&vdev->ud.lock); +- spin_unlock(&the_controller->lock); ++ spin_unlock_irqrestore(&the_controller->lock, flags); + /* end the lock */ + + vdev->ud.tcp_rx = kthread_get_run(vhci_rx_loop, &vdev->ud, "vhci_rx"); +--- a/drivers/usb/usbip/vhci_tx.c ++++ b/drivers/usb/usbip/vhci_tx.c +@@ -47,16 +47,17 @@ static void setup_cmd_submit_pdu(struct + static struct vhci_priv *dequeue_from_priv_tx(struct vhci_device *vdev) + { + struct vhci_priv *priv, *tmp; ++ unsigned long flags; + +- spin_lock(&vdev->priv_lock); ++ spin_lock_irqsave(&vdev->priv_lock, flags); + + list_for_each_entry_safe(priv, tmp, &vdev->priv_tx, list) { + list_move_tail(&priv->list, &vdev->priv_rx); +- spin_unlock(&vdev->priv_lock); ++ spin_unlock_irqrestore(&vdev->priv_lock, flags); + return priv; + } + +- spin_unlock(&vdev->priv_lock); ++ spin_unlock_irqrestore(&vdev->priv_lock, flags); + + return NULL; + } +@@ -137,16 +138,17 @@ static int vhci_send_cmd_submit(struct v + static struct vhci_unlink *dequeue_from_unlink_tx(struct vhci_device *vdev) + { + struct vhci_unlink *unlink, *tmp; ++ unsigned long flags; + +- spin_lock(&vdev->priv_lock); ++ spin_lock_irqsave(&vdev->priv_lock, flags); + + list_for_each_entry_safe(unlink, tmp, &vdev->unlink_tx, list) { + list_move_tail(&unlink->list, &vdev->unlink_rx); +- spin_unlock(&vdev->priv_lock); ++ spin_unlock_irqrestore(&vdev->priv_lock, flags); + return unlink; + } + +- spin_unlock(&vdev->priv_lock); ++ spin_unlock_irqrestore(&vdev->priv_lock, flags); + + return NULL; + } diff --git a/queue-4.4/usbip-fix-stub_rx-get_pipe-to-validate-endpoint-number.patch b/queue-4.4/usbip-fix-stub_rx-get_pipe-to-validate-endpoint-number.patch new file mode 100644 index 00000000000..0b6b865d088 --- /dev/null +++ b/queue-4.4/usbip-fix-stub_rx-get_pipe-to-validate-endpoint-number.patch @@ -0,0 +1,71 @@ +From 635f545a7e8be7596b9b2b6a43cab6bbd5a88e43 Mon Sep 17 00:00:00 2001 +From: Shuah Khan +Date: Thu, 7 Dec 2017 14:16:47 -0700 +Subject: usbip: fix stub_rx: get_pipe() to validate endpoint number + +From: Shuah Khan + +commit 635f545a7e8be7596b9b2b6a43cab6bbd5a88e43 upstream. + +get_pipe() routine doesn't validate the input endpoint number +and uses to reference ep_in and ep_out arrays. Invalid endpoint +number can trigger BUG(). Range check the epnum and returning +error instead of calling BUG(). + +Change caller stub_recv_cmd_submit() to handle the get_pipe() +error return. + +Reported-by: Secunia Research +Signed-off-by: Shuah Khan +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/usbip/stub_rx.c | 18 +++++++++++------- + 1 file changed, 11 insertions(+), 7 deletions(-) + +--- a/drivers/usb/usbip/stub_rx.c ++++ b/drivers/usb/usbip/stub_rx.c +@@ -344,15 +344,15 @@ static int get_pipe(struct stub_device * + struct usb_host_endpoint *ep; + struct usb_endpoint_descriptor *epd = NULL; + ++ if (epnum < 0 || epnum > 15) ++ goto err_ret; ++ + if (dir == USBIP_DIR_IN) + ep = udev->ep_in[epnum & 0x7f]; + else + ep = udev->ep_out[epnum & 0x7f]; +- if (!ep) { +- dev_err(&sdev->interface->dev, "no such endpoint?, %d\n", +- epnum); +- BUG(); +- } ++ if (!ep) ++ goto err_ret; + + epd = &ep->desc; + if (usb_endpoint_xfer_control(epd)) { +@@ -383,9 +383,10 @@ static int get_pipe(struct stub_device * + return usb_rcvisocpipe(udev, epnum); + } + ++err_ret: + /* NOT REACHED */ +- dev_err(&sdev->interface->dev, "get pipe, epnum %d\n", epnum); +- return 0; ++ dev_err(&sdev->udev->dev, "get pipe() invalid epnum %d\n", epnum); ++ return -1; + } + + static void masking_bogus_flags(struct urb *urb) +@@ -451,6 +452,9 @@ static void stub_recv_cmd_submit(struct + struct usb_device *udev = sdev->udev; + int pipe = get_pipe(sdev, pdu->base.ep, pdu->base.direction); + ++ if (pipe == -1) ++ return; ++ + priv = stub_priv_alloc(sdev, pdu); + if (!priv) + return; diff --git a/queue-4.4/usbip-fix-stub_rx-harden-cmd_submit-path-to-handle-malicious-input.patch b/queue-4.4/usbip-fix-stub_rx-harden-cmd_submit-path-to-handle-malicious-input.patch new file mode 100644 index 00000000000..4e7a4c787a5 --- /dev/null +++ b/queue-4.4/usbip-fix-stub_rx-harden-cmd_submit-path-to-handle-malicious-input.patch @@ -0,0 +1,95 @@ +From c6688ef9f29762e65bce325ef4acd6c675806366 Mon Sep 17 00:00:00 2001 +From: Shuah Khan +Date: Thu, 7 Dec 2017 14:16:48 -0700 +Subject: usbip: fix stub_rx: harden CMD_SUBMIT path to handle malicious input + +From: Shuah Khan + +commit c6688ef9f29762e65bce325ef4acd6c675806366 upstream. + +Harden CMD_SUBMIT path to handle malicious input that could trigger +large memory allocations. Add checks to validate transfer_buffer_length +and number_of_packets to protect against bad input requesting for +unbounded memory allocations. Validate early in get_pipe() and return +failure. + +Reported-by: Secunia Research +Signed-off-by: Shuah Khan +Signed-off-by: Greg Kroah-Hartman + + +--- + drivers/usb/usbip/stub_rx.c | 30 +++++++++++++++++++++++++++--- + 1 file changed, 27 insertions(+), 3 deletions(-) + +--- a/drivers/usb/usbip/stub_rx.c ++++ b/drivers/usb/usbip/stub_rx.c +@@ -338,11 +338,13 @@ static struct stub_priv *stub_priv_alloc + return priv; + } + +-static int get_pipe(struct stub_device *sdev, int epnum, int dir) ++static int get_pipe(struct stub_device *sdev, struct usbip_header *pdu) + { + struct usb_device *udev = sdev->udev; + struct usb_host_endpoint *ep; + struct usb_endpoint_descriptor *epd = NULL; ++ int epnum = pdu->base.ep; ++ int dir = pdu->base.direction; + + if (epnum < 0 || epnum > 15) + goto err_ret; +@@ -355,6 +357,7 @@ static int get_pipe(struct stub_device * + goto err_ret; + + epd = &ep->desc; ++ + if (usb_endpoint_xfer_control(epd)) { + if (dir == USBIP_DIR_OUT) + return usb_sndctrlpipe(udev, epnum); +@@ -377,6 +380,27 @@ static int get_pipe(struct stub_device * + } + + if (usb_endpoint_xfer_isoc(epd)) { ++ /* validate packet size and number of packets */ ++ unsigned int maxp, packets, bytes; ++ ++#define USB_EP_MAXP_MULT_SHIFT 11 ++#define USB_EP_MAXP_MULT_MASK (3 << USB_EP_MAXP_MULT_SHIFT) ++#define USB_EP_MAXP_MULT(m) \ ++ (((m) & USB_EP_MAXP_MULT_MASK) >> USB_EP_MAXP_MULT_SHIFT) ++ ++ maxp = usb_endpoint_maxp(epd); ++ maxp *= (USB_EP_MAXP_MULT( ++ __le16_to_cpu(epd->wMaxPacketSize)) + 1); ++ bytes = pdu->u.cmd_submit.transfer_buffer_length; ++ packets = DIV_ROUND_UP(bytes, maxp); ++ ++ if (pdu->u.cmd_submit.number_of_packets < 0 || ++ pdu->u.cmd_submit.number_of_packets > packets) { ++ dev_err(&sdev->udev->dev, ++ "CMD_SUBMIT: isoc invalid num packets %d\n", ++ pdu->u.cmd_submit.number_of_packets); ++ return -1; ++ } + if (dir == USBIP_DIR_OUT) + return usb_sndisocpipe(udev, epnum); + else +@@ -385,7 +409,7 @@ static int get_pipe(struct stub_device * + + err_ret: + /* NOT REACHED */ +- dev_err(&sdev->udev->dev, "get pipe() invalid epnum %d\n", epnum); ++ dev_err(&sdev->udev->dev, "CMD_SUBMIT: invalid epnum %d\n", epnum); + return -1; + } + +@@ -450,7 +474,7 @@ static void stub_recv_cmd_submit(struct + struct stub_priv *priv; + struct usbip_device *ud = &sdev->ud; + struct usb_device *udev = sdev->udev; +- int pipe = get_pipe(sdev, pdu->base.ep, pdu->base.direction); ++ int pipe = get_pipe(sdev, pdu); + + if (pipe == -1) + return; diff --git a/queue-4.4/usbip-prevent-leaking-socket-pointer-address-in-messages.patch b/queue-4.4/usbip-prevent-leaking-socket-pointer-address-in-messages.patch new file mode 100644 index 00000000000..2a52cb769bf --- /dev/null +++ b/queue-4.4/usbip-prevent-leaking-socket-pointer-address-in-messages.patch @@ -0,0 +1,82 @@ +From 90120d15f4c397272aaf41077960a157fc4212bf Mon Sep 17 00:00:00 2001 +From: Shuah Khan +Date: Fri, 15 Dec 2017 10:50:09 -0700 +Subject: usbip: prevent leaking socket pointer address in messages + +From: Shuah Khan + +commit 90120d15f4c397272aaf41077960a157fc4212bf upstream. + +usbip driver is leaking socket pointer address in messages. Remove +the messages that aren't useful and print sockfd in the ones that +are useful for debugging. + +Signed-off-by: Shuah Khan +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/usbip/stub_dev.c | 3 +-- + drivers/usb/usbip/usbip_common.c | 15 ++++----------- + drivers/usb/usbip/vhci_hcd.c | 2 +- + 3 files changed, 6 insertions(+), 14 deletions(-) + +--- a/drivers/usb/usbip/stub_dev.c ++++ b/drivers/usb/usbip/stub_dev.c +@@ -163,8 +163,7 @@ static void stub_shutdown_connection(str + * step 1? + */ + if (ud->tcp_socket) { +- dev_dbg(&sdev->udev->dev, "shutdown tcp_socket %p\n", +- ud->tcp_socket); ++ dev_dbg(&sdev->udev->dev, "shutdown sockfd %d\n", ud->sockfd); + kernel_sock_shutdown(ud->tcp_socket, SHUT_RDWR); + } + +--- a/drivers/usb/usbip/usbip_common.c ++++ b/drivers/usb/usbip/usbip_common.c +@@ -317,18 +317,14 @@ int usbip_recv(struct socket *sock, void + struct msghdr msg; + struct kvec iov; + int total = 0; +- + /* for blocks of if (usbip_dbg_flag_xmit) */ + char *bp = buf; + int osize = size; + +- usbip_dbg_xmit("enter\n"); +- +- if (!sock || !buf || !size) { +- pr_err("invalid arg, sock %p buff %p size %d\n", sock, buf, +- size); ++ if (!sock || !buf || !size) + return -EINVAL; +- } ++ ++ usbip_dbg_xmit("enter\n"); + + do { + sock->sk->sk_allocation = GFP_NOIO; +@@ -341,11 +337,8 @@ int usbip_recv(struct socket *sock, void + msg.msg_flags = MSG_NOSIGNAL; + + result = kernel_recvmsg(sock, &msg, &iov, 1, size, MSG_WAITALL); +- if (result <= 0) { +- pr_debug("receive sock %p buf %p size %u ret %d total %d\n", +- sock, buf, size, result, total); ++ if (result <= 0) + goto err; +- } + + size -= result; + buf += result; +--- a/drivers/usb/usbip/vhci_hcd.c ++++ b/drivers/usb/usbip/vhci_hcd.c +@@ -778,7 +778,7 @@ static void vhci_shutdown_connection(str + + /* need this? see stub_dev.c */ + if (ud->tcp_socket) { +- pr_debug("shutdown tcp_socket %p\n", ud->tcp_socket); ++ pr_debug("shutdown sockfd %d\n", ud->sockfd); + kernel_sock_shutdown(ud->tcp_socket, SHUT_RDWR); + } +