aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hid/i2c-hid
diff options
context:
space:
mode:
authorBenjamin Tissoires <benjamin.tissoires@gmail.com>2012-12-05 09:02:56 -0500
committerJiri Kosina <jkosina@suse.cz>2012-12-06 04:58:42 -0500
commite5b50fe7bea43d0658773c89ba410ecc56867ee6 (patch)
tree8e52cc3e9a269224ad1a233c07a751adcf64b3b9 /drivers/hid/i2c-hid
parent8a1bbb5319384dab6568ac2ce30d19b922413bec (diff)
HID: i2c-hid: fix i2c_hid_get_raw_report count mismatches
The previous memcpy implementation relied on the size advertized by the device. There were no guarantees that buf was big enough. Some gymnastic is also required with the +2/-2 to take into account the first 2 bytes of the returned buffer where the total returned length is supplied by the device. Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'drivers/hid/i2c-hid')
-rw-r--r--drivers/hid/i2c-hid/i2c-hid.c16
1 files changed, 12 insertions, 4 deletions
diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c
index c6630d442e78..ce01d5916184 100644
--- a/drivers/hid/i2c-hid/i2c-hid.c
+++ b/drivers/hid/i2c-hid/i2c-hid.c
@@ -502,23 +502,31 @@ static int i2c_hid_get_raw_report(struct hid_device *hid,
502{ 502{
503 struct i2c_client *client = hid->driver_data; 503 struct i2c_client *client = hid->driver_data;
504 struct i2c_hid *ihid = i2c_get_clientdata(client); 504 struct i2c_hid *ihid = i2c_get_clientdata(client);
505 size_t ret_count, ask_count;
505 int ret; 506 int ret;
506 507
507 if (report_type == HID_OUTPUT_REPORT) 508 if (report_type == HID_OUTPUT_REPORT)
508 return -EINVAL; 509 return -EINVAL;
509 510
510 if (count > ihid->bufsize) 511 /* +2 bytes to include the size of the reply in the query buffer */
511 count = ihid->bufsize; 512 ask_count = min(count + 2, (size_t)ihid->bufsize);
512 513
513 ret = i2c_hid_get_report(client, 514 ret = i2c_hid_get_report(client,
514 report_type == HID_FEATURE_REPORT ? 0x03 : 0x01, 515 report_type == HID_FEATURE_REPORT ? 0x03 : 0x01,
515 report_number, ihid->inbuf, count); 516 report_number, ihid->inbuf, ask_count);
516 517
517 if (ret < 0) 518 if (ret < 0)
518 return ret; 519 return ret;
519 520
520 count = ihid->inbuf[0] | (ihid->inbuf[1] << 8); 521 ret_count = ihid->inbuf[0] | (ihid->inbuf[1] << 8);
521 522
523 if (!ret_count)
524 return 0;
525
526 ret_count = min(ret_count, ask_count);
527
528 /* The query buffer contains the size, dropping it in the reply */
529 count = min(count, ret_count - 2);
522 memcpy(buf, ihid->inbuf + 2, count); 530 memcpy(buf, ihid->inbuf + 2, count);
523 531
524 return count; 532 return count;