]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.4-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 13 Feb 2019 15:01:04 +0000 (16:01 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 13 Feb 2019 15:01:04 +0000 (16:01 +0100)
added patches:
hid-debug-fix-the-ring-buffer-implementation.patch
nfc-nxp-nci-include-unaligned.h-instead-of-access_ok.h.patch

queue-4.4/hid-debug-fix-the-ring-buffer-implementation.patch [new file with mode: 0644]
queue-4.4/nfc-nxp-nci-include-unaligned.h-instead-of-access_ok.h.patch [new file with mode: 0644]
queue-4.4/series

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 (file)
index 0000000..5fb9078
--- /dev/null
@@ -0,0 +1,274 @@
+From 13054abbaa4f1fd4e6f3b4b63439ec033b4c8035 Mon Sep 17 00:00:00 2001
+From: Vladis Dronov <vdronov@redhat.com>
+Date: Tue, 29 Jan 2019 11:58:35 +0100
+Subject: HID: debug: fix the ring buffer implementation
+
+From: Vladis Dronov <vdronov@redhat.com>
+
+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 <linux/sched.h> into <linux/sched/signal.h>")
+
+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 <vdronov@redhat.com>
+Reviewed-by: Oleg Nesterov <oleg@redhat.com>
+Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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 <linux/debugfs.h>
+ #include <linux/seq_file.h>
++#include <linux/kfifo.h>
+ #include <linux/sched.h>
+ #include <linux/export.h>
+ #include <linux/slab.h>
+@@ -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 <linux/kfifo.h>
++
+ #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 (file)
index 0000000..84e02bb
--- /dev/null
@@ -0,0 +1,61 @@
+From 2eee74b7e2a496dea49847c36fd09320505f45b7 Mon Sep 17 00:00:00 2001
+From: Guenter Roeck <linux@roeck-us.net>
+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 <linux@roeck-us.net>
+
+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 <clement.perrochaud@effinnov.com>
+Cc: Samuel Ortiz <sameo@linux.intel.com>
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
+Cc: Matthias Kaehlcke <mka@chromium.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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 <linux/completion.h>
+ #include <linux/firmware.h>
+ #include <linux/nfc.h>
+-#include <linux/unaligned/access_ok.h>
++#include <asm/unaligned.h>
+ #include "nxp-nci.h"
+--- a/drivers/nfc/nxp-nci/i2c.c
++++ b/drivers/nfc/nxp-nci/i2c.c
+@@ -36,7 +36,7 @@
+ #include <linux/of_gpio.h>
+ #include <linux/of_irq.h>
+ #include <linux/platform_data/nxp-nci.h>
+-#include <linux/unaligned/access_ok.h>
++#include <asm/unaligned.h>
+ #include <net/nfc/nfc.h>
index b3a97cb8aadea20c5b0f1eb7e572192aff62340f..ee195eb1871e25cccca70c195c28ae7122120b7c 100644 (file)
@@ -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