diff options
author | Benjamin Tissoires <benjamin.tissoires@redhat.com> | 2013-09-11 15:56:58 -0400 |
---|---|---|
committer | Jiri Kosina <jkosina@suse.cz> | 2013-09-13 09:13:52 -0400 |
commit | 8821f5dc187bdf16cfb32ef5aa8c3035273fa79a (patch) | |
tree | 5cefd4e48b6eb226d8da4d887cb56dac67db64fa /drivers/hid | |
parent | 297502abb32e225fb23801fcdb0e4f6f8e17099a (diff) |
HID: multitouch: validate indexes details
When working on report indexes, always validate that they are in bounds.
Without this, a HID device could report a malicious feature report that
could trick the driver into a heap overflow:
[ 634.885003] usb 1-1: New USB device found, idVendor=0596, idProduct=0500
...
[ 676.469629] BUG kmalloc-192 (Tainted: G W ): Redzone overwritten
Note that we need to change the indexes from s8 to s16 as they can
be between -1 and 255.
CVE-2013-2897
Cc: stable@vger.kernel.org
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
Acked-by: Kees Cook <keescook@chromium.org>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'drivers/hid')
-rw-r--r-- | drivers/hid/hid-multitouch.c | 26 |
1 files changed, 14 insertions, 12 deletions
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index ac28f08c3866..5e5fe1b8eebb 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c | |||
@@ -101,9 +101,9 @@ struct mt_device { | |||
101 | unsigned last_slot_field; /* the last field of a slot */ | 101 | unsigned last_slot_field; /* the last field of a slot */ |
102 | unsigned mt_report_id; /* the report ID of the multitouch device */ | 102 | unsigned mt_report_id; /* the report ID of the multitouch device */ |
103 | unsigned pen_report_id; /* the report ID of the pen device */ | 103 | unsigned pen_report_id; /* the report ID of the pen device */ |
104 | __s8 inputmode; /* InputMode HID feature, -1 if non-existent */ | 104 | __s16 inputmode; /* InputMode HID feature, -1 if non-existent */ |
105 | __s8 inputmode_index; /* InputMode HID feature index in the report */ | 105 | __s16 inputmode_index; /* InputMode HID feature index in the report */ |
106 | __s8 maxcontact_report_id; /* Maximum Contact Number HID feature, | 106 | __s16 maxcontact_report_id; /* Maximum Contact Number HID feature, |
107 | -1 if non-existent */ | 107 | -1 if non-existent */ |
108 | __u8 num_received; /* how many contacts we received */ | 108 | __u8 num_received; /* how many contacts we received */ |
109 | __u8 num_expected; /* expected last contact index */ | 109 | __u8 num_expected; /* expected last contact index */ |
@@ -312,20 +312,18 @@ static void mt_feature_mapping(struct hid_device *hdev, | |||
312 | struct hid_field *field, struct hid_usage *usage) | 312 | struct hid_field *field, struct hid_usage *usage) |
313 | { | 313 | { |
314 | struct mt_device *td = hid_get_drvdata(hdev); | 314 | struct mt_device *td = hid_get_drvdata(hdev); |
315 | int i; | ||
316 | 315 | ||
317 | switch (usage->hid) { | 316 | switch (usage->hid) { |
318 | case HID_DG_INPUTMODE: | 317 | case HID_DG_INPUTMODE: |
319 | td->inputmode = field->report->id; | 318 | /* Ignore if value index is out of bounds. */ |
320 | td->inputmode_index = 0; /* has to be updated below */ | 319 | if (usage->usage_index >= field->report_count) { |
321 | 320 | dev_err(&hdev->dev, "HID_DG_INPUTMODE out of range\n"); | |
322 | for (i=0; i < field->maxusage; i++) { | 321 | break; |
323 | if (field->usage[i].hid == usage->hid) { | ||
324 | td->inputmode_index = i; | ||
325 | break; | ||
326 | } | ||
327 | } | 322 | } |
328 | 323 | ||
324 | td->inputmode = field->report->id; | ||
325 | td->inputmode_index = usage->usage_index; | ||
326 | |||
329 | break; | 327 | break; |
330 | case HID_DG_CONTACTMAX: | 328 | case HID_DG_CONTACTMAX: |
331 | td->maxcontact_report_id = field->report->id; | 329 | td->maxcontact_report_id = field->report->id; |
@@ -511,6 +509,10 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi, | |||
511 | mt_store_field(usage, td, hi); | 509 | mt_store_field(usage, td, hi); |
512 | return 1; | 510 | return 1; |
513 | case HID_DG_CONTACTCOUNT: | 511 | case HID_DG_CONTACTCOUNT: |
512 | /* Ignore if indexes are out of bounds. */ | ||
513 | if (field->index >= field->report->maxfield || | ||
514 | usage->usage_index >= field->report_count) | ||
515 | return 1; | ||
514 | td->cc_index = field->index; | 516 | td->cc_index = field->index; |
515 | td->cc_value_index = usage->usage_index; | 517 | td->cc_value_index = usage->usage_index; |
516 | return 1; | 518 | return 1; |