diff options
author | Kees Cook <keescook@chromium.org> | 2013-09-11 15:56:54 -0400 |
---|---|---|
committer | Jiri Kosina <jkosina@suse.cz> | 2013-09-13 09:12:39 -0400 |
commit | 0fb6bd06e06792469acc15bbe427361b56ada528 (patch) | |
tree | 9c389f833e25a00ca172274e359aefe77fa713dc /drivers/hid/hid-lg4ff.c | |
parent | 41df7f6d43723deb7364340b44bc5d94bf717456 (diff) |
HID: LG: validate HID output report details
A HID device could send a malicious output report that would cause the
lg, lg3, and lg4 HID drivers to write beyond the output report allocation
during an event, causing a heap overflow:
[ 325.245240] usb 1-1: New USB device found, idVendor=046d, idProduct=c287
...
[ 414.518960] BUG kmalloc-4096 (Not tainted): Redzone overwritten
Additionally, while lg2 did correctly validate the report details, it was
cleaned up and shortened.
CVE-2013-2893
Signed-off-by: Kees Cook <keescook@chromium.org>
Cc: stable@vger.kernel.org
Reviewed-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'drivers/hid/hid-lg4ff.c')
-rw-r--r-- | drivers/hid/hid-lg4ff.c | 20 |
1 files changed, 1 insertions, 19 deletions
diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c index 0ddae2a00d59..8782fe1aaa07 100644 --- a/drivers/hid/hid-lg4ff.c +++ b/drivers/hid/hid-lg4ff.c | |||
@@ -484,34 +484,16 @@ static enum led_brightness lg4ff_led_get_brightness(struct led_classdev *led_cde | |||
484 | int lg4ff_init(struct hid_device *hid) | 484 | int lg4ff_init(struct hid_device *hid) |
485 | { | 485 | { |
486 | struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list); | 486 | struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list); |
487 | struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; | ||
488 | struct input_dev *dev = hidinput->input; | 487 | struct input_dev *dev = hidinput->input; |
489 | struct hid_report *report; | ||
490 | struct hid_field *field; | ||
491 | struct lg4ff_device_entry *entry; | 488 | struct lg4ff_device_entry *entry; |
492 | struct lg_drv_data *drv_data; | 489 | struct lg_drv_data *drv_data; |
493 | struct usb_device_descriptor *udesc; | 490 | struct usb_device_descriptor *udesc; |
494 | int error, i, j; | 491 | int error, i, j; |
495 | __u16 bcdDevice, rev_maj, rev_min; | 492 | __u16 bcdDevice, rev_maj, rev_min; |
496 | 493 | ||
497 | /* Find the report to use */ | ||
498 | if (list_empty(report_list)) { | ||
499 | hid_err(hid, "No output report found\n"); | ||
500 | return -1; | ||
501 | } | ||
502 | |||
503 | /* Check that the report looks ok */ | 494 | /* Check that the report looks ok */ |
504 | report = list_entry(report_list->next, struct hid_report, list); | 495 | if (!hid_validate_values(hid, HID_OUTPUT_REPORT, 0, 0, 7)) |
505 | if (!report) { | ||
506 | hid_err(hid, "NULL output report\n"); | ||
507 | return -1; | 496 | return -1; |
508 | } | ||
509 | |||
510 | field = report->field[0]; | ||
511 | if (!field) { | ||
512 | hid_err(hid, "NULL field\n"); | ||
513 | return -1; | ||
514 | } | ||
515 | 497 | ||
516 | /* Check what wheel has been connected */ | 498 | /* Check what wheel has been connected */ |
517 | for (i = 0; i < ARRAY_SIZE(lg4ff_devices); i++) { | 499 | for (i = 0; i < ARRAY_SIZE(lg4ff_devices); i++) { |