Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a4b1b587 authored by David Herrmann's avatar David Herrmann Committed by Jiri Kosina
Browse files

HID: Bluetooth: hidp: make sure input buffers are big enough



HID core expects the input buffers to be at least of size 4096
(HID_MAX_BUFFER_SIZE). Other sizes will result in buffer-overflows if an
input-report is smaller than advertised. We could, like i2c, compute the
biggest report-size instead of using HID_MAX_BUFFER_SIZE, but this will
blow up if report-descriptors are changed after ->start() has been called.
So lets be safe and just use the biggest buffer we have.

Note that this adds an additional copy to the HIDP input path. If there is
a way to make sure the skb-buf is big enough, we should use that instead.

The best way would be to make hid-core honor the @size argument, though,
that sounds easier than it is. So lets just fix the buffer-overflows for
now and afterwards look for a faster way for all transport drivers.

Signed-off-by: default avatarDavid Herrmann <dh.herrmann@gmail.com>
Signed-off-by: default avatarJiri Kosina <jkosina@suse.cz>
parent 218eb9ed
Loading
Loading
Loading
Loading
+14 −2
Original line number Diff line number Diff line
@@ -430,6 +430,16 @@ static void hidp_del_timer(struct hidp_session *session)
		del_timer(&session->timer);
}

static void hidp_process_report(struct hidp_session *session,
				int type, const u8 *data, int len, int intr)
{
	if (len > HID_MAX_BUFFER_SIZE)
		len = HID_MAX_BUFFER_SIZE;

	memcpy(session->input_buf, data, len);
	hid_input_report(session->hid, type, session->input_buf, len, intr);
}

static void hidp_process_handshake(struct hidp_session *session,
					unsigned char param)
{
@@ -502,7 +512,8 @@ static int hidp_process_data(struct hidp_session *session, struct sk_buff *skb,
			hidp_input_report(session, skb);

		if (session->hid)
			hid_input_report(session->hid, HID_INPUT_REPORT, skb->data, skb->len, 0);
			hidp_process_report(session, HID_INPUT_REPORT,
					    skb->data, skb->len, 0);
		break;

	case HIDP_DATA_RTYPE_OTHER:
@@ -584,7 +595,8 @@ static void hidp_recv_intr_frame(struct hidp_session *session,
			hidp_input_report(session, skb);

		if (session->hid) {
			hid_input_report(session->hid, HID_INPUT_REPORT, skb->data, skb->len, 1);
			hidp_process_report(session, HID_INPUT_REPORT,
					    skb->data, skb->len, 1);
			BT_DBG("report len %d", skb->len);
		}
	} else {
+4 −0
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@
#define __HIDP_H

#include <linux/types.h>
#include <linux/hid.h>
#include <linux/kref.h>
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/l2cap.h>
@@ -179,6 +180,9 @@ struct hidp_session {

	/* Used in hidp_output_raw_report() */
	int output_report_success; /* boolean */

	/* temporary input buffer */
	u8 input_buf[HID_MAX_BUFFER_SIZE];
};

/* HIDP init defines */