]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
HID: core: introduce hid_safe_input_report()
authorBenjamin Tissoires <bentiss@kernel.org>
Mon, 4 May 2026 08:47:23 +0000 (10:47 +0200)
committerJiri Kosina <jkosina@suse.com>
Tue, 12 May 2026 16:03:58 +0000 (18:03 +0200)
hid_input_report() is used in too many places to have a commit that
doesn't cross subsystem borders. Instead of changing the API, introduce
a new one when things matters in the transport layers:
- usbhid
- i2chid

This effectively revert to the old behavior for those two transport
layers.

Fixes: 0a3fe972a7cb ("HID: core: Mitigate potential OOB by removing bogus memset()")
Cc: stable@vger.kernel.org
Signed-off-by: Benjamin Tissoires <bentiss@kernel.org>
Signed-off-by: Jiri Kosina <jkosina@suse.com>
drivers/hid/hid-core.c
drivers/hid/i2c-hid/i2c-hid-core.c
drivers/hid/usbhid/hid-core.c
include/linux/hid.h

index a806820df7e55371adf1e17e6eae705e06f21b95..b3596851c7191a4a24094ef1e393aef0b07447e2 100644 (file)
@@ -2181,6 +2181,7 @@ unlock:
  * @interrupt: distinguish between interrupt and control transfers
  *
  * This is data entry for lower layers.
+ * Legacy, please use hid_safe_input_report() instead.
  */
 int hid_input_report(struct hid_device *hid, enum hid_report_type type, u8 *data, u32 size,
                     int interrupt)
@@ -2191,6 +2192,30 @@ int hid_input_report(struct hid_device *hid, enum hid_report_type type, u8 *data
 }
 EXPORT_SYMBOL_GPL(hid_input_report);
 
+/**
+ * hid_safe_input_report - report data from lower layer (usb, bt...)
+ *
+ * @hid: hid device
+ * @type: HID report type (HID_*_REPORT)
+ * @data: report contents
+ * @bufsize: allocated size of the data buffer
+ * @size: useful size of data parameter
+ * @interrupt: distinguish between interrupt and control transfers
+ *
+ * This is data entry for lower layers.
+ * Please use this function instead of the non safe version because we provide
+ * here the size of the buffer, allowing hid-core to make smarter decisions
+ * regarding the incoming buffer.
+ */
+int hid_safe_input_report(struct hid_device *hid, enum hid_report_type type, u8 *data,
+                         size_t bufsize, u32 size, int interrupt)
+{
+       return __hid_input_report(hid, type, data, bufsize, size, interrupt, 0,
+                                 false, /* from_bpf */
+                                 false /* lock_already_taken */);
+}
+EXPORT_SYMBOL_GPL(hid_safe_input_report);
+
 bool hid_match_one_id(const struct hid_device *hdev,
                      const struct hid_device_id *id)
 {
index 5a183af3d5c6a6093c724043785be00f0677ab85..e0a302544cef4b032ee8251257fc49ee5b5abf77 100644 (file)
@@ -574,9 +574,10 @@ static void i2c_hid_get_input(struct i2c_hid *ihid)
                if (ihid->hid->group != HID_GROUP_RMI)
                        pm_wakeup_event(&ihid->client->dev, 0);
 
-               hid_input_report(ihid->hid, HID_INPUT_REPORT,
-                               ihid->inbuf + sizeof(__le16),
-                               ret_size - sizeof(__le16), 1);
+               hid_safe_input_report(ihid->hid, HID_INPUT_REPORT,
+                                     ihid->inbuf + sizeof(__le16),
+                                     ihid->bufsize - sizeof(__le16),
+                                     ret_size - sizeof(__le16), 1);
        }
 
        return;
index fbbfc0f60829becbf4445d9ffec96ab0ed1d9fc6..5af93b9b1fb560a9975d20878079ffa3793812ee 100644 (file)
@@ -283,9 +283,9 @@ static void hid_irq_in(struct urb *urb)
                        break;
                usbhid_mark_busy(usbhid);
                if (!test_bit(HID_RESUME_RUNNING, &usbhid->iofl)) {
-                       hid_input_report(urb->context, HID_INPUT_REPORT,
-                                        urb->transfer_buffer,
-                                        urb->actual_length, 1);
+                       hid_safe_input_report(urb->context, HID_INPUT_REPORT,
+                                             urb->transfer_buffer, urb->transfer_buffer_length,
+                                             urb->actual_length, 1);
                        /*
                         * autosuspend refused while keys are pressed
                         * because most keyboards don't wake up when
@@ -482,9 +482,10 @@ static void hid_ctrl(struct urb *urb)
        switch (status) {
        case 0:                 /* success */
                if (usbhid->ctrl[usbhid->ctrltail].dir == USB_DIR_IN)
-                       hid_input_report(urb->context,
+                       hid_safe_input_report(urb->context,
                                usbhid->ctrl[usbhid->ctrltail].report->type,
-                               urb->transfer_buffer, urb->actual_length, 0);
+                               urb->transfer_buffer, urb->transfer_buffer_length,
+                               urb->actual_length, 0);
                break;
        case -ESHUTDOWN:        /* unplug */
                unplug = 1;
index ac432a2ef415aa383d773a3ecca6afc4aac05f60..bfb9859f391ee558246cbb04a86704e594616d40 100644 (file)
@@ -1030,6 +1030,8 @@ struct hid_field *hid_find_field(struct hid_device *hdev, unsigned int report_ty
 int hid_set_field(struct hid_field *, unsigned, __s32);
 int hid_input_report(struct hid_device *hid, enum hid_report_type type, u8 *data, u32 size,
                     int interrupt);
+int hid_safe_input_report(struct hid_device *hid, enum hid_report_type type, u8 *data,
+                         size_t bufsize, u32 size, int interrupt);
 struct hid_field *hidinput_get_led_field(struct hid_device *hid);
 unsigned int hidinput_count_leds(struct hid_device *hid);
 __s32 hidinput_calc_abs_res(const struct hid_field *field, __u16 code);