From: Greg Kroah-Hartman Date: Mon, 9 Oct 2017 12:04:09 +0000 (+0200) Subject: 4.4-stable patches X-Git-Tag: v3.18.75~32 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=889f4f04c64e3be67e8e027929d3353566964dbd;p=thirdparty%2Fkernel%2Fstable-queue.git 4.4-stable patches added patches: iio-adc-twl4030-disable-the-vusb3v1-rugulator-in-the-error-handling-path-of-twl4030_madc_probe.patch iio-adc-twl4030-fix-an-error-handling-path-in-twl4030_madc_probe.patch usb-core-harden-cdc_parse_cdc_header.patch usb-fix-out-of-bounds-in-usb_set_configuration.patch usb-g_mass_storage-fix-deadlock-when-driver-is-unbound.patch usb-increase-quirk-delay-for-usb-devices.patch usb-uas-fix-bug-in-handling-of-alternate-settings.patch xhci-fix-finding-correct-bus_state-structure-for-usb-3.1-hosts.patch --- diff --git a/queue-4.4/iio-adc-twl4030-disable-the-vusb3v1-rugulator-in-the-error-handling-path-of-twl4030_madc_probe.patch b/queue-4.4/iio-adc-twl4030-disable-the-vusb3v1-rugulator-in-the-error-handling-path-of-twl4030_madc_probe.patch new file mode 100644 index 00000000000..8f0a3c784e1 --- /dev/null +++ b/queue-4.4/iio-adc-twl4030-disable-the-vusb3v1-rugulator-in-the-error-handling-path-of-twl4030_madc_probe.patch @@ -0,0 +1,42 @@ +From 7f70be6e4025db0551e6863e7eb9cca07122695c Mon Sep 17 00:00:00 2001 +From: Christophe JAILLET +Date: Sat, 23 Sep 2017 08:06:19 +0200 +Subject: iio: adc: twl4030: Disable the vusb3v1 rugulator in the error handling path of 'twl4030_madc_probe()' + +From: Christophe JAILLET + +commit 7f70be6e4025db0551e6863e7eb9cca07122695c upstream. + +Commit 7cc97d77ee8a has introduced a call to 'regulator_disable()' in the +.remove function. +So we should also have such a call in the .probe function in case of +error after a successful 'regulator_enable()' call. + +Add a new label for that and use it. + +Fixes: 7cc97d77ee8a ("iio: adc: twl4030: Fix ADC[3:6] readings") +Signed-off-by: Christophe JAILLET +Signed-off-by: Jonathan Cameron +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/iio/adc/twl4030-madc.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/drivers/iio/adc/twl4030-madc.c ++++ b/drivers/iio/adc/twl4030-madc.c +@@ -878,11 +878,13 @@ static int twl4030_madc_probe(struct pla + ret = iio_device_register(iio_dev); + if (ret) { + dev_err(&pdev->dev, "could not register iio device\n"); +- goto err_i2c; ++ goto err_usb3v1; + } + + return 0; + ++err_usb3v1: ++ regulator_disable(madc->usb3v1); + err_i2c: + twl4030_madc_set_current_generator(madc, 0, 0); + err_current_generator: diff --git a/queue-4.4/iio-adc-twl4030-fix-an-error-handling-path-in-twl4030_madc_probe.patch b/queue-4.4/iio-adc-twl4030-fix-an-error-handling-path-in-twl4030_madc_probe.patch new file mode 100644 index 00000000000..96422a20505 --- /dev/null +++ b/queue-4.4/iio-adc-twl4030-fix-an-error-handling-path-in-twl4030_madc_probe.patch @@ -0,0 +1,37 @@ +From 245a396a9b1a67ac5c3228737c261b3e48708a2a Mon Sep 17 00:00:00 2001 +From: Christophe JAILLET +Date: Sat, 23 Sep 2017 08:06:18 +0200 +Subject: iio: adc: twl4030: Fix an error handling path in 'twl4030_madc_probe()' + +From: Christophe JAILLET + +commit 245a396a9b1a67ac5c3228737c261b3e48708a2a upstream. + +If 'devm_regulator_get()' fails, we should go through the existing error +handling path instead of returning directly, as done is all the other +error handling paths in this function. + +Fixes: 7cc97d77ee8a ("iio: adc: twl4030: Fix ADC[3:6] readings") +Signed-off-by: Christophe JAILLET +Signed-off-by: Jonathan Cameron +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/iio/adc/twl4030-madc.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +--- a/drivers/iio/adc/twl4030-madc.c ++++ b/drivers/iio/adc/twl4030-madc.c +@@ -866,8 +866,10 @@ static int twl4030_madc_probe(struct pla + + /* Enable 3v1 bias regulator for MADC[3:6] */ + madc->usb3v1 = devm_regulator_get(madc->dev, "vusb3v1"); +- if (IS_ERR(madc->usb3v1)) +- return -ENODEV; ++ if (IS_ERR(madc->usb3v1)) { ++ ret = -ENODEV; ++ goto err_i2c; ++ } + + ret = regulator_enable(madc->usb3v1); + if (ret) diff --git a/queue-4.4/series b/queue-4.4/series index cf516fcb8af..43a11710d27 100644 --- a/queue-4.4/series +++ b/queue-4.4/series @@ -11,3 +11,11 @@ usb-dummy-hcd-fix-connection-failures-wrong-speed.patch usb-dummy-hcd-fix-infinite-loop-resubmission-bug.patch usb-dummy-hcd-fix-erroneous-synchronization-change.patch usb-devio-don-t-corrupt-user-memory.patch +usb-g_mass_storage-fix-deadlock-when-driver-is-unbound.patch +usb-uas-fix-bug-in-handling-of-alternate-settings.patch +usb-core-harden-cdc_parse_cdc_header.patch +usb-increase-quirk-delay-for-usb-devices.patch +usb-fix-out-of-bounds-in-usb_set_configuration.patch +xhci-fix-finding-correct-bus_state-structure-for-usb-3.1-hosts.patch +iio-adc-twl4030-fix-an-error-handling-path-in-twl4030_madc_probe.patch +iio-adc-twl4030-disable-the-vusb3v1-rugulator-in-the-error-handling-path-of-twl4030_madc_probe.patch diff --git a/queue-4.4/usb-core-harden-cdc_parse_cdc_header.patch b/queue-4.4/usb-core-harden-cdc_parse_cdc_header.patch new file mode 100644 index 00000000000..f71bb67e7fe --- /dev/null +++ b/queue-4.4/usb-core-harden-cdc_parse_cdc_header.patch @@ -0,0 +1,39 @@ +From 2e1c42391ff2556387b3cb6308b24f6f65619feb Mon Sep 17 00:00:00 2001 +From: Greg Kroah-Hartman +Date: Thu, 21 Sep 2017 16:58:48 +0200 +Subject: USB: core: harden cdc_parse_cdc_header + +From: Greg Kroah-Hartman + +commit 2e1c42391ff2556387b3cb6308b24f6f65619feb upstream. + +Andrey Konovalov reported a possible out-of-bounds problem for the +cdc_parse_cdc_header function. He writes: + It looks like cdc_parse_cdc_header() doesn't validate buflen + before accessing buffer[1], buffer[2] and so on. The only check + present is while (buflen > 0). + +So fix this issue up by properly validating the buffer length matches +what the descriptor says it is. + +Reported-by: Andrey Konovalov +Tested-by: Andrey Konovalov +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/net/usb/usbnet.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/drivers/net/usb/usbnet.c ++++ b/drivers/net/usb/usbnet.c +@@ -1990,6 +1990,10 @@ int cdc_parse_cdc_header(struct usb_cdc_ + elength = 1; + goto next_desc; + } ++ if ((buflen < elength) || (elength < 3)) { ++ dev_err(&intf->dev, "invalid descriptor buffer length\n"); ++ break; ++ } + if (buffer[1] != USB_DT_CS_INTERFACE) { + dev_err(&intf->dev, "skipping garbage\n"); + goto next_desc; diff --git a/queue-4.4/usb-fix-out-of-bounds-in-usb_set_configuration.patch b/queue-4.4/usb-fix-out-of-bounds-in-usb_set_configuration.patch new file mode 100644 index 00000000000..775f8c12387 --- /dev/null +++ b/queue-4.4/usb-fix-out-of-bounds-in-usb_set_configuration.patch @@ -0,0 +1,67 @@ +From bd7a3fe770ebd8391d1c7d072ff88e9e76d063eb Mon Sep 17 00:00:00 2001 +From: Greg Kroah-Hartman +Date: Tue, 19 Sep 2017 15:07:17 +0200 +Subject: USB: fix out-of-bounds in usb_set_configuration + +From: Greg Kroah-Hartman + +commit bd7a3fe770ebd8391d1c7d072ff88e9e76d063eb upstream. + +Andrey Konovalov reported a possible out-of-bounds problem for a USB interface +association descriptor. He writes: + It seems there's no proper size check of a USB_DT_INTERFACE_ASSOCIATION + descriptor. It's only checked that the size is >= 2 in + usb_parse_configuration(), so find_iad() might do out-of-bounds access + to intf_assoc->bInterfaceCount. + +And he's right, we don't check for crazy descriptors of this type very well, so +resolve this problem. Yet another issue found by syzkaller... + +Reported-by: Andrey Konovalov +Tested-by: Andrey Konovalov +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/core/config.c | 14 +++++++++++--- + include/uapi/linux/usb/ch9.h | 1 + + 2 files changed, 12 insertions(+), 3 deletions(-) + +--- a/drivers/usb/core/config.c ++++ b/drivers/usb/core/config.c +@@ -609,15 +609,23 @@ static int usb_parse_configuration(struc + + } else if (header->bDescriptorType == + USB_DT_INTERFACE_ASSOCIATION) { ++ struct usb_interface_assoc_descriptor *d; ++ ++ d = (struct usb_interface_assoc_descriptor *)header; ++ if (d->bLength < USB_DT_INTERFACE_ASSOCIATION_SIZE) { ++ dev_warn(ddev, ++ "config %d has an invalid interface association descriptor of length %d, skipping\n", ++ cfgno, d->bLength); ++ continue; ++ } ++ + if (iad_num == USB_MAXIADS) { + dev_warn(ddev, "found more Interface " + "Association Descriptors " + "than allocated for in " + "configuration %d\n", cfgno); + } else { +- config->intf_assoc[iad_num] = +- (struct usb_interface_assoc_descriptor +- *)header; ++ config->intf_assoc[iad_num] = d; + iad_num++; + } + +--- a/include/uapi/linux/usb/ch9.h ++++ b/include/uapi/linux/usb/ch9.h +@@ -717,6 +717,7 @@ struct usb_interface_assoc_descriptor { + __u8 iFunction; + } __attribute__ ((packed)); + ++#define USB_DT_INTERFACE_ASSOCIATION_SIZE 8 + + /*-------------------------------------------------------------------------*/ + diff --git a/queue-4.4/usb-g_mass_storage-fix-deadlock-when-driver-is-unbound.patch b/queue-4.4/usb-g_mass_storage-fix-deadlock-when-driver-is-unbound.patch new file mode 100644 index 00000000000..792f47de766 --- /dev/null +++ b/queue-4.4/usb-g_mass_storage-fix-deadlock-when-driver-is-unbound.patch @@ -0,0 +1,261 @@ +From 1fbbb78f25d1291274f320462bf6908906f538db Mon Sep 17 00:00:00 2001 +From: Alan Stern +Date: Thu, 21 Sep 2017 13:22:00 -0400 +Subject: USB: g_mass_storage: Fix deadlock when driver is unbound + +From: Alan Stern + +commit 1fbbb78f25d1291274f320462bf6908906f538db upstream. + +As a holdover from the old g_file_storage gadget, the g_mass_storage +legacy gadget driver attempts to unregister itself when its main +operating thread terminates (if it hasn't been unregistered already). +This is not strictly necessary; it was never more than an attempt to +have the gadget fail cleanly if something went wrong and the main +thread was killed. + +However, now that the UDC core manages gadget drivers independently of +UDC drivers, this scheme doesn't work any more. A simple test: + + modprobe dummy-hcd + modprobe g-mass-storage file=... + rmmod dummy-hcd + +ends up in a deadlock with the following backtrace: + + sysrq: SysRq : Show Blocked State + task PC stack pid father + file-storage D 0 1130 2 0x00000000 + Call Trace: + __schedule+0x53e/0x58c + schedule+0x6e/0x77 + schedule_preempt_disabled+0xd/0xf + __mutex_lock.isra.1+0x129/0x224 + ? _raw_spin_unlock_irqrestore+0x12/0x14 + __mutex_lock_slowpath+0x12/0x14 + mutex_lock+0x28/0x2b + usb_gadget_unregister_driver+0x29/0x9b [udc_core] + usb_composite_unregister+0x10/0x12 [libcomposite] + msg_cleanup+0x1d/0x20 [g_mass_storage] + msg_thread_exits+0xd/0xdd7 [g_mass_storage] + fsg_main_thread+0x1395/0x13d6 [usb_f_mass_storage] + ? __schedule+0x573/0x58c + kthread+0xd9/0xdb + ? do_set_interface+0x25c/0x25c [usb_f_mass_storage] + ? init_completion+0x1e/0x1e + ret_from_fork+0x19/0x24 + rmmod D 0 1155 683 0x00000000 + Call Trace: + __schedule+0x53e/0x58c + schedule+0x6e/0x77 + schedule_timeout+0x26/0xbc + ? __schedule+0x573/0x58c + do_wait_for_common+0xb3/0x128 + ? usleep_range+0x81/0x81 + ? wake_up_q+0x3f/0x3f + wait_for_common+0x2e/0x45 + wait_for_completion+0x17/0x19 + fsg_common_put+0x34/0x81 [usb_f_mass_storage] + fsg_free_inst+0x13/0x1e [usb_f_mass_storage] + usb_put_function_instance+0x1a/0x25 [libcomposite] + msg_unbind+0x2a/0x42 [g_mass_storage] + __composite_unbind+0x4a/0x6f [libcomposite] + composite_unbind+0x12/0x14 [libcomposite] + usb_gadget_remove_driver+0x4f/0x77 [udc_core] + usb_del_gadget_udc+0x52/0xcc [udc_core] + dummy_udc_remove+0x27/0x2c [dummy_hcd] + platform_drv_remove+0x1d/0x31 + device_release_driver_internal+0xe9/0x16d + device_release_driver+0x11/0x13 + bus_remove_device+0xd2/0xe2 + device_del+0x19f/0x221 + ? selinux_capable+0x22/0x27 + platform_device_del+0x21/0x63 + platform_device_unregister+0x10/0x1a + cleanup+0x20/0x817 [dummy_hcd] + SyS_delete_module+0x10c/0x197 + ? ____fput+0xd/0xf + ? task_work_run+0x55/0x62 + ? prepare_exit_to_usermode+0x65/0x75 + do_fast_syscall_32+0x86/0xc3 + entry_SYSENTER_32+0x4e/0x7c + +What happens is that removing the dummy-hcd driver causes the UDC core +to unbind the gadget driver, which it does while holding the udc_lock +mutex. The unbind routine in g_mass_storage tells the main thread to +exit and waits for it to terminate. + +But as mentioned above, when the main thread exits it tries to +unregister the mass-storage function driver. Via the composite +framework this ends up calling usb_gadget_unregister_driver(), which +tries to acquire the udc_lock mutex. The result is deadlock. + +The simplest way to fix the problem is not to be so clever: The main +thread doesn't have to unregister the function driver. The side +effects won't be so terrible; if the gadget is still attached to a USB +host when the main thread is killed, it will appear to the host as +though the gadget's firmware has crashed -- a reasonably accurate +interpretation, and an all-too-common occurrence for USB mass-storage +devices. + +In fact, the code to unregister the driver when the main thread exits +is specific to g-mass-storage; it is not used when f-mass-storage is +included as a function in a larger composite device. Therefore the +entire mechanism responsible for this (the fsg_operations structure +with its ->thread_exits method, the fsg_common_set_ops() routine, and +the msg_thread_exits() callback routine) can all be eliminated. Even +the msg_registered bitflag can be removed, because now the driver is +unregistered in only one place rather than in two places. + +Signed-off-by: Alan Stern +Acked-by: Felipe Balbi +Acked-by: Michal Nazarewicz +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/gadget/function/f_mass_storage.c | 29 +++++++-------------------- + drivers/usb/gadget/function/f_mass_storage.h | 14 ------------- + drivers/usb/gadget/legacy/mass_storage.c | 19 +---------------- + 3 files changed, 10 insertions(+), 52 deletions(-) + +--- a/drivers/usb/gadget/function/f_mass_storage.c ++++ b/drivers/usb/gadget/function/f_mass_storage.c +@@ -306,8 +306,6 @@ struct fsg_common { + struct completion thread_notifier; + struct task_struct *thread_task; + +- /* Callback functions. */ +- const struct fsg_operations *ops; + /* Gadget's private data. */ + void *private_data; + +@@ -2504,6 +2502,7 @@ static void handle_exception(struct fsg_ + static int fsg_main_thread(void *common_) + { + struct fsg_common *common = common_; ++ int i; + + /* + * Allow the thread to be killed by a signal, but set the signal mask +@@ -2565,21 +2564,16 @@ static int fsg_main_thread(void *common_ + common->thread_task = NULL; + spin_unlock_irq(&common->lock); + +- if (!common->ops || !common->ops->thread_exits +- || common->ops->thread_exits(common) < 0) { +- int i; +- +- down_write(&common->filesem); +- for (i = 0; i < ARRAY_SIZE(common->luns); --i) { +- struct fsg_lun *curlun = common->luns[i]; +- if (!curlun || !fsg_lun_is_open(curlun)) +- continue; ++ /* Eject media from all LUNs */ + ++ down_write(&common->filesem); ++ for (i = 0; i < ARRAY_SIZE(common->luns); i++) { ++ struct fsg_lun *curlun = common->luns[i]; ++ ++ if (curlun && fsg_lun_is_open(curlun)) + fsg_lun_close(curlun); +- curlun->unit_attention_data = SS_MEDIUM_NOT_PRESENT; +- } +- up_write(&common->filesem); + } ++ up_write(&common->filesem); + + /* Let fsg_unbind() know the thread has exited */ + complete_and_exit(&common->thread_notifier, 0); +@@ -2785,13 +2779,6 @@ void fsg_common_remove_luns(struct fsg_c + } + EXPORT_SYMBOL_GPL(fsg_common_remove_luns); + +-void fsg_common_set_ops(struct fsg_common *common, +- const struct fsg_operations *ops) +-{ +- common->ops = ops; +-} +-EXPORT_SYMBOL_GPL(fsg_common_set_ops); +- + void fsg_common_free_buffers(struct fsg_common *common) + { + _fsg_common_free_buffers(common->buffhds, common->fsg_num_buffers); +--- a/drivers/usb/gadget/function/f_mass_storage.h ++++ b/drivers/usb/gadget/function/f_mass_storage.h +@@ -60,17 +60,6 @@ struct fsg_module_parameters { + struct fsg_common; + + /* FSF callback functions */ +-struct fsg_operations { +- /* +- * Callback function to call when thread exits. If no +- * callback is set or it returns value lower then zero MSF +- * will force eject all LUNs it operates on (including those +- * marked as non-removable or with prevent_medium_removal flag +- * set). +- */ +- int (*thread_exits)(struct fsg_common *common); +-}; +- + struct fsg_lun_opts { + struct config_group group; + struct fsg_lun *lun; +@@ -141,9 +130,6 @@ void fsg_common_remove_lun(struct fsg_lu + + void fsg_common_remove_luns(struct fsg_common *common); + +-void fsg_common_set_ops(struct fsg_common *common, +- const struct fsg_operations *ops); +- + int fsg_common_create_lun(struct fsg_common *common, struct fsg_lun_config *cfg, + unsigned int id, const char *name, + const char **name_pfx); +--- a/drivers/usb/gadget/legacy/mass_storage.c ++++ b/drivers/usb/gadget/legacy/mass_storage.c +@@ -107,15 +107,6 @@ static unsigned int fsg_num_buffers = CO + + FSG_MODULE_PARAMETERS(/* no prefix */, mod_data); + +-static unsigned long msg_registered; +-static void msg_cleanup(void); +- +-static int msg_thread_exits(struct fsg_common *common) +-{ +- msg_cleanup(); +- return 0; +-} +- + static int msg_do_config(struct usb_configuration *c) + { + struct fsg_opts *opts; +@@ -154,9 +145,6 @@ static struct usb_configuration msg_conf + + static int msg_bind(struct usb_composite_dev *cdev) + { +- static const struct fsg_operations ops = { +- .thread_exits = msg_thread_exits, +- }; + struct fsg_opts *opts; + struct fsg_config config; + int status; +@@ -173,8 +161,6 @@ static int msg_bind(struct usb_composite + if (status) + goto fail; + +- fsg_common_set_ops(opts->common, &ops); +- + status = fsg_common_set_cdev(opts->common, cdev, config.can_stall); + if (status) + goto fail_set_cdev; +@@ -261,9 +247,8 @@ static int __init msg_init(void) + } + module_init(msg_init); + +-static void msg_cleanup(void) ++static void __exit msg_cleanup(void) + { +- if (test_and_clear_bit(0, &msg_registered)) +- usb_composite_unregister(&msg_driver); ++ usb_composite_unregister(&msg_driver); + } + module_exit(msg_cleanup); diff --git a/queue-4.4/usb-increase-quirk-delay-for-usb-devices.patch b/queue-4.4/usb-increase-quirk-delay-for-usb-devices.patch new file mode 100644 index 00000000000..ebc526b5f83 --- /dev/null +++ b/queue-4.4/usb-increase-quirk-delay-for-usb-devices.patch @@ -0,0 +1,52 @@ +From b2a542bbb3081dbd64acc8929c140d196664c406 Mon Sep 17 00:00:00 2001 +From: Dmitry Fleytman +Date: Tue, 5 Sep 2017 11:40:56 +0300 +Subject: usb: Increase quirk delay for USB devices + +From: Dmitry Fleytman + +commit b2a542bbb3081dbd64acc8929c140d196664c406 upstream. + +Commit e0429362ab15 +("usb: Add device quirk for Logitech HD Pro Webcams C920 and C930e") +introduced quirk to workaround an issue with some Logitech webcams. + +The workaround is introducing delay for some USB operations. + +According to our testing, delay introduced by original commit +is not long enough and in rare cases we still see issues described +by the aforementioned commit. + +This patch increases delays introduced by original commit. +Having this patch applied we do not see those problems anymore. + +Signed-off-by: Dmitry Fleytman +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/core/config.c | 2 +- + drivers/usb/core/hub.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/usb/core/config.c ++++ b/drivers/usb/core/config.c +@@ -818,7 +818,7 @@ int usb_get_configuration(struct usb_dev + } + + if (dev->quirks & USB_QUIRK_DELAY_INIT) +- msleep(100); ++ msleep(200); + + result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, + bigbuffer, length); +--- a/drivers/usb/core/hub.c ++++ b/drivers/usb/core/hub.c +@@ -4761,7 +4761,7 @@ static void hub_port_connect(struct usb_ + goto loop; + + if (udev->quirks & USB_QUIRK_DELAY_INIT) +- msleep(1000); ++ msleep(2000); + + /* consecutive bus-powered hubs aren't reliable; they can + * violate the voltage drop budget. if the new child has diff --git a/queue-4.4/usb-uas-fix-bug-in-handling-of-alternate-settings.patch b/queue-4.4/usb-uas-fix-bug-in-handling-of-alternate-settings.patch new file mode 100644 index 00000000000..1a71d9b69f5 --- /dev/null +++ b/queue-4.4/usb-uas-fix-bug-in-handling-of-alternate-settings.patch @@ -0,0 +1,103 @@ +From 786de92b3cb26012d3d0f00ee37adf14527f35c4 Mon Sep 17 00:00:00 2001 +From: Alan Stern +Date: Fri, 22 Sep 2017 11:56:49 -0400 +Subject: USB: uas: fix bug in handling of alternate settings + +From: Alan Stern + +commit 786de92b3cb26012d3d0f00ee37adf14527f35c4 upstream. + +The uas driver has a subtle bug in the way it handles alternate +settings. The uas_find_uas_alt_setting() routine returns an +altsetting value (the bAlternateSetting number in the descriptor), but +uas_use_uas_driver() then treats that value as an index to the +intf->altsetting array, which it isn't. + +Normally this doesn't cause any problems because the various +alternate settings have bAlternateSetting values 0, 1, 2, ..., so the +value is equal to the index in the array. But this is not guaranteed, +and Andrey Konovalov used the syzkaller fuzzer with KASAN to get a +slab-out-of-bounds error by violating this assumption. + +This patch fixes the bug by making uas_find_uas_alt_setting() return a +pointer to the altsetting entry rather than either the value or the +index. Pointers are less subject to misinterpretation. + +Signed-off-by: Alan Stern +Reported-by: Andrey Konovalov +Tested-by: Andrey Konovalov +CC: Oliver Neukum +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/storage/uas-detect.h | 15 ++++++++------- + drivers/usb/storage/uas.c | 10 +++++----- + 2 files changed, 13 insertions(+), 12 deletions(-) + +--- a/drivers/usb/storage/uas-detect.h ++++ b/drivers/usb/storage/uas-detect.h +@@ -9,7 +9,8 @@ static int uas_is_interface(struct usb_h + intf->desc.bInterfaceProtocol == USB_PR_UAS); + } + +-static int uas_find_uas_alt_setting(struct usb_interface *intf) ++static struct usb_host_interface *uas_find_uas_alt_setting( ++ struct usb_interface *intf) + { + int i; + +@@ -17,10 +18,10 @@ static int uas_find_uas_alt_setting(stru + struct usb_host_interface *alt = &intf->altsetting[i]; + + if (uas_is_interface(alt)) +- return alt->desc.bAlternateSetting; ++ return alt; + } + +- return -ENODEV; ++ return NULL; + } + + static int uas_find_endpoints(struct usb_host_interface *alt, +@@ -58,14 +59,14 @@ static int uas_use_uas_driver(struct usb + struct usb_device *udev = interface_to_usbdev(intf); + struct usb_hcd *hcd = bus_to_hcd(udev->bus); + unsigned long flags = id->driver_info; +- int r, alt; +- ++ struct usb_host_interface *alt; ++ int r; + + alt = uas_find_uas_alt_setting(intf); +- if (alt < 0) ++ if (!alt) + return 0; + +- r = uas_find_endpoints(&intf->altsetting[alt], eps); ++ r = uas_find_endpoints(alt, eps); + if (r < 0) + return 0; + +--- a/drivers/usb/storage/uas.c ++++ b/drivers/usb/storage/uas.c +@@ -849,14 +849,14 @@ MODULE_DEVICE_TABLE(usb, uas_usb_ids); + static int uas_switch_interface(struct usb_device *udev, + struct usb_interface *intf) + { +- int alt; ++ struct usb_host_interface *alt; + + alt = uas_find_uas_alt_setting(intf); +- if (alt < 0) +- return alt; ++ if (!alt) ++ return -ENODEV; + +- return usb_set_interface(udev, +- intf->altsetting[0].desc.bInterfaceNumber, alt); ++ return usb_set_interface(udev, alt->desc.bInterfaceNumber, ++ alt->desc.bAlternateSetting); + } + + static int uas_configure_endpoints(struct uas_dev_info *devinfo) diff --git a/queue-4.4/xhci-fix-finding-correct-bus_state-structure-for-usb-3.1-hosts.patch b/queue-4.4/xhci-fix-finding-correct-bus_state-structure-for-usb-3.1-hosts.patch new file mode 100644 index 00000000000..cec5c79fcd0 --- /dev/null +++ b/queue-4.4/xhci-fix-finding-correct-bus_state-structure-for-usb-3.1-hosts.patch @@ -0,0 +1,34 @@ +From 5a838a13c9b4e5dd188b7a6eaeb894e9358ead0c Mon Sep 17 00:00:00 2001 +From: Mathias Nyman +Date: Mon, 18 Sep 2017 17:39:13 +0300 +Subject: xhci: fix finding correct bus_state structure for USB 3.1 hosts + +From: Mathias Nyman + +commit 5a838a13c9b4e5dd188b7a6eaeb894e9358ead0c upstream. + +xhci driver keeps a bus_state structure for each hcd (usb2 and usb3) + +The structure is picked based on hcd speed, but driver only compared +for HCD_USB3 speed, returning the wrong bus_state for HCD_USB31 hosts. + +This caused null pointer dereference errors in bus_resume function. + +Signed-off-by: Mathias Nyman +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/host/xhci.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/usb/host/xhci.h ++++ b/drivers/usb/host/xhci.h +@@ -1490,7 +1490,7 @@ struct xhci_bus_state { + + static inline unsigned int hcd_index(struct usb_hcd *hcd) + { +- if (hcd->speed == HCD_USB3) ++ if (hcd->speed >= HCD_USB3) + return 0; + else + return 1;