[PATCH 4/9] HID: core: Validate GET_REPORT report ID centrally

From: Dmitry Torokhov

Date: Mon Oct 12 2026 - 23:42:46 EST


Several transport drivers and device drivers individually check whether
a successful report retrieval response returns the expected report ID.

Centralize this check in the core HID raw request path so that all
report retrieval requests verify that the start of the returned buffer
matches the requested report ID. Introduce a new quirk,
HID_QUIRK_IGNORE_REPORT_ID_MISMATCH, for hardware with buggy firmware
(such as the ASUS ROG Flow Z13 touchpad) that returns mismatched report
IDs on feature fetches.

Assisted-by: LLM
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@xxxxxxxxx>
---
drivers/hid/hid-core.c | 11 ++++++++++-
drivers/hid/hid-quirks.c | 2 ++
include/linux/hid.h | 2 ++
3 files changed, 14 insertions(+), 1 deletion(-)

diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 3a9bd56dbf85..cd099a420b9b 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -2565,8 +2565,17 @@ int __hid_hw_raw_request(struct hid_device *hdev,
if (ret)
return ret;

- return hdev->ll_driver->raw_request(hdev, reportnum, buf, len,
+ ret = hdev->ll_driver->raw_request(hdev, reportnum, buf, len,
rtype, reqtype);
+ if (ret > 0 && reqtype == HID_REQ_GET_REPORT &&
+ !(hdev->quirks & HID_QUIRK_IGNORE_REPORT_ID_MISMATCH) &&
+ buf[0] != reportnum) {
+ hid_warn(hdev, "mismatched report ID %u (expected %u)\n",
+ buf[0], reportnum);
+ return -EINVAL;
+ }
+
+ return ret;
}

/**
diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c
index 96a36c5ba04f..0ea592d1c9e7 100644
--- a/drivers/hid/hid-quirks.c
+++ b/drivers/hid/hid-quirks.c
@@ -37,6 +37,8 @@ static const struct hid_device_id hid_quirks[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_ALPS, USB_DEVICE_ID_IBM_GAMEPAD), HID_QUIRK_BADPAD },
{ HID_USB_DEVICE(USB_VENDOR_ID_AMI, USB_DEVICE_ID_AMI_VIRT_KEYBOARD_AND_MOUSE), HID_QUIRK_ALWAYS_POLL },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_REVB_ANSI), HID_QUIRK_ALWAYS_POLL },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_ROG_Z13_FOLIO),
+ HID_QUIRK_IGNORE_REPORT_ID_MISMATCH },
{ HID_USB_DEVICE(USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM), HID_QUIRK_NOGET },
{ HID_USB_DEVICE(USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVMC), HID_QUIRK_NOGET },
{ HID_USB_DEVICE(USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVM), HID_QUIRK_NOGET },
diff --git a/include/linux/hid.h b/include/linux/hid.h
index 8d17b741638c..8f5e485b1351 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -388,6 +388,7 @@ struct hid_item {
* | @HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE:
* | @HID_QUIRK_IGNORE_SPECIAL_DRIVER
* | @HID_QUIRK_POWER_ON_AFTER_BACKLIGHT
+ * | @HID_QUIRK_IGNORE_REPORT_ID_MISMATCH:
* | @HID_QUIRK_FULLSPEED_INTERVAL:
* | @HID_QUIRK_NO_INIT_REPORTS:
* | @HID_QUIRK_NO_IGNORE:
@@ -416,6 +417,7 @@ struct hid_item {
#define HID_QUIRK_NOINVERT BIT(21)
#define HID_QUIRK_IGNORE_SPECIAL_DRIVER BIT(22)
#define HID_QUIRK_POWER_ON_AFTER_BACKLIGHT BIT(23)
+#define HID_QUIRK_IGNORE_REPORT_ID_MISMATCH BIT(24)
#define HID_QUIRK_FULLSPEED_INTERVAL BIT(28)
#define HID_QUIRK_NO_INIT_REPORTS BIT(29)
#define HID_QUIRK_NO_IGNORE BIT(30)

--
2.56.0.385.gd3acb90ef8-goog