From 2e78b21864dd6e21b76160753ea632b5e758fdbd Mon Sep 17 00:00:00 2001 From: Myeonghun Pak Date: Fri, 24 Apr 2026 22:21:31 +0900 Subject: [PATCH 1/7] HID: u2fzero: free allocated URB on probe errors u2fzero_fill_in_urb() allocates dev->urb with usb_alloc_urb(), but u2fzero_probe() ignored its return value and only freed the URB from u2fzero_remove(). If LED or hwrng registration fails after the URB allocation, probe returns an error and the driver core does not call .remove(), leaking the URB. A failed URB setup was also allowed to continue probing with an unusable device. Check the URB setup result and add the missing probe-error unwind so the URB is freed before returning from later errors. Signed-off-by: Myeonghun Pak Signed-off-by: Benjamin Tissoires --- drivers/hid/hid-u2fzero.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/drivers/hid/hid-u2fzero.c b/drivers/hid/hid-u2fzero.c index 744a91e6e78c..82404b6e2d25 100644 --- a/drivers/hid/hid-u2fzero.c +++ b/drivers/hid/hid-u2fzero.c @@ -341,29 +341,33 @@ static int u2fzero_probe(struct hid_device *hdev, if (ret) return ret; - u2fzero_fill_in_urb(dev); + ret = u2fzero_fill_in_urb(dev); + if (ret) + goto err_hid_hw_stop; dev->present = true; minor = ((struct hidraw *) hdev->hidraw)->minor; ret = u2fzero_init_led(dev, minor); - if (ret) { - hid_hw_stop(hdev); - return ret; - } + if (ret) + goto err_free_urb; hid_info(hdev, "%s LED initialised\n", hw_configs[dev->hw_revision].name); ret = u2fzero_init_hwrng(dev, minor); - if (ret) { - hid_hw_stop(hdev); - return ret; - } + if (ret) + goto err_free_urb; hid_info(hdev, "%s RNG initialised\n", hw_configs[dev->hw_revision].name); return 0; + +err_free_urb: + usb_free_urb(dev->urb); +err_hid_hw_stop: + hid_hw_stop(hdev); + return ret; } static void u2fzero_remove(struct hid_device *hdev) From dd2147375a8fe7c5bc3f1f1b1d3a9567c26faefa Mon Sep 17 00:00:00 2001 From: Liu Kai Date: Thu, 7 May 2026 16:32:04 +0800 Subject: [PATCH 2/7] HID: remove duplicate hid_warn_ratelimited definition The hid_warn_ratelimited macro is defined twice in include/linux/hid.h: - first one added by commit 4051ead99888 ("HID: rate-limit hid_warn to prevent log flooding") - second one added by commit 1d64624243af ("HID: core: Add printk_ratelimited variants to hid_warn() etc")). The second definition is correctly grouped with other ratelimited macros. Remove the duplicate definition. Fixes: 1d64624243af ("HID: core: Add printk_ratelimited variants to hid_warn() etc") Signed-off-by: Liu Kai [bentiss: edited commit message] Signed-off-by: Benjamin Tissoires --- include/linux/hid.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/linux/hid.h b/include/linux/hid.h index bfb9859f391e..47dc0bc89fa4 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -1316,8 +1316,6 @@ void hid_quirks_exit(__u16 bus); dev_notice(&(hid)->dev, fmt, ##__VA_ARGS__) #define hid_warn(hid, fmt, ...) \ dev_warn(&(hid)->dev, fmt, ##__VA_ARGS__) -#define hid_warn_ratelimited(hid, fmt, ...) \ - dev_warn_ratelimited(&(hid)->dev, fmt, ##__VA_ARGS__) #define hid_info(hid, fmt, ...) \ dev_info(&(hid)->dev, fmt, ##__VA_ARGS__) #define hid_dbg(hid, fmt, ...) \ From 07466fc91c55532edcfb5c6a7ccd2ea52728d6bd Mon Sep 17 00:00:00 2001 From: hlleng Date: Tue, 12 May 2026 09:57:37 +0800 Subject: [PATCH 3/7] HID: quirks: Add ALWAYS_POLL quirk for SIGMACHIP USB mouse The SIGMACHIP USB mouse with VID/PID 1c4f:0034 can disconnect and re-enumerate repeatedly after it has been enumerated if its interrupt endpoint is not continuously polled. This was observed with the device reporting itself as "SIGMACHIP Usb Mouse". Keeping the input event device open avoids the disconnects. Add HID_QUIRK_ALWAYS_POLL for this device so the HID core keeps polling it even when there is no userspace input consumer. Cc: stable@vger.kernel.org Signed-off-by: hlleng Signed-off-by: Benjamin Tissoires --- drivers/hid/hid-ids.h | 1 + drivers/hid/hid-quirks.c | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 4657d96fb083..426ff78c1c03 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -1284,6 +1284,7 @@ #define USB_VENDOR_ID_SIGMA_MICRO 0x1c4f #define USB_DEVICE_ID_SIGMA_MICRO_KEYBOARD 0x0002 +#define USB_DEVICE_ID_SIGMA_MICRO_USB_MOUSE 0x0034 #define USB_DEVICE_ID_SIGMA_MICRO_KEYBOARD2 0x0059 #define USB_VENDOR_ID_SIGMATEL 0x066F diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c index 512049963978..57d8efdd9b89 100644 --- a/drivers/hid/hid-quirks.c +++ b/drivers/hid/hid-quirks.c @@ -187,6 +187,7 @@ static const struct hid_device_id hid_quirks[] = { { HID_USB_DEVICE(USB_VENDOR_ID_SEMICO, USB_DEVICE_ID_SEMICO_USB_KEYKOARD), HID_QUIRK_NO_INIT_REPORTS }, { HID_USB_DEVICE(USB_VENDOR_ID_SENNHEISER, USB_DEVICE_ID_SENNHEISER_BTD500USB), HID_QUIRK_NOGET }, { HID_USB_DEVICE(USB_VENDOR_ID_SIGMA_MICRO, USB_DEVICE_ID_SIGMA_MICRO_KEYBOARD), HID_QUIRK_NO_INIT_REPORTS }, + { HID_USB_DEVICE(USB_VENDOR_ID_SIGMA_MICRO, USB_DEVICE_ID_SIGMA_MICRO_USB_MOUSE), HID_QUIRK_ALWAYS_POLL }, { HID_USB_DEVICE(USB_VENDOR_ID_SIGMATEL, USB_DEVICE_ID_SIGMATEL_STMP3780), HID_QUIRK_NOGET }, { HID_USB_DEVICE(USB_VENDOR_ID_SIS_TOUCH, USB_DEVICE_ID_SIS1030_TOUCH), HID_QUIRK_NOGET }, { HID_USB_DEVICE(USB_VENDOR_ID_SIS_TOUCH, USB_DEVICE_ID_SIS817_TOUCH), HID_QUIRK_NOGET }, From c7ee0b73c8c4dfb7eafa49aaef5247890862a948 Mon Sep 17 00:00:00 2001 From: Kean Date: Thu, 14 May 2026 20:58:38 +0800 Subject: [PATCH 4/7] HID: lenovo: Fix buffer over-read and unaligned access in X12 Tab raw_event handler In lenovo_raw_event(), the X12 Tab keyboard handler reads a 4-byte little-endian value from the raw HID report buffer but: 1. The size guard is size >= 3, while the access reads 4 bytes. A malformed 3-byte report with ID 0x03 would over-read the buffer by one byte. 2. Casting u8 *data directly to __le32 * can trigger unaligned access faults on architectures like ARM, MIPS, and SPARC, because HID input buffers carry no alignment guarantee. (e.g. uhid payloads start at offset 6 in struct uhid_event, giving only 2-byte alignment.) Fix both by tightening the size check to >= 4 and replacing the open-coded cast + le32_to_cpu() with get_unaligned_le32(), which handles the LE-to-CPU conversion safely regardless of alignment. Link: https://sashiko.dev/#/message/20260512044911.99B6DC2BCB0%40smtp.kernel.org Assisted-by: CLAUDE:claude-4-sonnet Signed-off-by: Kean Signed-off-by: Benjamin Tissoires --- drivers/hid/hid-lenovo.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/hid/hid-lenovo.c b/drivers/hid/hid-lenovo.c index a6b73e03c16b..c11957ae8b77 100644 --- a/drivers/hid/hid-lenovo.c +++ b/drivers/hid/hid-lenovo.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include "hid-ids.h" @@ -793,8 +794,8 @@ static int lenovo_raw_event(struct hid_device *hdev, */ if (unlikely((hdev->product == USB_DEVICE_ID_LENOVO_X12_TAB || hdev->product == USB_DEVICE_ID_LENOVO_X12_TAB2) - && size >= 3 && report->id == 0x03)) - return lenovo_raw_event_TP_X12_tab(hdev, le32_to_cpu(*(__le32 *)data)); + && size >= 4 && report->id == 0x03)) + return lenovo_raw_event_TP_X12_tab(hdev, get_unaligned_le32(data)); return 0; } From 2ee7e632405b022319f42c01635eb6fbbd86414a Mon Sep 17 00:00:00 2001 From: Louis Clinckx Date: Fri, 15 May 2026 14:57:39 +0000 Subject: [PATCH 5/7] HID: lenovo-go: reject non-USB transports in probe These drivers only match HID_USB_DEVICE() entries and assume the underlying bus is USB. Make that explicit at probe by rejecting any non-USB hdev, following the pattern used by other HID drivers. Signed-off-by: Louis Clinckx Reviewed-by: Derek J. Clark Tested-by: Derek J. Clark Signed-off-by: Benjamin Tissoires --- drivers/hid/hid-lenovo-go-s.c | 3 +++ drivers/hid/hid-lenovo-go.c | 3 +++ 2 files changed, 6 insertions(+) diff --git a/drivers/hid/hid-lenovo-go-s.c b/drivers/hid/hid-lenovo-go-s.c index ff1782a75191..0444d84498bd 100644 --- a/drivers/hid/hid-lenovo-go-s.c +++ b/drivers/hid/hid-lenovo-go-s.c @@ -1461,6 +1461,9 @@ static int hid_gos_probe(struct hid_device *hdev, { int ret, ep; + if (!hid_is_usb(hdev)) + return -EINVAL; + ret = hid_parse(hdev); if (ret) { hid_err(hdev, "Parse failed\n"); diff --git a/drivers/hid/hid-lenovo-go.c b/drivers/hid/hid-lenovo-go.c index d4d26c783356..3fa1fe83f7e5 100644 --- a/drivers/hid/hid-lenovo-go.c +++ b/drivers/hid/hid-lenovo-go.c @@ -2419,6 +2419,9 @@ static int hid_go_probe(struct hid_device *hdev, const struct hid_device_id *id) { int ret, ep; + if (!hid_is_usb(hdev)) + return -EINVAL; + hdev->quirks |= HID_QUIRK_INPUT_PER_APP | HID_QUIRK_MULTI_INPUT; ret = hid_parse(hdev); From da7f96a68c39de9eb1c351a261e7fbf716375c91 Mon Sep 17 00:00:00 2001 From: Louis Clinckx Date: Fri, 15 May 2026 14:57:40 +0000 Subject: [PATCH 6/7] HID: lenovo-go: drop dead NULL check on to_usb_interface() to_usb_interface() is a container_of_const() macro: it performs pointer arithmetic and never returns NULL. The if (!intf) and if (intf) tests in get_endpoint_address() can never fire. Remove them in both drivers. No functional change. Suggested-by: Derek J. Clark Signed-off-by: Louis Clinckx Reviewed-by: Derek J. Clark Tested-by: Derek J. Clark Signed-off-by: Benjamin Tissoires --- drivers/hid/hid-lenovo-go-s.c | 8 +++----- drivers/hid/hid-lenovo-go.c | 3 --- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/drivers/hid/hid-lenovo-go-s.c b/drivers/hid/hid-lenovo-go-s.c index 0444d84498bd..a72f7f748cb5 100644 --- a/drivers/hid/hid-lenovo-go-s.c +++ b/drivers/hid/hid-lenovo-go-s.c @@ -382,11 +382,9 @@ static int get_endpoint_address(struct hid_device *hdev) struct usb_interface *intf = to_usb_interface(hdev->dev.parent); struct usb_host_endpoint *ep; - if (intf) { - ep = intf->cur_altsetting->endpoint; - if (ep) - return ep->desc.bEndpointAddress; - } + ep = intf->cur_altsetting->endpoint; + if (ep) + return ep->desc.bEndpointAddress; return -ENODEV; } diff --git a/drivers/hid/hid-lenovo-go.c b/drivers/hid/hid-lenovo-go.c index 3fa1fe83f7e5..e0c9d5ec9451 100644 --- a/drivers/hid/hid-lenovo-go.c +++ b/drivers/hid/hid-lenovo-go.c @@ -641,9 +641,6 @@ static int get_endpoint_address(struct hid_device *hdev) struct usb_interface *intf = to_usb_interface(hdev->dev.parent); struct usb_host_endpoint *ep; - if (!intf) - return -ENODEV; - ep = intf->cur_altsetting->endpoint; if (!ep) return -ENODEV; From c0a8899e02ddebd51e2589835182c239c2e224ae Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Wed, 27 May 2026 17:05:26 +0100 Subject: [PATCH 7/7] HID: wacom: Fix OOB write in wacom_hid_set_device_mode() wacom_hid_set_device_mode() currently assumes that the HID_DG_INPUTMODE usage is always located in the first field (field[0]) of the feature report. However, a device can specify HID_DG_INPUTMODE in a different field. If HID_DG_INPUTMODE is in a field other than the first one and the first field has a report_count smaller than the usage_index of HID_DG_INPUTMODE, this leads to an out-of-bounds write to r->field[0]->value. Fix this by storing the field index of HID_DG_INPUTMODE in 'struct hid_data' during feature mapping. In wacom_hid_set_device_mode(), use this stored field index to access the correct field and add bounds checks to ensure both the field index and the value index are within valid ranges before writing. Cc: stable@vger.kernel.org Fixes: 5ae6e89f7409 ("HID: wacom: implement the finger part of the HID generic handling") Tested-by: Ping Cheng Reviewed-by: Ping Cheng Signed-off-by: Lee Jones Signed-off-by: Benjamin Tissoires --- drivers/hid/wacom_sys.c | 13 ++++++++++--- drivers/hid/wacom_wac.h | 1 + 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c index a32320b351e3..2220168bf116 100644 --- a/drivers/hid/wacom_sys.c +++ b/drivers/hid/wacom_sys.c @@ -356,6 +356,7 @@ static void wacom_feature_mapping(struct hid_device *hdev, hid_data->inputmode = field->report->id; hid_data->inputmode_index = usage->usage_index; + hid_data->inputmode_field_index = field->index; break; case HID_UP_DIGITIZER: @@ -571,9 +572,14 @@ static int wacom_hid_set_device_mode(struct hid_device *hdev) re = &(hdev->report_enum[HID_FEATURE_REPORT]); r = re->report_id_hash[hid_data->inputmode]; - if (r) { - r->field[0]->value[hid_data->inputmode_index] = 2; - hid_hw_request(hdev, r, HID_REQ_SET_REPORT); + if (r && hid_data->inputmode_field_index >= 0 && + hid_data->inputmode_field_index < r->maxfield) { + struct hid_field *field = r->field[hid_data->inputmode_field_index]; + + if (field && hid_data->inputmode_index < field->report_count) { + field->value[hid_data->inputmode_index] = 2; + hid_hw_request(hdev, r, HID_REQ_SET_REPORT); + } } return 0; } @@ -2846,6 +2852,7 @@ static int wacom_probe(struct hid_device *hdev, return -ENODEV; wacom_wac->hid_data.inputmode = -1; + wacom_wac->hid_data.inputmode_field_index = -1; wacom_wac->mode_report = -1; if (hid_is_usb(hdev)) { diff --git a/drivers/hid/wacom_wac.h b/drivers/hid/wacom_wac.h index d4f7d8ca1e7e..126bec6e5c0c 100644 --- a/drivers/hid/wacom_wac.h +++ b/drivers/hid/wacom_wac.h @@ -295,6 +295,7 @@ struct wacom_shared { struct hid_data { __s16 inputmode; /* InputMode HID feature, -1 if non-existent */ __s16 inputmode_index; /* InputMode HID feature index in the report */ + __s16 inputmode_field_index; /* InputMode HID feature field index in the report */ bool sense_state; bool inrange_state; bool eraser;