Commit 2653e3fe authored by Linus Torvalds's avatar Linus Torvalds

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

Pull HID fixes from Benjamin Tissoires:

 - fix potential out of bound write of zeroes in HID core with a
   specially crafted uhid device (Lee Jones)

 - fix potential use-after-free in work function in intel-ish-hid (Reka
   Norman)

 - selftests config fixes (Benjamin Tissoires)

 - few device small fixes and support

* tag 'for-linus-2023030901' of git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid:
  HID: intel-ish-hid: ipc: Fix potential use-after-free in work function
  HID: logitech-hidpp: Add support for Logitech MX Master 3S mouse
  HID: cp2112: Fix driver not registering GPIO IRQ chip as threaded
  selftest: hid: fix hid_bpf not set in config
  HID: uhid: Over-ride the default maximum data buffer value with our own
  HID: core: Provide new max_buffer_size attribute to over-ride the default
parents c70e9b8e 8ae2f2b0
...@@ -256,6 +256,7 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign ...@@ -256,6 +256,7 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign
{ {
struct hid_report *report; struct hid_report *report;
struct hid_field *field; struct hid_field *field;
unsigned int max_buffer_size = HID_MAX_BUFFER_SIZE;
unsigned int usages; unsigned int usages;
unsigned int offset; unsigned int offset;
unsigned int i; unsigned int i;
...@@ -286,8 +287,11 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign ...@@ -286,8 +287,11 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign
offset = report->size; offset = report->size;
report->size += parser->global.report_size * parser->global.report_count; report->size += parser->global.report_size * parser->global.report_count;
if (parser->device->ll_driver->max_buffer_size)
max_buffer_size = parser->device->ll_driver->max_buffer_size;
/* Total size check: Allow for possible report index byte */ /* Total size check: Allow for possible report index byte */
if (report->size > (HID_MAX_BUFFER_SIZE - 1) << 3) { if (report->size > (max_buffer_size - 1) << 3) {
hid_err(parser->device, "report is too long\n"); hid_err(parser->device, "report is too long\n");
return -1; return -1;
} }
...@@ -1963,6 +1967,7 @@ int hid_report_raw_event(struct hid_device *hid, enum hid_report_type type, u8 * ...@@ -1963,6 +1967,7 @@ int hid_report_raw_event(struct hid_device *hid, enum hid_report_type type, u8 *
struct hid_report_enum *report_enum = hid->report_enum + type; struct hid_report_enum *report_enum = hid->report_enum + type;
struct hid_report *report; struct hid_report *report;
struct hid_driver *hdrv; struct hid_driver *hdrv;
int max_buffer_size = HID_MAX_BUFFER_SIZE;
u32 rsize, csize = size; u32 rsize, csize = size;
u8 *cdata = data; u8 *cdata = data;
int ret = 0; int ret = 0;
...@@ -1978,10 +1983,13 @@ int hid_report_raw_event(struct hid_device *hid, enum hid_report_type type, u8 * ...@@ -1978,10 +1983,13 @@ int hid_report_raw_event(struct hid_device *hid, enum hid_report_type type, u8 *
rsize = hid_compute_report_size(report); rsize = hid_compute_report_size(report);
if (report_enum->numbered && rsize >= HID_MAX_BUFFER_SIZE) if (hid->ll_driver->max_buffer_size)
rsize = HID_MAX_BUFFER_SIZE - 1; max_buffer_size = hid->ll_driver->max_buffer_size;
else if (rsize > HID_MAX_BUFFER_SIZE)
rsize = HID_MAX_BUFFER_SIZE; if (report_enum->numbered && rsize >= max_buffer_size)
rsize = max_buffer_size - 1;
else if (rsize > max_buffer_size)
rsize = max_buffer_size;
if (csize < rsize) { if (csize < rsize) {
dbg_hid("report %d is too short, (%d < %d)\n", report->id, dbg_hid("report %d is too short, (%d < %d)\n", report->id,
...@@ -2396,7 +2404,12 @@ int hid_hw_raw_request(struct hid_device *hdev, ...@@ -2396,7 +2404,12 @@ int hid_hw_raw_request(struct hid_device *hdev,
unsigned char reportnum, __u8 *buf, unsigned char reportnum, __u8 *buf,
size_t len, enum hid_report_type rtype, enum hid_class_request reqtype) size_t len, enum hid_report_type rtype, enum hid_class_request reqtype)
{ {
if (len < 1 || len > HID_MAX_BUFFER_SIZE || !buf) unsigned int max_buffer_size = HID_MAX_BUFFER_SIZE;
if (hdev->ll_driver->max_buffer_size)
max_buffer_size = hdev->ll_driver->max_buffer_size;
if (len < 1 || len > max_buffer_size || !buf)
return -EINVAL; return -EINVAL;
return hdev->ll_driver->raw_request(hdev, reportnum, buf, len, return hdev->ll_driver->raw_request(hdev, reportnum, buf, len,
...@@ -2415,7 +2428,12 @@ EXPORT_SYMBOL_GPL(hid_hw_raw_request); ...@@ -2415,7 +2428,12 @@ EXPORT_SYMBOL_GPL(hid_hw_raw_request);
*/ */
int hid_hw_output_report(struct hid_device *hdev, __u8 *buf, size_t len) int hid_hw_output_report(struct hid_device *hdev, __u8 *buf, size_t len)
{ {
if (len < 1 || len > HID_MAX_BUFFER_SIZE || !buf) unsigned int max_buffer_size = HID_MAX_BUFFER_SIZE;
if (hdev->ll_driver->max_buffer_size)
max_buffer_size = hdev->ll_driver->max_buffer_size;
if (len < 1 || len > max_buffer_size || !buf)
return -EINVAL; return -EINVAL;
if (hdev->ll_driver->output_report) if (hdev->ll_driver->output_report)
......
...@@ -1354,6 +1354,7 @@ static int cp2112_probe(struct hid_device *hdev, const struct hid_device_id *id) ...@@ -1354,6 +1354,7 @@ static int cp2112_probe(struct hid_device *hdev, const struct hid_device_id *id)
girq->parents = NULL; girq->parents = NULL;
girq->default_type = IRQ_TYPE_NONE; girq->default_type = IRQ_TYPE_NONE;
girq->handler = handle_simple_irq; girq->handler = handle_simple_irq;
girq->threaded = true;
ret = gpiochip_add_data(&dev->gc, dev); ret = gpiochip_add_data(&dev->gc, dev);
if (ret < 0) { if (ret < 0) {
......
...@@ -4399,6 +4399,8 @@ static const struct hid_device_id hidpp_devices[] = { ...@@ -4399,6 +4399,8 @@ static const struct hid_device_id hidpp_devices[] = {
HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb02a) }, HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb02a) },
{ /* MX Master 3 mouse over Bluetooth */ { /* MX Master 3 mouse over Bluetooth */
HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb023) }, HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb023) },
{ /* MX Master 3S mouse over Bluetooth */
HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb034) },
{} {}
}; };
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
* Copyright (c) 2014-2016, Intel Corporation. * Copyright (c) 2014-2016, Intel Corporation.
*/ */
#include <linux/devm-helpers.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/delay.h> #include <linux/delay.h>
...@@ -621,7 +622,6 @@ static void recv_ipc(struct ishtp_device *dev, uint32_t doorbell_val) ...@@ -621,7 +622,6 @@ static void recv_ipc(struct ishtp_device *dev, uint32_t doorbell_val)
case MNG_RESET_NOTIFY: case MNG_RESET_NOTIFY:
if (!ishtp_dev) { if (!ishtp_dev) {
ishtp_dev = dev; ishtp_dev = dev;
INIT_WORK(&fw_reset_work, fw_reset_work_fn);
} }
schedule_work(&fw_reset_work); schedule_work(&fw_reset_work);
break; break;
...@@ -940,6 +940,7 @@ struct ishtp_device *ish_dev_init(struct pci_dev *pdev) ...@@ -940,6 +940,7 @@ struct ishtp_device *ish_dev_init(struct pci_dev *pdev)
{ {
struct ishtp_device *dev; struct ishtp_device *dev;
int i; int i;
int ret;
dev = devm_kzalloc(&pdev->dev, dev = devm_kzalloc(&pdev->dev,
sizeof(struct ishtp_device) + sizeof(struct ish_hw), sizeof(struct ishtp_device) + sizeof(struct ish_hw),
...@@ -975,6 +976,12 @@ struct ishtp_device *ish_dev_init(struct pci_dev *pdev) ...@@ -975,6 +976,12 @@ struct ishtp_device *ish_dev_init(struct pci_dev *pdev)
list_add_tail(&tx_buf->link, &dev->wr_free_list); list_add_tail(&tx_buf->link, &dev->wr_free_list);
} }
ret = devm_work_autocancel(&pdev->dev, &fw_reset_work, fw_reset_work_fn);
if (ret) {
dev_err(dev->devc, "Failed to initialise FW reset work\n");
return NULL;
}
dev->ops = &ish_hw_ops; dev->ops = &ish_hw_ops;
dev->devc = &pdev->dev; dev->devc = &pdev->dev;
dev->mtu = IPC_PAYLOAD_SIZE - sizeof(struct ishtp_msg_hdr); dev->mtu = IPC_PAYLOAD_SIZE - sizeof(struct ishtp_msg_hdr);
......
...@@ -395,6 +395,7 @@ static const struct hid_ll_driver uhid_hid_driver = { ...@@ -395,6 +395,7 @@ static const struct hid_ll_driver uhid_hid_driver = {
.parse = uhid_hid_parse, .parse = uhid_hid_parse,
.raw_request = uhid_hid_raw_request, .raw_request = uhid_hid_raw_request,
.output_report = uhid_hid_output_report, .output_report = uhid_hid_output_report,
.max_buffer_size = UHID_DATA_MAX,
}; };
#ifdef CONFIG_COMPAT #ifdef CONFIG_COMPAT
......
...@@ -834,6 +834,7 @@ struct hid_driver { ...@@ -834,6 +834,7 @@ struct hid_driver {
* @output_report: send output report to device * @output_report: send output report to device
* @idle: send idle request to device * @idle: send idle request to device
* @may_wakeup: return if device may act as a wakeup source during system-suspend * @may_wakeup: return if device may act as a wakeup source during system-suspend
* @max_buffer_size: over-ride maximum data buffer size (default: HID_MAX_BUFFER_SIZE)
*/ */
struct hid_ll_driver { struct hid_ll_driver {
int (*start)(struct hid_device *hdev); int (*start)(struct hid_device *hdev);
...@@ -859,6 +860,8 @@ struct hid_ll_driver { ...@@ -859,6 +860,8 @@ struct hid_ll_driver {
int (*idle)(struct hid_device *hdev, int report, int idle, int reqtype); int (*idle)(struct hid_device *hdev, int report, int idle, int reqtype);
bool (*may_wakeup)(struct hid_device *hdev); bool (*may_wakeup)(struct hid_device *hdev);
unsigned int max_buffer_size;
}; };
extern bool hid_is_usb(const struct hid_device *hdev); extern bool hid_is_usb(const struct hid_device *hdev);
......
...@@ -17,5 +17,6 @@ CONFIG_FTRACE_SYSCALLS=y ...@@ -17,5 +17,6 @@ CONFIG_FTRACE_SYSCALLS=y
CONFIG_FUNCTION_TRACER=y CONFIG_FUNCTION_TRACER=y
CONFIG_HIDRAW=y CONFIG_HIDRAW=y
CONFIG_HID=y CONFIG_HID=y
CONFIG_HID_BPF=y
CONFIG_INPUT_EVDEV=y CONFIG_INPUT_EVDEV=y
CONFIG_UHID=y CONFIG_UHID=y
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