Commit 20634254 authored by Benjamin Tissoires's avatar Benjamin Tissoires Committed by Jiri Kosina
Browse files

HID: core: introduce hid_safe_input_report()



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: 0a3fe972 ("HID: core: Mitigate potential OOB by removing bogus memset()")
Cc: stable@vger.kernel.org
Signed-off-by: default avatarBenjamin Tissoires <bentiss@kernel.org>
Signed-off-by: default avatarJiri Kosina <jkosina@suse.com>
parent 2c85c61d
Loading
Loading
Loading
Loading
+25 −0
Original line number Diff line number Diff line
@@ -2181,6 +2181,7 @@ static int __hid_input_report(struct hid_device *hid, enum hid_report_type type,
 * @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)
{
+4 −3
Original line number Diff line number Diff line
@@ -574,8 +574,9 @@ 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,
		hid_safe_input_report(ihid->hid, HID_INPUT_REPORT,
				      ihid->inbuf + sizeof(__le16),
				      ihid->bufsize - sizeof(__le16),
				      ret_size - sizeof(__le16), 1);
	}

+6 −5
Original line number Diff line number Diff line
@@ -283,8 +283,8 @@ 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,
			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
@@ -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;
+2 −0
Original line number Diff line number Diff line
@@ -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);