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

(cherry picked from commit a4b1b5877b514b276f0f31efe02388a9c2836728)

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: David Herrmann <dh.herrmann@gmail.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Bug: 65853588
Change-Id: Iec1410993a6d21dd9c88bd7669cf658b9f48f9dc
This commit is contained in:
David Herrmann 2013-12-19 12:09:32 +01:00 committed by syphyr
parent 4d261ae9ac
commit a79aa02daa
2 changed files with 18 additions and 2 deletions

View File

@ -425,6 +425,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)
{
@ -498,7 +508,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:
@ -580,7 +591,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 {

View File

@ -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>
@ -177,6 +178,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 */