From 4ec0ef3a82125efc36173062a50624550a900ae0 Mon Sep 17 00:00:00 2001 From: Josh Boyer Date: Mon, 14 Mar 2016 10:42:38 -0400 Subject: [PATCH 1/5] USB: iowarrior: fix oops with malicious USB descriptors The iowarrior driver expects at least one valid endpoint. If given malicious descriptors that specify 0 for the number of endpoints, it will crash in the probe function. Ensure there is at least one endpoint on the interface before using it. The full report of this issue can be found here: http://seclists.org/bugtraq/2016/Mar/87 Reported-by: Ralf Spenneberg Cc: stable Signed-off-by: Josh Boyer Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/iowarrior.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/usb/misc/iowarrior.c b/drivers/usb/misc/iowarrior.c index c6bfd13f6c92f..1950e87b42190 100644 --- a/drivers/usb/misc/iowarrior.c +++ b/drivers/usb/misc/iowarrior.c @@ -787,6 +787,12 @@ static int iowarrior_probe(struct usb_interface *interface, iface_desc = interface->cur_altsetting; dev->product_id = le16_to_cpu(udev->descriptor.idProduct); + if (iface_desc->desc.bNumEndpoints < 1) { + dev_err(&interface->dev, "Invalid number of endpoints\n"); + retval = -EINVAL; + goto error; + } + /* set up the endpoint information */ for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { endpoint = &iface_desc->endpoint[i].desc; From 7222c832254a75dcd67d683df75753d4a4e125bb Mon Sep 17 00:00:00 2001 From: Nicolai Stange Date: Thu, 17 Mar 2016 23:53:02 +0100 Subject: [PATCH 2/5] usb/core: usb_alloc_dev(): fix setting of ->portnum With commit 69bec7259853 ("USB: core: let USB device know device node"), the port1 argument of usb_alloc_dev() gets overwritten as follows: ... usb_alloc_dev(..., unsigned port1) { ... if (!parent->parent) { port1 = usb_hcd_find_raw_port_number(..., port1); } ... } Later on, this now overwritten port1 gets assigned to ->portnum: dev->portnum = port1; However, since xhci_find_raw_port_number() isn't idempotent, the aforementioned commit causes a number of KASAN splats like the following: BUG: KASAN: slab-out-of-bounds in xhci_find_raw_port_number+0x98/0x170 at addr ffff8801d9311670 Read of size 8 by task kworker/2:1/87 [...] Workqueue: usb_hub_wq hub_event 0000000000000188 000000005814b877 ffff8800cba17588 ffffffff8191447e 0000000041b58ab3 ffffffff82a03209 ffffffff819143a2 ffffffff82a252f4 ffff8801d93115e0 0000000000000188 ffff8801d9311628 ffff8800cba17588 Call Trace: [] dump_stack+0xdc/0x15e [] ? _atomic_dec_and_lock+0xa2/0xa2 [] ? print_section+0x61/0xb0 [] print_trailer+0x179/0x2c0 [] object_err+0x34/0x40 [] kasan_report_error+0x2f8/0x8b0 [] ? __slab_alloc+0x5e/0x90 [] ? __lock_is_held+0x90/0x130 [] kasan_report+0x71/0xa0 [] ? kmem_cache_alloc_trace+0x212/0x560 [] ? xhci_find_raw_port_number+0x98/0x170 [] __asan_load8+0x64/0x70 [] xhci_find_raw_port_number+0x98/0x170 [] xhci_setup_addressable_virt_dev+0x235/0xa10 [] xhci_setup_device+0x3c1/0x1430 [] ? trace_hardirqs_on+0xd/0x10 [] ? xhci_setup_device+0x1430/0x1430 [] xhci_address_device+0x13/0x20 [] hub_port_init+0x55a/0x1550 [] hub_event+0xef5/0x24d0 [] ? hub_port_debounce+0x2f0/0x2f0 [] ? debug_object_deactivate+0x1be/0x270 [] ? print_rt_rq+0x53/0x2d0 [] ? trace_hardirqs_off+0xd/0x10 [] ? _raw_spin_unlock_irqrestore+0x5b/0x60 [] ? irq_domain_set_hwirq_and_chip+0x30/0xb0 [] ? debug_lockdep_rcu_enabled+0x39/0x40 [] ? __lock_is_held+0x90/0x130 [] process_one_work+0x567/0xec0 [...] Afterwards, xhci reports some functional errors: xhci_hcd 0000:00:14.0: ERROR: unexpected setup address command completion code 0x11. xhci_hcd 0000:00:14.0: ERROR: unexpected setup address command completion code 0x11. usb 4-3: device not accepting address 2, error -22 Fix this by not overwriting the port1 argument in usb_alloc_dev(), but storing the raw port number as required by OF in an additional variable, raw_port. Fixes: 69bec7259853 ("USB: core: let USB device know device node") Signed-off-by: Nicolai Stange Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/usb.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index ffa5cf13ffe18..dcb85e3cd5a76 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -424,6 +424,7 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent, struct usb_device *dev; struct usb_hcd *usb_hcd = bus_to_hcd(bus); unsigned root_hub = 0; + unsigned raw_port = port1; dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) @@ -498,11 +499,11 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent, if (!parent->parent) { /* device under root hub's port */ - port1 = usb_hcd_find_raw_port_number(usb_hcd, + raw_port = usb_hcd_find_raw_port_number(usb_hcd, port1); } dev->dev.of_node = usb_of_get_child_node(parent->dev.of_node, - port1); + raw_port); /* hub driver sets up TT records */ } From 0b818e3956fc1ad976bee791eadcbb3b5fec5bfd Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Wed, 16 Mar 2016 13:26:17 +0100 Subject: [PATCH 3/5] USB: usb_driver_claim_interface: add sanity checking Attacks that trick drivers into passing a NULL pointer to usb_driver_claim_interface() using forged descriptors are known. This thwarts them by sanity checking. Signed-off-by: Oliver Neukum CC: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/driver.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 56593a9a87268..2057d91d83360 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -502,11 +502,15 @@ static int usb_unbind_interface(struct device *dev) int usb_driver_claim_interface(struct usb_driver *driver, struct usb_interface *iface, void *priv) { - struct device *dev = &iface->dev; + struct device *dev; struct usb_device *udev; int retval = 0; int lpm_disable_error; + if (!iface) + return -ENODEV; + + dev = &iface->dev; if (dev->driver) return -EBUSY; From 8835ba4a39cf53f705417b3b3a94eb067673f2c9 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Tue, 15 Mar 2016 10:14:04 +0100 Subject: [PATCH 4/5] USB: cdc-acm: more sanity checking An attack has become available which pretends to be a quirky device circumventing normal sanity checks and crashes the kernel by an insufficient number of interfaces. This patch adds a check to the code path for quirky devices. Signed-off-by: Oliver Neukum CC: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/cdc-acm.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 1d2c99af25324..83fd30b0577c5 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -1179,6 +1179,9 @@ static int acm_probe(struct usb_interface *intf, if (quirks == NO_UNION_NORMAL) { data_interface = usb_ifnum_to_if(usb_dev, 1); control_interface = usb_ifnum_to_if(usb_dev, 0); + /* we would crash */ + if (!data_interface || !control_interface) + return -ENODEV; goto skip_normal_probe; } From 55ff8cfbc4e12a7d2187df523938cc671fbebdd1 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 7 Mar 2016 20:11:52 +0100 Subject: [PATCH 5/5] USB: uas: Reduce can_queue to MAX_CMNDS The uas driver can never queue more then MAX_CMNDS (- 1) tags and tags are shared between luns, so there is no need to claim that we can_queue some random large number. Not claiming that we can_queue 65536 commands, fixes the uas driver failing to initialize while allocating the tag map with a "Page allocation failure (order 7)" error on systems which have been running for a while and thus have fragmented memory. Cc: stable@vger.kernel.org Reported-and-tested-by: Yves-Alexis Perez Signed-off-by: Hans de Goede Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/uas.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c index 44b096c1737b6..13e4cc31bc79e 100644 --- a/drivers/usb/storage/uas.c +++ b/drivers/usb/storage/uas.c @@ -836,7 +836,7 @@ static struct scsi_host_template uas_host_template = { .slave_configure = uas_slave_configure, .eh_abort_handler = uas_eh_abort_handler, .eh_bus_reset_handler = uas_eh_bus_reset_handler, - .can_queue = 65536, /* Is there a limit on the _host_ ? */ + .can_queue = MAX_CMNDS, .this_id = -1, .sg_tablesize = SG_NONE, .skip_settle_delay = 1,