From: Greg Kroah-Hartman Date: Wed, 13 Feb 2019 15:01:04 +0000 (+0100) Subject: 4.4-stable patches X-Git-Tag: v4.9.157~14 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=5ec7874424f5ee8750be38651a4cc8a3183a45bd;p=thirdparty%2Fkernel%2Fstable-queue.git 4.4-stable patches added patches: hid-debug-fix-the-ring-buffer-implementation.patch nfc-nxp-nci-include-unaligned.h-instead-of-access_ok.h.patch --- diff --git a/queue-4.4/hid-debug-fix-the-ring-buffer-implementation.patch b/queue-4.4/hid-debug-fix-the-ring-buffer-implementation.patch new file mode 100644 index 00000000000..5fb90782ae0 --- /dev/null +++ b/queue-4.4/hid-debug-fix-the-ring-buffer-implementation.patch @@ -0,0 +1,274 @@ +From 13054abbaa4f1fd4e6f3b4b63439ec033b4c8035 Mon Sep 17 00:00:00 2001 +From: Vladis Dronov +Date: Tue, 29 Jan 2019 11:58:35 +0100 +Subject: HID: debug: fix the ring buffer implementation + +From: Vladis Dronov + +commit 13054abbaa4f1fd4e6f3b4b63439ec033b4c8035 upstream. + +Ring buffer implementation in hid_debug_event() and hid_debug_events_read() +is strange allowing lost or corrupted data. After commit 717adfdaf147 +("HID: debug: check length before copy_to_user()") it is possible to enter +an infinite loop in hid_debug_events_read() by providing 0 as count, this +locks up a system. Fix this by rewriting the ring buffer implementation +with kfifo and simplify the code. + +This fixes CVE-2019-3819. + +v2: fix an execution logic and add a comment +v3: use __set_current_state() instead of set_current_state() + +Backport to v4.4: some (tree-wide) patches are missing in v4.4 so +cherry-pick relevant pieces from: + * 6396bb22151 ("treewide: kzalloc() -> kcalloc()") + * a9a08845e9ac ("vfs: do bulk POLL* -> EPOLL* replacement") + * 92529623d242 ("HID: debug: improve hid_debug_event()") + * 174cd4b1e5fb ("sched/headers: Prepare to move signal wakeup & sigpending + methods from into ") + +Link: https://bugzilla.redhat.com/show_bug.cgi?id=1669187 +Cc: stable@vger.kernel.org # v4.18+ +Fixes: cd667ce24796 ("HID: use debugfs for events/reports dumping") +Fixes: 717adfdaf147 ("HID: debug: check length before copy_to_user()") +Signed-off-by: Vladis Dronov +Reviewed-by: Oleg Nesterov +Signed-off-by: Benjamin Tissoires +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/hid/hid-debug.c | 122 ++++++++++++++++++---------------------------- + include/linux/hid-debug.h | 9 +-- + 2 files changed, 52 insertions(+), 79 deletions(-) + +--- a/drivers/hid/hid-debug.c ++++ b/drivers/hid/hid-debug.c +@@ -30,6 +30,7 @@ + + #include + #include ++#include + #include + #include + #include +@@ -455,7 +456,7 @@ static char *resolv_usage_page(unsigned + char *buf = NULL; + + if (!f) { +- buf = kzalloc(sizeof(char) * HID_DEBUG_BUFSIZE, GFP_ATOMIC); ++ buf = kzalloc(HID_DEBUG_BUFSIZE, GFP_ATOMIC); + if (!buf) + return ERR_PTR(-ENOMEM); + } +@@ -659,17 +660,12 @@ EXPORT_SYMBOL_GPL(hid_dump_device); + /* enqueue string to 'events' ring buffer */ + void hid_debug_event(struct hid_device *hdev, char *buf) + { +- int i; + struct hid_debug_list *list; + unsigned long flags; + + spin_lock_irqsave(&hdev->debug_list_lock, flags); +- list_for_each_entry(list, &hdev->debug_list, node) { +- for (i = 0; i < strlen(buf); i++) +- list->hid_debug_buf[(list->tail + i) % HID_DEBUG_BUFSIZE] = +- buf[i]; +- list->tail = (list->tail + i) % HID_DEBUG_BUFSIZE; +- } ++ list_for_each_entry(list, &hdev->debug_list, node) ++ kfifo_in(&list->hid_debug_fifo, buf, strlen(buf)); + spin_unlock_irqrestore(&hdev->debug_list_lock, flags); + + wake_up_interruptible(&hdev->debug_wait); +@@ -720,8 +716,7 @@ void hid_dump_input(struct hid_device *h + hid_debug_event(hdev, buf); + + kfree(buf); +- wake_up_interruptible(&hdev->debug_wait); +- ++ wake_up_interruptible(&hdev->debug_wait); + } + EXPORT_SYMBOL_GPL(hid_dump_input); + +@@ -1086,8 +1081,8 @@ static int hid_debug_events_open(struct + goto out; + } + +- if (!(list->hid_debug_buf = kzalloc(sizeof(char) * HID_DEBUG_BUFSIZE, GFP_KERNEL))) { +- err = -ENOMEM; ++ err = kfifo_alloc(&list->hid_debug_fifo, HID_DEBUG_FIFOSIZE, GFP_KERNEL); ++ if (err) { + kfree(list); + goto out; + } +@@ -1107,77 +1102,57 @@ static ssize_t hid_debug_events_read(str + size_t count, loff_t *ppos) + { + struct hid_debug_list *list = file->private_data; +- int ret = 0, len; ++ int ret = 0, copied; + DECLARE_WAITQUEUE(wait, current); + + mutex_lock(&list->read_mutex); +- while (ret == 0) { +- if (list->head == list->tail) { +- add_wait_queue(&list->hdev->debug_wait, &wait); +- set_current_state(TASK_INTERRUPTIBLE); +- +- while (list->head == list->tail) { +- if (file->f_flags & O_NONBLOCK) { +- ret = -EAGAIN; +- break; +- } +- if (signal_pending(current)) { +- ret = -ERESTARTSYS; +- break; +- } +- +- if (!list->hdev || !list->hdev->debug) { +- ret = -EIO; +- set_current_state(TASK_RUNNING); +- goto out; +- } +- +- /* allow O_NONBLOCK from other threads */ +- mutex_unlock(&list->read_mutex); +- schedule(); +- mutex_lock(&list->read_mutex); +- set_current_state(TASK_INTERRUPTIBLE); ++ if (kfifo_is_empty(&list->hid_debug_fifo)) { ++ add_wait_queue(&list->hdev->debug_wait, &wait); ++ set_current_state(TASK_INTERRUPTIBLE); ++ ++ while (kfifo_is_empty(&list->hid_debug_fifo)) { ++ if (file->f_flags & O_NONBLOCK) { ++ ret = -EAGAIN; ++ break; + } + +- set_current_state(TASK_RUNNING); +- remove_wait_queue(&list->hdev->debug_wait, &wait); +- } +- +- if (ret) +- goto out; +- +- /* pass the ringbuffer contents to userspace */ +-copy_rest: +- if (list->tail == list->head) +- goto out; +- if (list->tail > list->head) { +- len = list->tail - list->head; +- if (len > count) +- len = count; +- +- if (copy_to_user(buffer + ret, &list->hid_debug_buf[list->head], len)) { +- ret = -EFAULT; +- goto out; ++ if (signal_pending(current)) { ++ ret = -ERESTARTSYS; ++ break; + } +- ret += len; +- list->head += len; +- } else { +- len = HID_DEBUG_BUFSIZE - list->head; +- if (len > count) +- len = count; + +- if (copy_to_user(buffer, &list->hid_debug_buf[list->head], len)) { +- ret = -EFAULT; ++ /* if list->hdev is NULL we cannot remove_wait_queue(). ++ * if list->hdev->debug is 0 then hid_debug_unregister() ++ * was already called and list->hdev is being destroyed. ++ * if we add remove_wait_queue() here we can hit a race. ++ */ ++ if (!list->hdev || !list->hdev->debug) { ++ ret = -EIO; ++ set_current_state(TASK_RUNNING); + goto out; + } +- list->head = 0; +- ret += len; +- count -= len; +- if (count > 0) +- goto copy_rest; ++ ++ /* allow O_NONBLOCK from other threads */ ++ mutex_unlock(&list->read_mutex); ++ schedule(); ++ mutex_lock(&list->read_mutex); ++ set_current_state(TASK_INTERRUPTIBLE); + } + ++ __set_current_state(TASK_RUNNING); ++ remove_wait_queue(&list->hdev->debug_wait, &wait); ++ ++ if (ret) ++ goto out; + } ++ ++ /* pass the fifo content to userspace, locking is not needed with only ++ * one concurrent reader and one concurrent writer ++ */ ++ ret = kfifo_to_user(&list->hid_debug_fifo, buffer, count, &copied); ++ if (ret) ++ goto out; ++ ret = copied; + out: + mutex_unlock(&list->read_mutex); + return ret; +@@ -1188,7 +1163,7 @@ static unsigned int hid_debug_events_pol + struct hid_debug_list *list = file->private_data; + + poll_wait(file, &list->hdev->debug_wait, wait); +- if (list->head != list->tail) ++ if (!kfifo_is_empty(&list->hid_debug_fifo)) + return POLLIN | POLLRDNORM; + if (!list->hdev->debug) + return POLLERR | POLLHUP; +@@ -1203,7 +1178,7 @@ static int hid_debug_events_release(stru + spin_lock_irqsave(&list->hdev->debug_list_lock, flags); + list_del(&list->node); + spin_unlock_irqrestore(&list->hdev->debug_list_lock, flags); +- kfree(list->hid_debug_buf); ++ kfifo_free(&list->hid_debug_fifo); + kfree(list); + + return 0; +@@ -1254,4 +1229,3 @@ void hid_debug_exit(void) + { + debugfs_remove_recursive(hid_debug_root); + } +- +--- a/include/linux/hid-debug.h ++++ b/include/linux/hid-debug.h +@@ -24,7 +24,10 @@ + + #ifdef CONFIG_DEBUG_FS + ++#include ++ + #define HID_DEBUG_BUFSIZE 512 ++#define HID_DEBUG_FIFOSIZE 512 + + void hid_dump_input(struct hid_device *, struct hid_usage *, __s32); + void hid_dump_report(struct hid_device *, int , u8 *, int); +@@ -37,11 +40,8 @@ void hid_debug_init(void); + void hid_debug_exit(void); + void hid_debug_event(struct hid_device *, char *); + +- + struct hid_debug_list { +- char *hid_debug_buf; +- int head; +- int tail; ++ DECLARE_KFIFO_PTR(hid_debug_fifo, char); + struct fasync_struct *fasync; + struct hid_device *hdev; + struct list_head node; +@@ -64,4 +64,3 @@ struct hid_debug_list { + #endif + + #endif +- diff --git a/queue-4.4/nfc-nxp-nci-include-unaligned.h-instead-of-access_ok.h.patch b/queue-4.4/nfc-nxp-nci-include-unaligned.h-instead-of-access_ok.h.patch new file mode 100644 index 00000000000..84e02bbdec8 --- /dev/null +++ b/queue-4.4/nfc-nxp-nci-include-unaligned.h-instead-of-access_ok.h.patch @@ -0,0 +1,61 @@ +From 2eee74b7e2a496dea49847c36fd09320505f45b7 Mon Sep 17 00:00:00 2001 +From: Guenter Roeck +Date: Sat, 1 Aug 2015 06:59:29 -0700 +Subject: NFC: nxp-nci: Include unaligned.h instead of access_ok.h +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Guenter Roeck + +commit 2eee74b7e2a496dea49847c36fd09320505f45b7 upstream. + +Directly including access_ok.h can result in the following compile errors +if an architecture such as ia64 does not support direct unaligned accesses. + +include/linux/unaligned/access_ok.h:7:19: error: + redefinition of 'get_unaligned_le16' +include/linux/unaligned/le_struct.h:6:19: note: + previous definition of 'get_unaligned_le16' was here +include/linux/unaligned/access_ok.h:12:19: error: + redefinition of 'get_unaligned_le32' +include/linux/unaligned/le_struct.h:11:19: note: + previous definition of 'get_unaligned_le32' was here + +Include asm/unaligned.h instead and let the architecture decide which +access functions to use. + +Cc: Clément Perrochaud +Cc: Samuel Ortiz +Signed-off-by: Guenter Roeck +Signed-off-by: Samuel Ortiz +Cc: Matthias Kaehlcke +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/nfc/nxp-nci/firmware.c | 2 +- + drivers/nfc/nxp-nci/i2c.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/nfc/nxp-nci/firmware.c ++++ b/drivers/nfc/nxp-nci/firmware.c +@@ -24,7 +24,7 @@ + #include + #include + #include +-#include ++#include + + #include "nxp-nci.h" + +--- a/drivers/nfc/nxp-nci/i2c.c ++++ b/drivers/nfc/nxp-nci/i2c.c +@@ -36,7 +36,7 @@ + #include + #include + #include +-#include ++#include + + #include + diff --git a/queue-4.4/series b/queue-4.4/series index b3a97cb8aad..ee195eb1871 100644 --- a/queue-4.4/series +++ b/queue-4.4/series @@ -108,3 +108,5 @@ mac80211-ensure-that-mgmt-tx-skbs-have-tailroom-for-encryption.patch drm-modes-prevent-division-by-zero-htotal.patch drm-vmwgfx-fix-setting-of-dma-masks.patch drm-vmwgfx-return-error-code-from-vmw_execbuf_copy_fence_user.patch +hid-debug-fix-the-ring-buffer-implementation.patch +nfc-nxp-nci-include-unaligned.h-instead-of-access_ok.h.patch