Commit e003ef2c authored by Linus Torvalds's avatar Linus Torvalds
Browse files

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)
parents 155a3c00 3a1d22bd
Loading
Loading
Loading
Loading
+14 −5
Original line number Diff line number Diff line
@@ -1883,9 +1883,12 @@ u8 *hid_alloc_report_buf(struct hid_report *report, gfp_t flags)
	/*
	 * 7 extra bytes are necessary to achieve proper functionality
	 * of implement() working on 8 byte chunks
	 * 1 extra byte for the report ID if it is null (not used) so
	 * we can reserve that extra byte in the first position of the buffer
	 * when sending it to .raw_request()
	 */

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

	return kzalloc(len, flags);
}
@@ -1973,7 +1976,7 @@ static struct hid_report *hid_get_report(struct hid_report_enum *report_enum,
int __hid_request(struct hid_device *hid, struct hid_report *report,
		enum hid_class_request reqtype)
{
	char *buf;
	char *buf, *data_buf;
	int ret;
	u32 len;

@@ -1981,13 +1984,19 @@ int __hid_request(struct hid_device *hid, struct hid_report *report,
	if (!buf)
		return -ENOMEM;

	data_buf = buf;
	len = hid_report_len(report);

	if (report->id == 0) {
		/* reserve the first byte for the report ID */
		data_buf++;
		len++;
	}

	if (reqtype == HID_REQ_SET_REPORT)
		hid_output_report(report, buf);
		hid_output_report(report, data_buf);

	ret = hid->ll_driver->raw_request(hid, report->id, buf, len,
					  report->type, reqtype);
	ret = hid_hw_raw_request(hid, report->id, buf, len, report->type, reqtype);
	if (ret < 0) {
		dbg_hid("unable to complete request: %d\n", ret);
		goto out;
+1 −1
Original line number Diff line number Diff line
@@ -3299,7 +3299,7 @@ static const char *keys[KEY_MAX + 1] = {
	[BTN_STYLUS2] = "Stylus2",		[BTN_TOOL_DOUBLETAP] = "ToolDoubleTap",
	[BTN_TOOL_TRIPLETAP] = "ToolTripleTap",	[BTN_TOOL_QUADTAP] = "ToolQuadrupleTap",
	[BTN_GEAR_DOWN] = "BtnGearDown",	[BTN_GEAR_UP] = "BtnGearUp",
	[BTN_WHEEL] = "BtnWheel",		[KEY_OK] = "Ok",
						[KEY_OK] = "Ok",
	[KEY_SELECT] = "Select",		[KEY_GOTO] = "Goto",
	[KEY_CLEAR] = "Clear",			[KEY_POWER2] = "Power2",
	[KEY_OPTION] = "Option",		[KEY_INFO] = "Info",
+70 −0
Original line number Diff line number Diff line
@@ -439,6 +439,68 @@ class BadResolutionMultiplierMouse(ResolutionMultiplierMouse):
        return 32  # EPIPE


class BadReportDescriptorMouse(BaseMouse):
    """
    This "device" was one autogenerated by syzbot. There are a lot of issues in
    it, and the most problematic is that it declares features that have no
    size.

    This leads to report->size being set to 0 and can mess up with usbhid
    internals.  Fortunately, uhid merely passes the incoming buffer, without
    touching it so a buffer of size 0 will be translated to [] without
    triggering a kernel oops.

    Because the report descriptor is wrong, no input are created, and we need
    to tweak a little bit the parameters to make it look correct.
    """

    # fmt: off
    report_descriptor = [
        0x96, 0x01, 0x00,              # Report Count (1)                    0
        0x06, 0x01, 0x00,              # Usage Page (Generic Desktop)        3
        # 0x03, 0x00, 0x00, 0x00, 0x00,  # Ignored by the kernel somehow
        0x2a, 0x90, 0xa0,              # Usage Maximum (41104)               6
        0x27, 0x00, 0x00, 0x00, 0x00,  # Logical Maximum (0)                 9
        0xb3, 0x81, 0x3e, 0x25, 0x03,  # Feature (Cnst,Arr,Abs,Vol)          14
        0x1b, 0xdd, 0xe8, 0x40, 0x50,  # Usage Minimum (1346431197)          19
        0x3b, 0x5d, 0x8c, 0x3d, 0xda,  # Designator Index                    24
    ]
    # fmt: on

    def __init__(
        self, rdesc=report_descriptor, name=None, input_info=(3, 0x045E, 0x07DA)
    ):
        super().__init__(rdesc, name, input_info)
        self.high_resolution_report_called = False

    def get_evdev(self, application=None):
        assert self._input_nodes is None
        return (
            "Ok"  # should be a list or None, but both would fail, so abusing the system
        )

    def next_sync_events(self, application=None):
        # there are no evdev nodes, so no events
        return []

    def is_ready(self):
        # we wait for the SET_REPORT command to come
        return self.high_resolution_report_called

    def set_report(self, req, rnum, rtype, data):
        if rtype != self.UHID_FEATURE_REPORT:
            raise InvalidHIDCommunication(f"Unexpected report type: {rtype}")
        if rnum != 0x0:
            raise InvalidHIDCommunication(f"Unexpected report number: {rnum}")

        if len(data) != 1:
            raise InvalidHIDCommunication(f"Unexpected data: {data}, expected '[0]'")

        self.high_resolution_report_called = True

        return 0


class ResolutionMultiplierHWheelMouse(TwoWheelMouse):
    # fmt: off
    report_descriptor = [
@@ -975,3 +1037,11 @@ class TestMiMouse(TestWheelMouse):
            # assert below print out the real error
            pass
        assert remaining == []


class TestBadReportDescriptorMouse(base.BaseTestCase.TestUhid):
    def create_device(self):
        return BadReportDescriptorMouse()

    def assertName(self, uhdev):
        pass