Skip to content

Commit e003ef2

Browse files
committed
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)
2 parents 155a3c0 + 3a1d22b commit e003ef2

File tree

3 files changed

+85
-6
lines changed

3 files changed

+85
-6
lines changed

drivers/hid/hid-core.c

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1883,9 +1883,12 @@ u8 *hid_alloc_report_buf(struct hid_report *report, gfp_t flags)
18831883
/*
18841884
* 7 extra bytes are necessary to achieve proper functionality
18851885
* 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()
18861889
*/
18871890

1888-
u32 len = hid_report_len(report) + 7;
1891+
u32 len = hid_report_len(report) + 7 + (report->id == 0);
18891892

18901893
return kzalloc(len, flags);
18911894
}
@@ -1973,21 +1976,27 @@ static struct hid_report *hid_get_report(struct hid_report_enum *report_enum,
19731976
int __hid_request(struct hid_device *hid, struct hid_report *report,
19741977
enum hid_class_request reqtype)
19751978
{
1976-
char *buf;
1979+
char *buf, *data_buf;
19771980
int ret;
19781981
u32 len;
19791982

19801983
buf = hid_alloc_report_buf(report, GFP_KERNEL);
19811984
if (!buf)
19821985
return -ENOMEM;
19831986

1987+
data_buf = buf;
19841988
len = hid_report_len(report);
19851989

1990+
if (report->id == 0) {
1991+
/* reserve the first byte for the report ID */
1992+
data_buf++;
1993+
len++;
1994+
}
1995+
19861996
if (reqtype == HID_REQ_SET_REPORT)
1987-
hid_output_report(report, buf);
1997+
hid_output_report(report, data_buf);
19881998

1989-
ret = hid->ll_driver->raw_request(hid, report->id, buf, len,
1990-
report->type, reqtype);
1999+
ret = hid_hw_raw_request(hid, report->id, buf, len, report->type, reqtype);
19912000
if (ret < 0) {
19922001
dbg_hid("unable to complete request: %d\n", ret);
19932002
goto out;

drivers/hid/hid-debug.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3299,7 +3299,7 @@ static const char *keys[KEY_MAX + 1] = {
32993299
[BTN_STYLUS2] = "Stylus2", [BTN_TOOL_DOUBLETAP] = "ToolDoubleTap",
33003300
[BTN_TOOL_TRIPLETAP] = "ToolTripleTap", [BTN_TOOL_QUADTAP] = "ToolQuadrupleTap",
33013301
[BTN_GEAR_DOWN] = "BtnGearDown", [BTN_GEAR_UP] = "BtnGearUp",
3302-
[BTN_WHEEL] = "BtnWheel", [KEY_OK] = "Ok",
3302+
[KEY_OK] = "Ok",
33033303
[KEY_SELECT] = "Select", [KEY_GOTO] = "Goto",
33043304
[KEY_CLEAR] = "Clear", [KEY_POWER2] = "Power2",
33053305
[KEY_OPTION] = "Option", [KEY_INFO] = "Info",

tools/testing/selftests/hid/tests/test_mouse.py

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -439,6 +439,68 @@ def set_report(self, req, rnum, rtype, data):
439439
return 32 # EPIPE
440440

441441

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+
442504
class ResolutionMultiplierHWheelMouse(TwoWheelMouse):
443505
# fmt: off
444506
report_descriptor = [
@@ -975,3 +1037,11 @@ def assertInputEvents(self, expected_events, effective_events):
9751037
# assert below print out the real error
9761038
pass
9771039
assert remaining == []
1040+
1041+
1042+
class TestBadReportDescriptorMouse(base.BaseTestCase.TestUhid):
1043+
def create_device(self):
1044+
return BadReportDescriptorMouse()
1045+
1046+
def assertName(self, uhdev):
1047+
pass

0 commit comments

Comments
 (0)