From 393c1b87ab5795f5dec2e1d390fa3a0a13478f12 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Sun, 5 Feb 2017 11:26:24 +0100 Subject: [PATCH] 4.4-stable patches added patches: firmware-fix-null-pointer-dereference-in-__fw_load_abort.patch usb-gadget-f_fs-assorted-buffer-overflow-checks.patch usb-serial-option-add-device-id-for-hp-lt2523-novatel-e371.patch x86-irq-make-irq-activate-operations-symmetric.patch --- ...inter-dereference-in-__fw_load_abort.patch | 152 ++++++++++++++++++ queue-4.4/series | 4 + ...f_fs-assorted-buffer-overflow-checks.patch | 66 ++++++++ ...device-id-for-hp-lt2523-novatel-e371.patch | 32 ++++ ...ke-irq-activate-operations-symmetric.patch | 58 +++++++ 5 files changed, 312 insertions(+) create mode 100644 queue-4.4/firmware-fix-null-pointer-dereference-in-__fw_load_abort.patch create mode 100644 queue-4.4/usb-gadget-f_fs-assorted-buffer-overflow-checks.patch create mode 100644 queue-4.4/usb-serial-option-add-device-id-for-hp-lt2523-novatel-e371.patch create mode 100644 queue-4.4/x86-irq-make-irq-activate-operations-symmetric.patch diff --git a/queue-4.4/firmware-fix-null-pointer-dereference-in-__fw_load_abort.patch b/queue-4.4/firmware-fix-null-pointer-dereference-in-__fw_load_abort.patch new file mode 100644 index 00000000000..575efd2a8d9 --- /dev/null +++ b/queue-4.4/firmware-fix-null-pointer-dereference-in-__fw_load_abort.patch @@ -0,0 +1,152 @@ +From 191e885a2e130e639bb0c8ee350d7047294f2ce6 Mon Sep 17 00:00:00 2001 +From: "Luis R. Rodriguez" +Date: Wed, 25 Jan 2017 10:31:52 -0800 +Subject: firmware: fix NULL pointer dereference in __fw_load_abort() + +From: Luis R. Rodriguez + +commit 191e885a2e130e639bb0c8ee350d7047294f2ce6 upstream. + +Since commit 5d47ec02c37ea6 ("firmware: Correct handling of +fw_state_wait() return value") fw_load_abort() could be called twice and +lead us to a kernel crash. This happens only when the firmware fallback +mechanism (regular or custom) is used. The fallback mechanism exposes a +sysfs interface for userspace to upload a file and notify the kernel +when the file is loaded and ready, or to cancel an upload by echo'ing -1 +into on the loading file: + +echo -n "-1" > /sys/$DEVPATH/loading + +This will call fw_load_abort(). Some distributions actually have a udev +rule in place to *always* immediately cancel all firmware fallback +mechanism requests (Debian), they have: + + $ cat /lib/udev/rules.d/50-firmware.rules + # stub for immediately telling the kernel that userspace firmware loading + # failed; necessary to avoid long timeouts with CONFIG_FW_LOADER_USER_HELPER=y + SUBSYSTEM=="firmware", ACTION=="add", ATTR{loading}="-1 + +Distributions with this udev rule would run into this crash only if the +fallback mechanism is used. Since most distributions disable by default +using the fallback mechanism (CONFIG_FW_LOADER_USER_HELPER_FALLBACK), +this would typicaly mean only 2 drivers which *require* the fallback +mechanism could typically incur a crash: drivers/firmware/dell_rbu.c and +the drivers/leds/leds-lp55xx-common.c driver. Distributions enabling +CONFIG_FW_LOADER_USER_HELPER_FALLBACK by default are obviously more +exposed to this crash. + +The crash happens because after commit 5b029624948d ("firmware: do not +use fw_lock for fw_state protection") and subsequent fix commit +5d47ec02c37ea6 ("firmware: Correct handling of fw_state_wait() return +value") a race can happen between this cancelation and the firmware +fw_state_wait_timeout() being woken up after a state change with which +fw_load_abort() as that calls swake_up(). Upon error +fw_state_wait_timeout() will also again call fw_load_abort() and trigger +a null reference. + +At first glance we could just fix this with a !buf check on +fw_load_abort() before accessing buf->fw_st, however there is a logical +issue in having a state machine used for the fallback mechanism and +preventing access from it once we abort as its inside the buf +(buf->fw_st). + +The firmware_class.c code is setting the buf to NULL to annotate an +abort has occurred. Replace this mechanism by simply using the state +check instead. All the other code in place already uses similar checks +for aborting as well so no further changes are needed. + +An oops can be reproduced with the new fw_fallback.sh fallback mechanism +cancellation test. Either cancelling the fallback mechanism or the +custom fallback mechanism triggers a crash. + +mcgrof@piggy ~/linux-next/tools/testing/selftests/firmware +(git::20170111-fw-fixes)$ sudo ./fw_fallback.sh + +./fw_fallback.sh: timeout works +./fw_fallback.sh: firmware comparison works +./fw_fallback.sh: fallback mechanism works + +[ this then sits here when it is trying the cancellation test ] + +Kernel log: + +test_firmware: loading 'nope-test-firmware.bin' +misc test_firmware: Direct firmware load for nope-test-firmware.bin failed with error -2 +misc test_firmware: Falling back to user helper +BUG: unable to handle kernel NULL pointer dereference at 0000000000000038 +IP: _request_firmware+0xa27/0xad0 +PGD 0 + +Oops: 0000 [#1] SMP +Modules linked in: test_firmware(E) ... etc ... +CPU: 1 PID: 1396 Comm: fw_fallback.sh Tainted: G W E 4.10.0-rc3-next-20170111+ #30 +Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.10.1-0-g8891697-prebuilt.qemu-project.org 04/01/2014 +task: ffff9740b27f4340 task.stack: ffffbb15c0bc8000 +RIP: 0010:_request_firmware+0xa27/0xad0 +RSP: 0018:ffffbb15c0bcbd10 EFLAGS: 00010246 +RAX: 00000000fffffffe RBX: ffff9740afe5aa80 RCX: 0000000000000000 +RDX: ffff9740b27f4340 RSI: 0000000000000283 RDI: 0000000000000000 +RBP: ffffbb15c0bcbd90 R08: ffffbb15c0bcbcd8 R09: 0000000000000000 +R10: 0000000894a0d4b1 R11: 000000000000008c R12: ffffffffc0312480 +R13: 0000000000000005 R14: ffff9740b1c32400 R15: 00000000000003e8 +FS: 00007f8604422700(0000) GS:ffff9740bfc80000(0000) knlGS:0000000000000000 +CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +CR2: 0000000000000038 CR3: 000000012164c000 CR4: 00000000000006e0 +Call Trace: + request_firmware+0x37/0x50 + trigger_request_store+0x79/0xd0 [test_firmware] + dev_attr_store+0x18/0x30 + sysfs_kf_write+0x37/0x40 + kernfs_fop_write+0x110/0x1a0 + __vfs_write+0x37/0x160 + ? _cond_resched+0x1a/0x50 + vfs_write+0xb5/0x1a0 + SyS_write+0x55/0xc0 + ? trace_do_page_fault+0x37/0xd0 + entry_SYSCALL_64_fastpath+0x1e/0xad +RIP: 0033:0x7f8603f49620 +RSP: 002b:00007fff6287b788 EFLAGS: 00000246 ORIG_RAX: 0000000000000001 +RAX: ffffffffffffffda RBX: 000055c307b110a0 RCX: 00007f8603f49620 +RDX: 0000000000000016 RSI: 000055c3084d8a90 RDI: 0000000000000001 +RBP: 0000000000000016 R08: 000000000000c0ff R09: 000055c3084d6336 +R10: 000055c307b108b0 R11: 0000000000000246 R12: 000055c307b13c80 +R13: 000055c3084d6320 R14: 0000000000000000 R15: 00007fff6287b950 +Code: 9f 64 84 e8 9c 61 fe ff b8 f4 ff ff ff e9 6b f9 ff +ff 48 c7 c7 40 6b 8d 84 89 45 a8 e8 43 84 18 00 49 8b be 00 03 00 00 8b +45 a8 <83> 7f 38 02 74 08 e8 6e ec ff ff 8b 45 a8 49 c7 86 00 03 00 00 +RIP: _request_firmware+0xa27/0xad0 RSP: ffffbb15c0bcbd10 +CR2: 0000000000000038 +---[ end trace 6d94ac339c133e6f ]--- + +Fixes: 5d47ec02c37e ("firmware: Correct handling of fw_state_wait() return value") +Reported-and-Tested-by: Jakub Kicinski +Reported-and-Tested-by: Patrick Bruenn +Reported-by: Chris Wilson +Signed-off-by: Luis R. Rodriguez +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/base/firmware_class.c | 5 +---- + 1 file changed, 1 insertion(+), 4 deletions(-) + +--- a/drivers/base/firmware_class.c ++++ b/drivers/base/firmware_class.c +@@ -495,9 +495,6 @@ static void fw_load_abort(struct firmwar + struct firmware_buf *buf = fw_priv->buf; + + __fw_load_abort(buf); +- +- /* avoid user action after loading abort */ +- fw_priv->buf = NULL; + } + + #define is_fw_load_aborted(buf) \ +@@ -651,7 +648,7 @@ static ssize_t firmware_loading_store(st + + mutex_lock(&fw_lock); + fw_buf = fw_priv->buf; +- if (!fw_buf) ++ if (fw_state_is_aborted(&fw_buf->fw_st)) + goto out; + + switch (loading) { diff --git a/queue-4.4/series b/queue-4.4/series index e852b92f935..4ffccbad7d1 100644 --- a/queue-4.4/series +++ b/queue-4.4/series @@ -24,3 +24,7 @@ kvm-x86-do-not-save-guest-unsupported-xsave-state.patch usb-serial-qcserial-add-dell-dw5570-qdl.patch usb-serial-pl2303-add-aten-device-id.patch usb-add-quirk-for-worlde-easykey.25-midi-keyboard.patch +usb-gadget-f_fs-assorted-buffer-overflow-checks.patch +usb-serial-option-add-device-id-for-hp-lt2523-novatel-e371.patch +x86-irq-make-irq-activate-operations-symmetric.patch +firmware-fix-null-pointer-dereference-in-__fw_load_abort.patch diff --git a/queue-4.4/usb-gadget-f_fs-assorted-buffer-overflow-checks.patch b/queue-4.4/usb-gadget-f_fs-assorted-buffer-overflow-checks.patch new file mode 100644 index 00000000000..e461b9fd7b0 --- /dev/null +++ b/queue-4.4/usb-gadget-f_fs-assorted-buffer-overflow-checks.patch @@ -0,0 +1,66 @@ +From 83e526f2a2fa4b2e82b6bd3ddbb26b70acfa8947 Mon Sep 17 00:00:00 2001 +From: Vincent Pelletier +Date: Wed, 18 Jan 2017 00:57:44 +0000 +Subject: usb: gadget: f_fs: Assorted buffer overflow checks. + +From: Vincent Pelletier + +commit 83e526f2a2fa4b2e82b6bd3ddbb26b70acfa8947 upstream. + +OS descriptor head, when flagged as provided, is accessed without +checking if it fits in provided buffer. Verify length before access. +Also, there are other places where buffer length it checked +after accessing offsets which are potentially past the end. Check +buffer length before as well to fail cleanly. + +Signed-off-by: Vincent Pelletier +Acked-by: Felipe Balbi +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/gadget/function/f_fs.c | 13 ++++++++++++- + 1 file changed, 12 insertions(+), 1 deletion(-) + +--- a/drivers/usb/gadget/function/f_fs.c ++++ b/drivers/usb/gadget/function/f_fs.c +@@ -2079,6 +2079,8 @@ static int __ffs_data_do_os_desc(enum ff + if (len < sizeof(*d) || h->interface >= ffs->interfaces_count) + return -EINVAL; + length = le32_to_cpu(d->dwSize); ++ if (len < length) ++ return -EINVAL; + type = le32_to_cpu(d->dwPropertyDataType); + if (type < USB_EXT_PROP_UNICODE || + type > USB_EXT_PROP_UNICODE_MULTI) { +@@ -2087,6 +2089,11 @@ static int __ffs_data_do_os_desc(enum ff + return -EINVAL; + } + pnl = le16_to_cpu(d->wPropertyNameLength); ++ if (length < 14 + pnl) { ++ pr_vdebug("invalid os descriptor length: %d pnl:%d (descriptor %d)\n", ++ length, pnl, type); ++ return -EINVAL; ++ } + pdl = le32_to_cpu(*(u32 *)((u8 *)data + 10 + pnl)); + if (length != 14 + pnl + pdl) { + pr_vdebug("invalid os descriptor length: %d pnl:%d pdl:%d (descriptor %d)\n", +@@ -2171,6 +2178,9 @@ static int __ffs_data_got_descs(struct f + } + } + if (flags & (1 << i)) { ++ if (len < 4) { ++ goto error; ++ } + os_descs_count = get_unaligned_le32(data); + data += 4; + len -= 4; +@@ -2243,7 +2253,8 @@ static int __ffs_data_got_strings(struct + + ENTER(); + +- if (unlikely(get_unaligned_le32(data) != FUNCTIONFS_STRINGS_MAGIC || ++ if (unlikely(len < 16 || ++ get_unaligned_le32(data) != FUNCTIONFS_STRINGS_MAGIC || + get_unaligned_le32(data + 4) != len)) + goto error; + str_count = get_unaligned_le32(data + 8); diff --git a/queue-4.4/usb-serial-option-add-device-id-for-hp-lt2523-novatel-e371.patch b/queue-4.4/usb-serial-option-add-device-id-for-hp-lt2523-novatel-e371.patch new file mode 100644 index 00000000000..c54ac67fd42 --- /dev/null +++ b/queue-4.4/usb-serial-option-add-device-id-for-hp-lt2523-novatel-e371.patch @@ -0,0 +1,32 @@ +From 5d03a2fd2292e71936c4235885c35ccc3c94695b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= +Date: Tue, 24 Jan 2017 10:31:18 +0100 +Subject: USB: serial: option: add device ID for HP lt2523 (Novatel E371) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Bjørn Mork + +commit 5d03a2fd2292e71936c4235885c35ccc3c94695b upstream. + +Yet another laptop vendor rebranded Novatel E371. + +Signed-off-by: Bjørn Mork +Signed-off-by: Johan Hovold +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/serial/option.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/usb/serial/option.c ++++ b/drivers/usb/serial/option.c +@@ -2007,6 +2007,7 @@ static const struct usb_device_id option + { USB_DEVICE_AND_INTERFACE_INFO(WETELECOM_VENDOR_ID, WETELECOM_PRODUCT_WMD200, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(WETELECOM_VENDOR_ID, WETELECOM_PRODUCT_6802, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(WETELECOM_VENDOR_ID, WETELECOM_PRODUCT_WMD300, 0xff, 0xff, 0xff) }, ++ { USB_DEVICE_AND_INTERFACE_INFO(0x03f0, 0x421d, 0xff, 0xff, 0xff) }, /* HP lt2523 (Novatel E371) */ + { } /* Terminating entry */ + }; + MODULE_DEVICE_TABLE(usb, option_ids); diff --git a/queue-4.4/x86-irq-make-irq-activate-operations-symmetric.patch b/queue-4.4/x86-irq-make-irq-activate-operations-symmetric.patch new file mode 100644 index 00000000000..2404fe5bf50 --- /dev/null +++ b/queue-4.4/x86-irq-make-irq-activate-operations-symmetric.patch @@ -0,0 +1,58 @@ +From aaaec6fc755447a1d056765b11b24d8ff2b81366 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Tue, 31 Jan 2017 19:03:21 +0100 +Subject: x86/irq: Make irq activate operations symmetric + +From: Thomas Gleixner + +commit aaaec6fc755447a1d056765b11b24d8ff2b81366 upstream. + +The recent commit which prevents double activation of interrupts unearthed +interesting code in x86. The code (ab)uses irq_domain_activate_irq() to +reconfigure an already activated interrupt. That trips over the prevention +code now. + +Fix it by deactivating the interrupt before activating the new configuration. + +Fixes: 08d85f3ea99f1 "irqdomain: Avoid activating interrupts more than once" +Reported-and-tested-by: Mike Galbraith +Reported-and-tested-by: Borislav Petkov +Signed-off-by: Thomas Gleixner +Cc: Andrey Ryabinin +Cc: Marc Zyngier +Link: http://lkml.kernel.org/r/alpine.DEB.2.20.1701311901580.3457@nanos +Signed-off-by: Greg Kroah-Hartman + +--- + arch/x86/kernel/apic/io_apic.c | 2 ++ + arch/x86/kernel/hpet.c | 1 + + 2 files changed, 3 insertions(+) + +--- a/arch/x86/kernel/apic/io_apic.c ++++ b/arch/x86/kernel/apic/io_apic.c +@@ -2117,6 +2117,7 @@ static inline void __init check_timer(vo + if (idx != -1 && irq_trigger(idx)) + unmask_ioapic_irq(irq_get_chip_data(0)); + } ++ irq_domain_deactivate_irq(irq_data); + irq_domain_activate_irq(irq_data); + if (timer_irq_works()) { + if (disable_timer_pin_1 > 0) +@@ -2138,6 +2139,7 @@ static inline void __init check_timer(vo + * legacy devices should be connected to IO APIC #0 + */ + replace_pin_at_irq_node(data, node, apic1, pin1, apic2, pin2); ++ irq_domain_deactivate_irq(irq_data); + irq_domain_activate_irq(irq_data); + legacy_pic->unmask(0); + if (timer_irq_works()) { +--- a/arch/x86/kernel/hpet.c ++++ b/arch/x86/kernel/hpet.c +@@ -351,6 +351,7 @@ static int hpet_resume(struct clock_even + } else { + struct hpet_dev *hdev = EVT_TO_HPET_DEV(evt); + ++ irq_domain_deactivate_irq(irq_get_irq_data(hdev->irq)); + irq_domain_activate_irq(irq_get_irq_data(hdev->irq)); + disable_irq(hdev->irq); + irq_set_affinity(hdev->irq, cpumask_of(hdev->cpu)); -- 2.47.3