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

View file

@ -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 {

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>
@ -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 */