]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
HID: core: ensure __hid_request reserves the report ID as the first byte
authorBenjamin Tissoires <bentiss@kernel.org>
Thu, 10 Jul 2025 14:01:34 +0000 (16:01 +0200)
committerBenjamin Tissoires <bentiss@kernel.org>
Sun, 13 Jul 2025 07:53:27 +0000 (09:53 +0200)
The low level transport driver expects the first byte to be the report
ID, even when the report ID is not use (in which case they just shift
the buffer).

However, __hid_request() whas not offsetting the buffer it used by one
in this case, meaning that the raw_request() callback emitted by the
transport driver would be stripped of the first byte.

Note: this changes the API for uhid devices when a request is made
through hid_hw_request. However, several considerations makes me think
this is fine:
- every request to a HID device made through hid_hw_request() would see
  that change, but every request made through hid_hw_raw_request()
  already has the new behaviour. So that means that the users are
  already facing situations where they might have or not the first byte
  being the null report ID when it is 0. We are making things more
  straightforward in the end.
- uhid is mainly used for BLE devices
- uhid is also used for testing, but I don't see that change a big issue
- for BLE devices, we can check which kernel module is calling
  hid_hw_request()
- and in those modules, we can check which are using a Bluetooth device
- and then we can check if the command is used with a report ID or not.
- surprise: none of the kernel module are using a report ID 0
- and finally, bluez, in its function set_report()[0], does the same
  shift if the report ID is 0 and the given buffer has a size > 0.

[0] https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/profiles/input/hog-lib.c#n879

Reported-by: Alan Stern <stern@rowland.harvard.edu>
Closes: https://lore.kernel.org/linux-input/c75433e0-9b47-4072-bbe8-b1d14ea97b13@rowland.harvard.edu/
Reported-by: syzbot+8258d5439c49d4c35f43@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=8258d5439c49d4c35f43
Tested-by: syzbot+8258d5439c49d4c35f43@syzkaller.appspotmail.com
Fixes: 4fa5a7f76cc7 ("HID: core: implement generic .request()")
Cc: stable@vger.kernel.org
Link: https://patch.msgid.link/20250710-report-size-null-v2-2-ccf922b7c4e5@kernel.org
Signed-off-by: Benjamin Tissoires <bentiss@kernel.org>
drivers/hid/hid-core.c

index 1a231dd9e4bc83202f2cbcd8b3a21e8c82b9deec..320887c365f7a36f7376556ffd19f99e52b7d732 100644 (file)
@@ -1976,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;
 
@@ -1984,10 +1984,17 @@ 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);