Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

David Herrmann and committed by
Jiri Kosina
a4b1b587 218eb9ed

+18 -2
+14 -2
net/bluetooth/hidp/core.c
··· 430 430 del_timer(&session->timer); 431 431 } 432 432 433 + static void hidp_process_report(struct hidp_session *session, 434 + int type, const u8 *data, int len, int intr) 435 + { 436 + if (len > HID_MAX_BUFFER_SIZE) 437 + len = HID_MAX_BUFFER_SIZE; 438 + 439 + memcpy(session->input_buf, data, len); 440 + hid_input_report(session->hid, type, session->input_buf, len, intr); 441 + } 442 + 433 443 static void hidp_process_handshake(struct hidp_session *session, 434 444 unsigned char param) 435 445 { ··· 512 502 hidp_input_report(session, skb); 513 503 514 504 if (session->hid) 515 - hid_input_report(session->hid, HID_INPUT_REPORT, skb->data, skb->len, 0); 505 + hidp_process_report(session, HID_INPUT_REPORT, 506 + skb->data, skb->len, 0); 516 507 break; 517 508 518 509 case HIDP_DATA_RTYPE_OTHER: ··· 595 584 hidp_input_report(session, skb); 596 585 597 586 if (session->hid) { 598 - hid_input_report(session->hid, HID_INPUT_REPORT, skb->data, skb->len, 1); 587 + hidp_process_report(session, HID_INPUT_REPORT, 588 + skb->data, skb->len, 1); 599 589 BT_DBG("report len %d", skb->len); 600 590 } 601 591 } else {
+4
net/bluetooth/hidp/hidp.h
··· 24 24 #define __HIDP_H 25 25 26 26 #include <linux/types.h> 27 + #include <linux/hid.h> 27 28 #include <linux/kref.h> 28 29 #include <net/bluetooth/bluetooth.h> 29 30 #include <net/bluetooth/l2cap.h> ··· 180 179 181 180 /* Used in hidp_output_raw_report() */ 182 181 int output_report_success; /* boolean */ 182 + 183 + /* temporary input buffer */ 184 + u8 input_buf[HID_MAX_BUFFER_SIZE]; 183 185 }; 184 186 185 187 /* HIDP init defines */