summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-09-04 09:25:38 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2026-09-04 09:25:38 -0700
commit986c24e0fe44f844b44d365b71ce831947f50298 (patch)
tree15818d60b81c25a4fb3019bb9d132b53401508a1 /drivers
parent36ec09e2637c3430acb8ec8fc3c303d9f1a24837 (diff)
parent9cdc7e6dc7a99ad7311ad5e7c145f2b9ce4e24b0 (diff)
Merge tag 'hid-for-linus-2026090401' of git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid
Pull HID fixes from Benjamin Tissoires: - hid-hyperv build fixes on certain configs (Jiri Kosina) - HID-BPF fix and selftests now that the bpf verifier is more restrictive (Benjamin Tissoires) - Some AI detected fixes for OOB, errors and validation (Ibrahim Hashimov, Shen Yongchao, Wei Jie Law) - various device fixes (Dave Carey and Vadim Klishko) * tag 'hid-for-linus-2026090401' of git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid: HID: bpf: serialize device reference release in struct_ops destroy path HID: rmi: fix OOB access with undersized RMI reports selftests/hid: prepare test_rdesc_fixup_get_data_overflow for the new verifier selftests/hid: Add a test to ensure we can write fields in hid_device HID: bpf: mark struct hid_device as safe BPF pointer HID: wacom: validate report length in wacom_intuos_pro2_bt_irq HID: multitouch: Fix stale MT slots when contact count drops to zero HID: i2c-hid: Add a quirk for a Cirque I2C device. HID: hyperv: make pointer arithmetics understandable for FORTIFY_SOURCE HID: hyperv: fix build breakage with certain configs
Diffstat (limited to 'drivers')
-rw-r--r--drivers/hid/Kconfig2
-rw-r--r--drivers/hid/bpf/hid_bpf_struct_ops.c23
-rw-r--r--drivers/hid/hid-hyperv.c4
-rw-r--r--drivers/hid/hid-ids.h1
-rw-r--r--drivers/hid/hid-multitouch.c19
-rw-r--r--drivers/hid/hid-rmi.c46
-rw-r--r--drivers/hid/i2c-hid/i2c-hid-core.c2
-rw-r--r--drivers/hid/wacom_wac.c13
8 files changed, 89 insertions, 21 deletions
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index aa7fa11a0197..a81bf51cbcf1 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -1253,7 +1253,7 @@ config HID_HYPERV_MOUSE
config HID_HYPERV_MOUSE_KUNIT_TEST
bool "KUnit tests for Hyper-V mouse driver" if !KUNIT_ALL_TESTS
- depends on KUNIT && HID_HYPERV_MOUSE
+ depends on KUNIT && (HID_HYPERV_MOUSE = KUNIT || KUNIT = y)
default KUNIT_ALL_TESTS
help
Builds unit tests for the Hyper-V synthetic HID driver.
diff --git a/drivers/hid/bpf/hid_bpf_struct_ops.c b/drivers/hid/bpf/hid_bpf_struct_ops.c
index 702c22fae136..c90b68956cb3 100644
--- a/drivers/hid/bpf/hid_bpf_struct_ops.c
+++ b/drivers/hid/bpf/hid_bpf_struct_ops.c
@@ -62,6 +62,10 @@ struct hid_bpf_offset_write_range {
u32 end;
};
+struct hid_bpf_ctx__safe_trusted {
+ struct hid_device *hid;
+};
+
static int hid_bpf_ops_btf_struct_access(struct bpf_verifier_log *log,
const struct bpf_reg_state *reg,
int off, int size)
@@ -86,6 +90,8 @@ static int hid_bpf_ops_btf_struct_access(struct bpf_verifier_log *log,
const char *cur = NULL;
int i;
+ BTF_TYPE_EMIT(struct hid_bpf_ctx__safe_trusted);
+
t = btf_type_by_id(reg->btf, reg->btf_id);
for (i = 0; i < ARRAY_SIZE(write_ranges); i++) {
@@ -250,6 +256,11 @@ static void hid_bpf_unreg(void *kdata, struct bpf_link *link)
mutex_lock(&hdev->bpf.prog_list_lock);
+ if (!ops->hdev) {
+ mutex_unlock(&hdev->bpf.prog_list_lock);
+ return;
+ }
+
list_del_rcu(&ops->list);
synchronize_srcu(&hdev->bpf.srcu);
ops->hdev = NULL;
@@ -310,13 +321,17 @@ static struct bpf_struct_ops bpf_hid_bpf_ops = {
void __hid_bpf_ops_destroy_device(struct hid_device *hdev)
{
struct hid_bpf_ops *e;
+ int count = 0;
- rcu_read_lock();
- list_for_each_entry_rcu(e, &hdev->bpf.prog_list, list) {
- hid_put_device(hdev);
+ mutex_lock(&hdev->bpf.prog_list_lock);
+ list_for_each_entry(e, &hdev->bpf.prog_list, list) {
e->hdev = NULL;
+ count++;
}
- rcu_read_unlock();
+ mutex_unlock(&hdev->bpf.prog_list_lock);
+
+ while (count--)
+ hid_put_device(hdev);
}
static int __init hid_bpf_struct_ops_init(void)
diff --git a/drivers/hid/hid-hyperv.c b/drivers/hid/hid-hyperv.c
index 6579bd19da13..cfc061dbdd24 100644
--- a/drivers/hid/hid-hyperv.c
+++ b/drivers/hid/hid-hyperv.c
@@ -687,7 +687,7 @@ static void mousevsc_device_info_valid_descriptor(struct kunit *test)
info->hid_descriptor.bLength = sizeof(struct hid_descriptor);
info->hid_descriptor.rpt_desc.wDescriptorLength = cpu_to_le16(4);
- report = ((u8 *)&info->hid_descriptor) + info->hid_descriptor.bLength;
+ report = (u8 *)(info + 1);
memset(report, 0x42, 4);
mousevsc_on_receive_device_info(input_dev, info, sizeof(*info) + 4);
@@ -713,7 +713,7 @@ static void mousevsc_device_info_report_desc_oob(struct kunit *test)
info->hid_descriptor.bLength = sizeof(struct hid_descriptor);
info->hid_descriptor.rpt_desc.wDescriptorLength = cpu_to_le16(64);
- report = ((u8 *)&info->hid_descriptor) + info->hid_descriptor.bLength;
+ report = (u8 *)(info + 1);
memset(report, 0x42, 8);
mousevsc_on_receive_device_info(input_dev, info, sizeof(*info) + 8);
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 341bf587863b..b3aca5aa9176 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -338,6 +338,7 @@
#define I2C_VENDOR_ID_CIRQUE 0x0488
#define I2C_PRODUCT_ID_CIRQUE_1063 0x1063
+#define I2C_PRODUCT_ID_CIRQUE_D0C1 0xD0C1
#define USB_VENDOR_ID_CJTOUCH 0x24b8
#define USB_DEVICE_ID_CJTOUCH_MULTI_TOUCH_0020 0x0020
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
index 2c41bacab1ca..451c7324e6a0 100644
--- a/drivers/hid/hid-multitouch.c
+++ b/drivers/hid/hid-multitouch.c
@@ -1321,21 +1321,18 @@ static void mt_touch_report(struct hid_device *hid,
* Includes multi-packet support where subsequent
* packets are sent with zero contactcount.
*/
- if (contact_count >= 0) {
+ if (contact_count > 0)
+ app->num_expected = contact_count;
+ else if (app->num_received == 0 && app->prev_scantime != scantime) {
/*
+ * New multi-report frame:
+ *
* For Win8 PTPs the first packet (td->num_received == 0) may
* have a contactcount of 0 if there only is a button event.
- * We double check that this is not a continuation packet
- * of a possible multi-packet frame be checking that the
- * timestamp has changed.
+ *
+ * Some other devices use a sentinel frame with 0 to release all contacts
*/
- if ((app->quirks & MT_QUIRK_WIN8_PTP_BUTTONS) &&
- app->num_received == 0 &&
- app->prev_scantime != scantime)
- app->num_expected = contact_count;
- /* A non 0 contact count always indicates a first packet */
- else if (contact_count)
- app->num_expected = contact_count;
+ app->num_expected = 0;
}
app->prev_scantime = scantime;
diff --git a/drivers/hid/hid-rmi.c b/drivers/hid/hid-rmi.c
index 2bd781f1e0f5..ecc19387f6b0 100644
--- a/drivers/hid/hid-rmi.c
+++ b/drivers/hid/hid-rmi.c
@@ -235,7 +235,23 @@ static int rmi_hid_read_block(struct rmi_transport_dev *xport, u16 addr,
break;
}
- read_input_count = data->readReport[1];
+ read_input_count = min_t(int, data->readReport[1],
+ data->input_report_size - 2);
+ if (!read_input_count) {
+ /*
+ * A zero length reply advances neither
+ * bytes_read nor bytes_needed, and because a
+ * reply did arrive the wait above does not
+ * time out either, so a device answering 0
+ * forever would spin here indefinitely with
+ * page_mutex held.
+ */
+ hid_warn(hdev, "%s: zero-length read reply\n",
+ __func__);
+ clear_bit(RMI_READ_DATA_PENDING, &data->flags);
+ ret = -EIO;
+ break;
+ }
memcpy(buf + bytes_read, &data->readReport[2],
min(read_input_count, bytes_needed));
@@ -271,6 +287,11 @@ static int rmi_hid_write_block(struct rmi_transport_dev *xport, u16 addr,
goto exit;
}
+ if (len + 4 > data->output_report_size) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
data->writeReport[0] = RMI_WRITE_REPORT_ID;
data->writeReport[1] = len;
data->writeReport[2] = addr & 0xFF;
@@ -666,8 +687,16 @@ static int rmi_probe(struct hid_device *hdev, const struct hid_device_id *id)
return ret;
}
- if (id->driver_data)
- data->device_flags = id->driver_data;
+ /*
+ * RMI_DEVICE can only mean "this probe validated the RMI reports and
+ * allocated writeReport": every bail-out to start below skips that
+ * allocation, and device_flags left carrying RMI_DEVICE from
+ * driver_data would send rmi_input_configured() into rmi_set_page()
+ * with writeReport still NULL. A bind through the new_id sysfs
+ * attribute can supply driver_data with the bit set, so do not let
+ * driver_data grant it.
+ */
+ data->device_flags = id->driver_data & ~RMI_DEVICE;
/*
* Check for the RMI specific report ids. If they are misisng
@@ -696,6 +725,17 @@ static int rmi_probe(struct hid_device *hdev, const struct hid_device_id *id)
data->output_report_size = hid_report_len(output_report);
+ /*
+ * The write reports built by this driver occupy 6 bytes and the read
+ * handshake looks at the first 3 bytes of an input report, so refuse
+ * to drive a device whose reports cannot hold them.
+ */
+ if (data->output_report_size < 6 || data->input_report_size < 3) {
+ hid_err(hdev, "rmi reports too small (out=%u in=%u)\n",
+ data->output_report_size, data->input_report_size);
+ goto start;
+ }
+
data->device_flags |= RMI_DEVICE;
alloc_size = data->output_report_size + data->input_report_size;
diff --git a/drivers/hid/i2c-hid/i2c-hid-core.c b/drivers/hid/i2c-hid/i2c-hid-core.c
index 0e725a0f0abe..0ff07fdab442 100644
--- a/drivers/hid/i2c-hid/i2c-hid-core.c
+++ b/drivers/hid/i2c-hid/i2c-hid-core.c
@@ -136,6 +136,8 @@ static const struct i2c_hid_quirks {
I2C_HID_QUIRK_BAD_INPUT_SIZE },
{ I2C_VENDOR_ID_CIRQUE, I2C_PRODUCT_ID_CIRQUE_1063,
I2C_HID_QUIRK_NO_SLEEP_ON_SUSPEND },
+ { I2C_VENDOR_ID_CIRQUE, I2C_PRODUCT_ID_CIRQUE_D0C1,
+ I2C_HID_QUIRK_NO_IRQ_AFTER_RESET },
/*
* Without additional power on command, at least some QTEC devices send garbage
*/
diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
index a29bf051ada7..8feb8027be95 100644
--- a/drivers/hid/wacom_wac.c
+++ b/drivers/hid/wacom_wac.c
@@ -1550,6 +1550,19 @@ static int wacom_intuos_pro2_bt_irq(struct wacom_wac *wacom, size_t len)
return 0;
}
+ if (wacom->features.type == INTUOSP2_BT ||
+ wacom->features.type == INTUOSP2S_BT) {
+ if (len < 286) {
+ dev_warn(wacom->pen_input->dev.parent,
+ "Pro2 BT report too short: %zu bytes\n", len);
+ return 0;
+ }
+ } else if (len < 46) {
+ dev_warn(wacom->pen_input->dev.parent,
+ "Pro2 BT report too short: %zu bytes\n", len);
+ return 0;
+ }
+
wacom_intuos_pro2_bt_pen(wacom);
if (wacom->features.type == INTUOSP2_BT ||
wacom->features.type == INTUOSP2S_BT) {