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

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>

authored by

Kees Cook and committed by
Jiri Kosina
0fb6bd06 41df7f6d

+12 -73
+3 -16
drivers/hid/hid-lg2ff.c
··· 64 64 struct hid_report *report; 65 65 struct hid_input *hidinput = list_entry(hid->inputs.next, 66 66 struct hid_input, list); 67 - struct list_head *report_list = 68 - &hid->report_enum[HID_OUTPUT_REPORT].report_list; 69 67 struct input_dev *dev = hidinput->input; 70 68 int error; 71 69 72 - if (list_empty(report_list)) { 73 - hid_err(hid, "no output report found\n"); 70 + /* Check that the report looks ok */ 71 + report = hid_validate_values(hid, HID_OUTPUT_REPORT, 0, 0, 7); 72 + if (!report) 74 73 return -ENODEV; 75 - } 76 - 77 - report = list_entry(report_list->next, struct hid_report, list); 78 - 79 - if (report->maxfield < 1) { 80 - hid_err(hid, "output report is empty\n"); 81 - return -ENODEV; 82 - } 83 - if (report->field[0]->report_count < 7) { 84 - hid_err(hid, "not enough values in the field\n"); 85 - return -ENODEV; 86 - } 87 74 88 75 lg2ff = kmalloc(sizeof(struct lg2ff_device), GFP_KERNEL); 89 76 if (!lg2ff)
+6 -23
drivers/hid/hid-lg3ff.c
··· 66 66 int x, y; 67 67 68 68 /* 69 - * Maxusage should always be 63 (maximum fields) 70 - * likely a better way to ensure this data is clean 69 + * Available values in the field should always be 63, but we only use up to 70 + * 35. Instead, clear the entire area, however big it is. 71 71 */ 72 - memset(report->field[0]->value, 0, sizeof(__s32)*report->field[0]->maxusage); 72 + memset(report->field[0]->value, 0, 73 + sizeof(__s32) * report->field[0]->report_count); 73 74 74 75 switch (effect->type) { 75 76 case FF_CONSTANT: ··· 130 129 int lg3ff_init(struct hid_device *hid) 131 130 { 132 131 struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list); 133 - struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; 134 132 struct input_dev *dev = hidinput->input; 135 - struct hid_report *report; 136 - struct hid_field *field; 137 133 const signed short *ff_bits = ff3_joystick_ac; 138 134 int error; 139 135 int i; 140 136 141 - /* Find the report to use */ 142 - if (list_empty(report_list)) { 143 - hid_err(hid, "No output report found\n"); 144 - return -1; 145 - } 146 - 147 137 /* Check that the report looks ok */ 148 - report = list_entry(report_list->next, struct hid_report, list); 149 - if (!report) { 150 - hid_err(hid, "NULL output report\n"); 151 - return -1; 152 - } 153 - 154 - field = report->field[0]; 155 - if (!field) { 156 - hid_err(hid, "NULL field\n"); 157 - return -1; 158 - } 138 + if (!hid_validate_values(hid, HID_OUTPUT_REPORT, 0, 0, 35)) 139 + return -ENODEV; 159 140 160 141 /* Assume single fixed device G940 */ 161 142 for (i = 0; ff_bits[i] >= 0; i++)
+1 -19
drivers/hid/hid-lg4ff.c
··· 484 484 int lg4ff_init(struct hid_device *hid) 485 485 { 486 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 487 struct input_dev *dev = hidinput->input; 489 - struct hid_report *report; 490 - struct hid_field *field; 491 488 struct lg4ff_device_entry *entry; 492 489 struct lg_drv_data *drv_data; 493 490 struct usb_device_descriptor *udesc; 494 491 int error, i, j; 495 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 494 /* Check that the report looks ok */ 504 - report = list_entry(report_list->next, struct hid_report, list); 505 - if (!report) { 506 - hid_err(hid, "NULL output report\n"); 495 + if (!hid_validate_values(hid, HID_OUTPUT_REPORT, 0, 0, 7)) 507 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 498 /* Check what wheel has been connected */ 517 499 for (i = 0; i < ARRAY_SIZE(lg4ff_devices); i++) {
+2 -15
drivers/hid/hid-lgff.c
··· 128 128 int lgff_init(struct hid_device* hid) 129 129 { 130 130 struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list); 131 - struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; 132 131 struct input_dev *dev = hidinput->input; 133 - struct hid_report *report; 134 - struct hid_field *field; 135 132 const signed short *ff_bits = ff_joystick; 136 133 int error; 137 134 int i; 138 135 139 - /* Find the report to use */ 140 - if (list_empty(report_list)) { 141 - hid_err(hid, "No output report found\n"); 142 - return -1; 143 - } 144 - 145 136 /* Check that the report looks ok */ 146 - report = list_entry(report_list->next, struct hid_report, list); 147 - field = report->field[0]; 148 - if (!field) { 149 - hid_err(hid, "NULL field\n"); 150 - return -1; 151 - } 137 + if (!hid_validate_values(hid, HID_OUTPUT_REPORT, 0, 0, 7)) 138 + return -ENODEV; 152 139 153 140 for (i = 0; i < ARRAY_SIZE(devices); i++) { 154 141 if (dev->id.vendor == devices[i].idVendor &&