Commit 092150a2 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid

Pull HID fixes from Jiri Kosina:

 - spectrev1 pattern fix in hiddev from Gustavo A. R. Silva

 - bounds check fix for hid-debug from Daniel Rosenberg

 - regression fix for HID autobinding from Benjamin Tissoires

 - removal of excessive logging from i2c-hid driver from Jason Andryuk

 - fix specific to 2nd generation of Wacom Intuos devices from Jason
   Gerecke

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid:
  HID: hiddev: fix potential Spectre v1
  HID: i2c-hid: Fix "incomplete report" noise
  HID: wacom: Correct touch maximum XY of 2nd-gen Intuos
  HID: debug: check length before copy_to_user()
  HID: core: allow concurrent registration of drivers
parents bdf33113 4f65245f
...@@ -1952,6 +1952,8 @@ static int hid_device_probe(struct device *dev) ...@@ -1952,6 +1952,8 @@ static int hid_device_probe(struct device *dev)
} }
hdev->io_started = false; hdev->io_started = false;
clear_bit(ffs(HID_STAT_REPROBED), &hdev->status);
if (!hdev->driver) { if (!hdev->driver) {
id = hid_match_device(hdev, hdrv); id = hid_match_device(hdev, hdrv);
if (id == NULL) { if (id == NULL) {
...@@ -2215,7 +2217,8 @@ static int __hid_bus_reprobe_drivers(struct device *dev, void *data) ...@@ -2215,7 +2217,8 @@ static int __hid_bus_reprobe_drivers(struct device *dev, void *data)
struct hid_device *hdev = to_hid_device(dev); struct hid_device *hdev = to_hid_device(dev);
if (hdev->driver == hdrv && if (hdev->driver == hdrv &&
!hdrv->match(hdev, hid_ignore_special_drivers)) !hdrv->match(hdev, hid_ignore_special_drivers) &&
!test_and_set_bit(ffs(HID_STAT_REPROBED), &hdev->status))
return device_reprobe(dev); return device_reprobe(dev);
return 0; return 0;
......
...@@ -1154,6 +1154,8 @@ static ssize_t hid_debug_events_read(struct file *file, char __user *buffer, ...@@ -1154,6 +1154,8 @@ static ssize_t hid_debug_events_read(struct file *file, char __user *buffer,
goto out; goto out;
if (list->tail > list->head) { if (list->tail > list->head) {
len = 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)) { if (copy_to_user(buffer + ret, &list->hid_debug_buf[list->head], len)) {
ret = -EFAULT; ret = -EFAULT;
...@@ -1163,6 +1165,8 @@ static ssize_t hid_debug_events_read(struct file *file, char __user *buffer, ...@@ -1163,6 +1165,8 @@ static ssize_t hid_debug_events_read(struct file *file, char __user *buffer,
list->head += len; list->head += len;
} else { } else {
len = HID_DEBUG_BUFSIZE - list->head; len = HID_DEBUG_BUFSIZE - list->head;
if (len > count)
len = count;
if (copy_to_user(buffer, &list->hid_debug_buf[list->head], len)) { if (copy_to_user(buffer, &list->hid_debug_buf[list->head], len)) {
ret = -EFAULT; ret = -EFAULT;
...@@ -1170,7 +1174,9 @@ static ssize_t hid_debug_events_read(struct file *file, char __user *buffer, ...@@ -1170,7 +1174,9 @@ static ssize_t hid_debug_events_read(struct file *file, char __user *buffer,
} }
list->head = 0; list->head = 0;
ret += len; ret += len;
goto copy_rest; count -= len;
if (count > 0)
goto copy_rest;
} }
} }
......
...@@ -484,7 +484,7 @@ static void i2c_hid_get_input(struct i2c_hid *ihid) ...@@ -484,7 +484,7 @@ static void i2c_hid_get_input(struct i2c_hid *ihid)
return; return;
} }
if ((ret_size > size) || (ret_size <= 2)) { if ((ret_size > size) || (ret_size < 2)) {
dev_err(&ihid->client->dev, "%s: incomplete report (%d/%d)\n", dev_err(&ihid->client->dev, "%s: incomplete report (%d/%d)\n",
__func__, size, ret_size); __func__, size, ret_size);
return; return;
......
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#include <linux/hiddev.h> #include <linux/hiddev.h>
#include <linux/compat.h> #include <linux/compat.h>
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
#include <linux/nospec.h>
#include "usbhid.h" #include "usbhid.h"
#ifdef CONFIG_USB_DYNAMIC_MINORS #ifdef CONFIG_USB_DYNAMIC_MINORS
...@@ -469,10 +470,14 @@ static noinline int hiddev_ioctl_usage(struct hiddev *hiddev, unsigned int cmd, ...@@ -469,10 +470,14 @@ static noinline int hiddev_ioctl_usage(struct hiddev *hiddev, unsigned int cmd,
if (uref->field_index >= report->maxfield) if (uref->field_index >= report->maxfield)
goto inval; goto inval;
uref->field_index = array_index_nospec(uref->field_index,
report->maxfield);
field = report->field[uref->field_index]; field = report->field[uref->field_index];
if (uref->usage_index >= field->maxusage) if (uref->usage_index >= field->maxusage)
goto inval; goto inval;
uref->usage_index = array_index_nospec(uref->usage_index,
field->maxusage);
uref->usage_code = field->usage[uref->usage_index].hid; uref->usage_code = field->usage[uref->usage_index].hid;
...@@ -499,6 +504,8 @@ static noinline int hiddev_ioctl_usage(struct hiddev *hiddev, unsigned int cmd, ...@@ -499,6 +504,8 @@ static noinline int hiddev_ioctl_usage(struct hiddev *hiddev, unsigned int cmd,
if (uref->field_index >= report->maxfield) if (uref->field_index >= report->maxfield)
goto inval; goto inval;
uref->field_index = array_index_nospec(uref->field_index,
report->maxfield);
field = report->field[uref->field_index]; field = report->field[uref->field_index];
...@@ -753,6 +760,8 @@ static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ...@@ -753,6 +760,8 @@ static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
if (finfo.field_index >= report->maxfield) if (finfo.field_index >= report->maxfield)
break; break;
finfo.field_index = array_index_nospec(finfo.field_index,
report->maxfield);
field = report->field[finfo.field_index]; field = report->field[finfo.field_index];
memset(&finfo, 0, sizeof(finfo)); memset(&finfo, 0, sizeof(finfo));
...@@ -797,6 +806,8 @@ static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ...@@ -797,6 +806,8 @@ static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
if (cinfo.index >= hid->maxcollection) if (cinfo.index >= hid->maxcollection)
break; break;
cinfo.index = array_index_nospec(cinfo.index,
hid->maxcollection);
cinfo.type = hid->collection[cinfo.index].type; cinfo.type = hid->collection[cinfo.index].type;
cinfo.usage = hid->collection[cinfo.index].usage; cinfo.usage = hid->collection[cinfo.index].usage;
......
...@@ -3365,8 +3365,14 @@ void wacom_setup_device_quirks(struct wacom *wacom) ...@@ -3365,8 +3365,14 @@ void wacom_setup_device_quirks(struct wacom *wacom)
if (features->type >= INTUOSHT && features->type <= BAMBOO_PT) if (features->type >= INTUOSHT && features->type <= BAMBOO_PT)
features->device_type |= WACOM_DEVICETYPE_PAD; features->device_type |= WACOM_DEVICETYPE_PAD;
features->x_max = 4096; if (features->type == INTUOSHT2) {
features->y_max = 4096; features->x_max = features->x_max / 10;
features->y_max = features->y_max / 10;
}
else {
features->x_max = 4096;
features->y_max = 4096;
}
} }
else if (features->pktlen == WACOM_PKGLEN_BBTOUCH) { else if (features->pktlen == WACOM_PKGLEN_BBTOUCH) {
features->device_type |= WACOM_DEVICETYPE_PAD; features->device_type |= WACOM_DEVICETYPE_PAD;
......
...@@ -511,6 +511,7 @@ struct hid_output_fifo { ...@@ -511,6 +511,7 @@ struct hid_output_fifo {
#define HID_STAT_ADDED BIT(0) #define HID_STAT_ADDED BIT(0)
#define HID_STAT_PARSED BIT(1) #define HID_STAT_PARSED BIT(1)
#define HID_STAT_DUP_DETECTED BIT(2) #define HID_STAT_DUP_DETECTED BIT(2)
#define HID_STAT_REPROBED BIT(3)
struct hid_input { struct hid_input {
struct list_head list; struct list_head list;
...@@ -579,7 +580,7 @@ struct hid_device { /* device report descriptor */ ...@@ -579,7 +580,7 @@ struct hid_device { /* device report descriptor */
bool battery_avoid_query; bool battery_avoid_query;
#endif #endif
unsigned int status; /* see STAT flags above */ unsigned long status; /* see STAT flags above */
unsigned claimed; /* Claimed by hidinput, hiddev? */ unsigned claimed; /* Claimed by hidinput, hiddev? */
unsigned quirks; /* Various quirks the device can pull on us */ unsigned quirks; /* Various quirks the device can pull on us */
bool io_started; /* If IO has started */ bool io_started; /* If IO has started */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment