Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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

Pull HID fixes from Benjamin Tissoires:

- one warning cleanup introduced in the last PR (Andy Shevchenko)

- a nasty syzbot buffer underflow fix co-debugged with Alan Stern
(Benjamin Tissoires)

* tag 'hid-for-linus-2025071501' of git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid:
selftests/hid: add a test case for the recent syzbot underflow
HID: core: do not bypass hid_hw_raw_request
HID: core: ensure __hid_request reserves the report ID as the first byte
HID: core: ensure the allocated report buffer can contain the reserved report ID
HID: debug: Remove duplicate entry (BTN_WHEEL)

+86 -7
+15 -6
drivers/hid/hid-core.c
··· 1883 1883 /* 1884 1884 * 7 extra bytes are necessary to achieve proper functionality 1885 1885 * of implement() working on 8 byte chunks 1886 + * 1 extra byte for the report ID if it is null (not used) so 1887 + * we can reserve that extra byte in the first position of the buffer 1888 + * when sending it to .raw_request() 1886 1889 */ 1887 1890 1888 - u32 len = hid_report_len(report) + 7; 1891 + u32 len = hid_report_len(report) + 7 + (report->id == 0); 1889 1892 1890 1893 return kzalloc(len, flags); 1891 1894 } ··· 1976 1973 int __hid_request(struct hid_device *hid, struct hid_report *report, 1977 1974 enum hid_class_request reqtype) 1978 1975 { 1979 - char *buf; 1976 + char *buf, *data_buf; 1980 1977 int ret; 1981 1978 u32 len; 1982 1979 ··· 1984 1981 if (!buf) 1985 1982 return -ENOMEM; 1986 1983 1984 + data_buf = buf; 1987 1985 len = hid_report_len(report); 1988 1986 1989 - if (reqtype == HID_REQ_SET_REPORT) 1990 - hid_output_report(report, buf); 1987 + if (report->id == 0) { 1988 + /* reserve the first byte for the report ID */ 1989 + data_buf++; 1990 + len++; 1991 + } 1991 1992 1992 - ret = hid->ll_driver->raw_request(hid, report->id, buf, len, 1993 - report->type, reqtype); 1993 + if (reqtype == HID_REQ_SET_REPORT) 1994 + hid_output_report(report, data_buf); 1995 + 1996 + ret = hid_hw_raw_request(hid, report->id, buf, len, report->type, reqtype); 1994 1997 if (ret < 0) { 1995 1998 dbg_hid("unable to complete request: %d\n", ret); 1996 1999 goto out;
+1 -1
drivers/hid/hid-debug.c
··· 3299 3299 [BTN_STYLUS2] = "Stylus2", [BTN_TOOL_DOUBLETAP] = "ToolDoubleTap", 3300 3300 [BTN_TOOL_TRIPLETAP] = "ToolTripleTap", [BTN_TOOL_QUADTAP] = "ToolQuadrupleTap", 3301 3301 [BTN_GEAR_DOWN] = "BtnGearDown", [BTN_GEAR_UP] = "BtnGearUp", 3302 - [BTN_WHEEL] = "BtnWheel", [KEY_OK] = "Ok", 3302 + [KEY_OK] = "Ok", 3303 3303 [KEY_SELECT] = "Select", [KEY_GOTO] = "Goto", 3304 3304 [KEY_CLEAR] = "Clear", [KEY_POWER2] = "Power2", 3305 3305 [KEY_OPTION] = "Option", [KEY_INFO] = "Info",
+70
tools/testing/selftests/hid/tests/test_mouse.py
··· 439 439 return 32 # EPIPE 440 440 441 441 442 + class BadReportDescriptorMouse(BaseMouse): 443 + """ 444 + This "device" was one autogenerated by syzbot. There are a lot of issues in 445 + it, and the most problematic is that it declares features that have no 446 + size. 447 + 448 + This leads to report->size being set to 0 and can mess up with usbhid 449 + internals. Fortunately, uhid merely passes the incoming buffer, without 450 + touching it so a buffer of size 0 will be translated to [] without 451 + triggering a kernel oops. 452 + 453 + Because the report descriptor is wrong, no input are created, and we need 454 + to tweak a little bit the parameters to make it look correct. 455 + """ 456 + 457 + # fmt: off 458 + report_descriptor = [ 459 + 0x96, 0x01, 0x00, # Report Count (1) 0 460 + 0x06, 0x01, 0x00, # Usage Page (Generic Desktop) 3 461 + # 0x03, 0x00, 0x00, 0x00, 0x00, # Ignored by the kernel somehow 462 + 0x2a, 0x90, 0xa0, # Usage Maximum (41104) 6 463 + 0x27, 0x00, 0x00, 0x00, 0x00, # Logical Maximum (0) 9 464 + 0xb3, 0x81, 0x3e, 0x25, 0x03, # Feature (Cnst,Arr,Abs,Vol) 14 465 + 0x1b, 0xdd, 0xe8, 0x40, 0x50, # Usage Minimum (1346431197) 19 466 + 0x3b, 0x5d, 0x8c, 0x3d, 0xda, # Designator Index 24 467 + ] 468 + # fmt: on 469 + 470 + def __init__( 471 + self, rdesc=report_descriptor, name=None, input_info=(3, 0x045E, 0x07DA) 472 + ): 473 + super().__init__(rdesc, name, input_info) 474 + self.high_resolution_report_called = False 475 + 476 + def get_evdev(self, application=None): 477 + assert self._input_nodes is None 478 + return ( 479 + "Ok" # should be a list or None, but both would fail, so abusing the system 480 + ) 481 + 482 + def next_sync_events(self, application=None): 483 + # there are no evdev nodes, so no events 484 + return [] 485 + 486 + def is_ready(self): 487 + # we wait for the SET_REPORT command to come 488 + return self.high_resolution_report_called 489 + 490 + def set_report(self, req, rnum, rtype, data): 491 + if rtype != self.UHID_FEATURE_REPORT: 492 + raise InvalidHIDCommunication(f"Unexpected report type: {rtype}") 493 + if rnum != 0x0: 494 + raise InvalidHIDCommunication(f"Unexpected report number: {rnum}") 495 + 496 + if len(data) != 1: 497 + raise InvalidHIDCommunication(f"Unexpected data: {data}, expected '[0]'") 498 + 499 + self.high_resolution_report_called = True 500 + 501 + return 0 502 + 503 + 442 504 class ResolutionMultiplierHWheelMouse(TwoWheelMouse): 443 505 # fmt: off 444 506 report_descriptor = [ ··· 1037 975 # assert below print out the real error 1038 976 pass 1039 977 assert remaining == [] 978 + 979 + 980 + class TestBadReportDescriptorMouse(base.BaseTestCase.TestUhid): 981 + def create_device(self): 982 + return BadReportDescriptorMouse() 983 + 984 + def assertName(self, uhdev): 985 + pass