Pull HID updates from Jiri Kosina: "Fixes for CVE-2013-2897, CVE-2013-2895, CVE-2013-2897, CVE-2013-2894, CVE-2013-2893, CVE-2013-2891, CVE-2013-2890, CVE-2013-2889. All the bugs are triggerable only by specially crafted evil-on-purpose HW devices. Fixes by Kees Cook and Benjamin Tissoires" * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid: HID: lenovo-tpkbd: fix leak if tpkbd_probe_tp fails HID: multitouch: validate indexes details HID: logitech-dj: validate output report details HID: validate feature and input report details HID: lenovo-tpkbd: validate output report details HID: LG: validate HID output report details HID: steelseries: validate output report details HID: sony: validate HID output report details HID: zeroplus: validate output report details HID: provide a helper for validating hid reports
Unified · Split
| @@ -94,7 +94,6 @@ EXPORT_SYMBOL_GPL(hid_register_report); · 93 unmodified lines | ||
| 94 | 94 | static struct hid_field *hid_register_field(struct hid_report *report, unsigned usages, unsigned values) |
| 95 | 95 | { |
| 96 | 96 | struct hid_field *field; |
| 97 | − int i; | |
| 98 | 97 | |
| 99 | 98 | if (report->maxfield == HID_MAX_FIELDS) { |
| 100 | 99 | hid_err(report->device, "too many fields in report\n"); |
| @@ -113,9 +112,6 @@ static struct hid_field *hid_register_field(struct hid_report *report, unsigned · 12 unmodified lines | ||
| 113 | 112 | field->value = (s32 *)(field->usage + usages); |
| 114 | 113 | field->report = report; |
| 115 | 114 | |
| 116 | − for (i = 0; i < usages; i++) | |
| 117 | − field->usage[i].usage_index = i; | |
| 118 | − | |
| 119 | 115 | return field; |
| 120 | 116 | } |
| 121 | 117 | |
| @@ -226,9 +222,9 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign · 104 unmodified lines | ||
| 226 | 222 | { |
| 227 | 223 | struct hid_report *report; |
| 228 | 224 | struct hid_field *field; |
| 229 | − int usages; | |
| 225 | + unsigned usages; | |
| 230 | 226 | unsigned offset; |
| 231 | − int i; | |
| 227 | + unsigned i; | |
| 232 | 228 | |
| 233 | 229 | report = hid_register_report(parser->device, report_type, parser->global.report_id); |
| 234 | 230 | if (!report) { |
| @@ -255,7 +251,8 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign · 20 unmodified lines | ||
| 255 | 251 | if (!parser->local.usage_index) /* Ignore padding fields */ |
| 256 | 252 | return 0; |
| 257 | 253 | |
| 258 | − usages = max_t(int, parser->local.usage_index, parser->global.report_count); | |
| 254 | + usages = max_t(unsigned, parser->local.usage_index, | |
| 255 | + parser->global.report_count); | |
| 259 | 256 | |
| 260 | 257 | field = hid_register_field(report, usages, parser->global.report_count); |
| 261 | 258 | if (!field) |
| @@ -266,13 +263,14 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign · 4 unmodified lines | ||
| 266 | 263 | field->application = hid_lookup_collection(parser, HID_COLLECTION_APPLICATION); |
| 267 | 264 | |
| 268 | 265 | for (i = 0; i < usages; i++) { |
| 269 | − int j = i; | |
| 266 | + unsigned j = i; | |
| 270 | 267 | /* Duplicate the last usage we parsed if we have excess values */ |
| 271 | 268 | if (i >= parser->local.usage_index) |
| 272 | 269 | j = parser->local.usage_index - 1; |
| 273 | 270 | field->usage[i].hid = parser->local.usage[j]; |
| 274 | 271 | field->usage[i].collection_index = |
| 275 | 272 | parser->local.collection_index[j]; |
| 273 | + field->usage[i].usage_index = i; | |
| 276 | 274 | } |
| 277 | 275 | |
| 278 | 276 | field->maxusage = usages; |
| @@ -801,6 +799,64 @@ int hid_parse_report(struct hid_device *hid, __u8 *start, unsigned size) · 522 unmodified lines | ||
| 801 | 799 | } |
| 802 | 800 | EXPORT_SYMBOL_GPL(hid_parse_report); |
| 803 | 801 | |
| 802 | +static const char * const hid_report_names[] = { | |
| 803 | + "HID_INPUT_REPORT", | |
| 804 | + "HID_OUTPUT_REPORT", | |
| 805 | + "HID_FEATURE_REPORT", | |
| 806 | +}; | |
| 807 | +/** | |
| 808 | + * hid_validate_values - validate existing device report's value indexes | |
| 809 | + * | |
| 810 | + * @device: hid device | |
| 811 | + * @type: which report type to examine | |
| 812 | + * @id: which report ID to examine (0 for first) | |
| 813 | + * @field_index: which report field to examine | |
| 814 | + * @report_counts: expected number of values | |
| 815 | + * | |
| 816 | + * Validate the number of values in a given field of a given report, after | |
| 817 | + * parsing. | |
| 818 | + */ | |
| 819 | +struct hid_report *hid_validate_values(struct hid_device *hid, | |
| 820 | + unsigned int type, unsigned int id, | |
| 821 | + unsigned int field_index, | |
| 822 | + unsigned int report_counts) | |
| 823 | +{ | |
| 824 | + struct hid_report *report; | |
| 825 | + | |
| 826 | + if (type > HID_FEATURE_REPORT) { | |
| 827 | + hid_err(hid, "invalid HID report type %u\n", type); | |
| 828 | + return NULL; | |
| 829 | + } | |
| 830 | + | |
| 831 | + if (id >= HID_MAX_IDS) { | |
| 832 | + hid_err(hid, "invalid HID report id %u\n", id); | |
| 833 | + return NULL; | |
| 834 | + } | |
| 835 | + | |
| 836 | + /* | |
| 837 | + * Explicitly not using hid_get_report() here since it depends on | |
| 838 | + * ->numbered being checked, which may not always be the case when | |
| 839 | + * drivers go to access report values. | |
| 840 | + */ | |
| 841 | + report = hid->report_enum[type].report_id_hash[id]; | |
| 842 | + if (!report) { | |
| 843 | + hid_err(hid, "missing %s %u\n", hid_report_names[type], id); | |
| 844 | + return NULL; | |
| 845 | + } | |
| 846 | + if (report->maxfield <= field_index) { | |
| 847 | + hid_err(hid, "not enough fields in %s %u\n", | |
| 848 | + hid_report_names[type], id); | |
| 849 | + return NULL; | |
| 850 | + } | |
| 851 | + if (report->field[field_index]->report_count < report_counts) { | |
| 852 | + hid_err(hid, "not enough values in %s %u field %u\n", | |
| 853 | + hid_report_names[type], id, field_index); | |
| 854 | + return NULL; | |
| 855 | + } | |
| 856 | + return report; | |
| 857 | +} | |
| 858 | +EXPORT_SYMBOL_GPL(hid_validate_values); | |
| 859 | + | |
| 804 | 860 | /** |
| 805 | 861 | * hid_open_report - open a driver-specific device report |
| 806 | 862 | * |
| @@ -1296,7 +1352,7 @@ int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size, · 489 unmodified lines | ||
| 1296 | 1352 | goto out; |
| 1297 | 1353 | } |
| 1298 | 1354 | |
| 1299 | − if (hid->claimed != HID_CLAIMED_HIDRAW) { | |
| 1355 | + if (hid->claimed != HID_CLAIMED_HIDRAW && report->maxfield) { | |
| 1300 | 1356 | for (a = 0; a < report->maxfield; a++) |
| 1301 | 1357 | hid_input_field(hid, report->field[a], cdata, interrupt); |
| 1302 | 1358 | hdrv = hid->driver; |
| @@ -485,6 +485,10 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel · 484 unmodified lines | ||
| 485 | 485 | if (field->flags & HID_MAIN_ITEM_CONSTANT) |
| 486 | 486 | goto ignore; |
| 487 | 487 | |
| 488 | + /* Ignore if report count is out of bounds. */ | |
| 489 | + if (field->report_count < 1) | |
| 490 | + goto ignore; | |
| 491 | + | |
| 488 | 492 | /* only LED usages are supported in output fields */ |
| 489 | 493 | if (field->report_type == HID_OUTPUT_REPORT && |
| 490 | 494 | (usage->hid & HID_USAGE_PAGE) != HID_UP_LED) { |
| @@ -1236,7 +1240,11 @@ static void report_features(struct hid_device *hid) · 745 unmodified lines | ||
| 1236 | 1240 | |
| 1237 | 1241 | rep_enum = &hid->report_enum[HID_FEATURE_REPORT]; |
| 1238 | 1242 | list_for_each_entry(rep, &rep_enum->report_list, list) |
| 1239 | − for (i = 0; i < rep->maxfield; i++) | |
| 1243 | + for (i = 0; i < rep->maxfield; i++) { | |
| 1244 | + /* Ignore if report count is out of bounds. */ | |
| 1245 | + if (rep->field[i]->report_count < 1) | |
| 1246 | + continue; | |
| 1247 | + | |
| 1240 | 1248 | for (j = 0; j < rep->field[i]->maxusage; j++) { |
| 1241 | 1249 | /* Verify if Battery Strength feature is available */ |
| 1242 | 1250 | hidinput_setup_battery(hid, HID_FEATURE_REPORT, rep->field[i]); |
| @@ -1245,6 +1253,7 @@ static void report_features(struct hid_device *hid) · 2 unmodified lines | ||
| 1245 | 1253 | drv->feature_mapping(hid, rep->field[i], |
| 1246 | 1254 | rep->field[i]->usage + j); |
| 1247 | 1255 | } |
| 1256 | + } | |
| 1248 | 1257 | } |
| 1249 | 1258 | |
| 1250 | 1259 | static struct hid_input *hidinput_allocate(struct hid_device *hid) |
| @@ -339,7 +339,15 @@ static int tpkbd_probe_tp(struct hid_device *hdev) · 338 unmodified lines | ||
| 339 | 339 | struct tpkbd_data_pointer *data_pointer; |
| 340 | 340 | size_t name_sz = strlen(dev_name(dev)) + 16; |
| 341 | 341 | char *name_mute, *name_micmute; |
| 342 | − int ret; | |
| 342 | + int i, ret; | |
| 343 | + | |
| 344 | + /* Validate required reports. */ | |
| 345 | + for (i = 0; i < 4; i++) { | |
| 346 | + if (!hid_validate_values(hdev, HID_FEATURE_REPORT, 4, i, 1)) | |
| 347 | + return -ENODEV; | |
| 348 | + } | |
| 349 | + if (!hid_validate_values(hdev, HID_OUTPUT_REPORT, 3, 0, 2)) | |
| 350 | + return -ENODEV; | |
| 343 | 351 | |
| 344 | 352 | if (sysfs_create_group(&hdev->dev.kobj, |
| 345 | 353 | &tpkbd_attr_group_pointer)) { |
| @@ -406,22 +414,27 @@ static int tpkbd_probe(struct hid_device *hdev, · 60 unmodified lines | ||
| 406 | 414 | ret = hid_parse(hdev); |
| 407 | 415 | if (ret) { |
| 408 | 416 | hid_err(hdev, "hid_parse failed\n"); |
| 409 | − goto err_free; | |
| 417 | + goto err; | |
| 410 | 418 | } |
| 411 | 419 | |
| 412 | 420 | ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); |
| 413 | 421 | if (ret) { |
| 414 | 422 | hid_err(hdev, "hid_hw_start failed\n"); |
| 415 | − goto err_free; | |
| 423 | + goto err; | |
| 416 | 424 | } |
| 417 | 425 | |
| 418 | 426 | uhdev = (struct usbhid_device *) hdev->driver_data; |
| 419 | 427 | |
| 420 | − if (uhdev->ifnum == 1) | |
| 421 | − return tpkbd_probe_tp(hdev); | |
| 428 | + if (uhdev->ifnum == 1) { | |
| 429 | + ret = tpkbd_probe_tp(hdev); | |
| 430 | + if (ret) | |
| 431 | + goto err_hid; | |
| 432 | + } | |
| 422 | 433 | |
| 423 | 434 | return 0; |
| 424 | −err_free: | |
| 435 | +err_hid: | |
| 436 | + hid_hw_stop(hdev); | |
| 437 | +err: | |
| 425 | 438 | return ret; |
| 426 | 439 | } |
| 427 | 440 | |
| @@ -64,26 +64,13 @@ int lg2ff_init(struct hid_device *hid) · 63 unmodified lines | ||
| 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) |
| @@ -66,10 +66,11 @@ static int hid_lg3ff_play(struct input_dev *dev, void *data, · 65 unmodified lines | ||
| 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: |
| @@ -129,32 +130,14 @@ static const signed short ff3_joystick_ac[] = { · 53 unmodified lines | ||
| 129 | 130 | int lg3ff_init(struct hid_device *hid) |
| 130 | 131 | { |
| 131 | 132 | struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list); |
| 132 | − struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; | |
| 133 | 133 | struct input_dev *dev = hidinput->input; |
| 134 | − struct hid_report *report; | |
| 135 | − struct hid_field *field; | |
| 136 | 134 | const signed short *ff_bits = ff3_joystick_ac; |
| 137 | 135 | int error; |
| 138 | 136 | int i; |
| 139 | 137 | |
| 140 | − /* Find the report to use */ | |
| 141 | − if (list_empty(report_list)) { | |
| 142 | − hid_err(hid, "No output report found\n"); | |
| 143 | − return -1; | |
| 144 | − } | |
| 145 | − | |
| 146 | 138 | /* Check that the report looks ok */ |
| 147 | − report = list_entry(report_list->next, struct hid_report, list); | |
| 148 | − if (!report) { | |
| 149 | − hid_err(hid, "NULL output report\n"); | |
| 150 | − return -1; | |
| 151 | − } | |
| 152 | − | |
| 153 | − field = report->field[0]; | |
| 154 | − if (!field) { | |
| 155 | − hid_err(hid, "NULL field\n"); | |
| 156 | − return -1; | |
| 157 | − } | |
| 139 | + if (!hid_validate_values(hid, HID_OUTPUT_REPORT, 0, 0, 35)) | |
| 140 | + return -ENODEV; | |
| 158 | 141 | |
| 159 | 142 | /* Assume single fixed device G940 */ |
| 160 | 143 | for (i = 0; ff_bits[i] >= 0; i++) |
| @@ -484,34 +484,16 @@ static enum led_brightness lg4ff_led_get_brightness(struct led_classdev *led_cde · 483 unmodified lines | ||
| 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++) { |
| @@ -128,27 +128,14 @@ static void hid_lgff_set_autocenter(struct input_dev *dev, u16 magnitude) · 127 unmodified lines | ||
| 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 && |
| @@ -461,7 +461,7 @@ static int logi_dj_recv_send_report(struct dj_receiver_dev *djrcv_dev, · 460 unmodified lines | ||
| 461 | 461 | struct hid_report *report; |
| 462 | 462 | struct hid_report_enum *output_report_enum; |
| 463 | 463 | u8 *data = (u8 *)(&dj_report->device_index); |
| 464 | − int i; | |
| 464 | + unsigned int i; | |
| 465 | 465 | |
| 466 | 466 | output_report_enum = &hdev->report_enum[HID_OUTPUT_REPORT]; |
| 467 | 467 | report = output_report_enum->report_id_hash[REPORT_ID_DJ_SHORT]; |
| @@ -471,7 +471,7 @@ static int logi_dj_recv_send_report(struct dj_receiver_dev *djrcv_dev, · 3 unmodified lines | ||
| 471 | 471 | return -ENODEV; |
| 472 | 472 | } |
| 473 | 473 | |
| 474 | − for (i = 0; i < report->field[0]->report_count; i++) | |
| 474 | + for (i = 0; i < DJREPORT_SHORT_LENGTH - 1; i++) | |
| 475 | 475 | report->field[0]->value[i] = data[i]; |
| 476 | 476 | |
| 477 | 477 | hid_hw_request(hdev, report, HID_REQ_SET_REPORT); |
| @@ -791,6 +791,12 @@ static int logi_dj_probe(struct hid_device *hdev, · 313 unmodified lines | ||
| 791 | 791 | goto hid_parse_fail; |
| 792 | 792 | } |
| 793 | 793 | |
| 794 | + if (!hid_validate_values(hdev, HID_OUTPUT_REPORT, REPORT_ID_DJ_SHORT, | |
| 795 | + 0, DJREPORT_SHORT_LENGTH - 1)) { | |
| 796 | + retval = -ENODEV; | |
| 797 | + goto hid_parse_fail; | |
| 798 | + } | |
| 799 | + | |
| 794 | 800 | /* Starts the usb device and connects to upper interfaces hiddev and |
| 795 | 801 | * hidraw */ |
| 796 | 802 | retval = hid_hw_start(hdev, HID_CONNECT_DEFAULT); |
| @@ -101,9 +101,9 @@ struct mt_device { · 100 unmodified lines | ||
| 101 | 101 | unsigned last_slot_field; /* the last field of a slot */ |
| 102 | 102 | unsigned mt_report_id; /* the report ID of the multitouch device */ |
| 103 | 103 | unsigned pen_report_id; /* the report ID of the pen device */ |
| 104 | − __s8 inputmode; /* InputMode HID feature, -1 if non-existent */ | |
| 105 | − __s8 inputmode_index; /* InputMode HID feature index in the report */ | |
| 106 | − __s8 maxcontact_report_id; /* Maximum Contact Number HID feature, | |
| 104 | + __s16 inputmode; /* InputMode HID feature, -1 if non-existent */ | |
| 105 | + __s16 inputmode_index; /* InputMode HID feature index in the report */ | |
| 106 | + __s16 maxcontact_report_id; /* Maximum Contact Number HID feature, | |
| 107 | 107 | -1 if non-existent */ |
| 108 | 108 | __u8 num_received; /* how many contacts we received */ |
| 109 | 109 | __u8 num_expected; /* expected last contact index */ |
| @@ -312,20 +312,18 @@ static void mt_feature_mapping(struct hid_device *hdev, · 202 unmodified lines | ||
| 312 | 312 | struct hid_field *field, struct hid_usage *usage) |
| 313 | 313 | { |
| 314 | 314 | struct mt_device *td = hid_get_drvdata(hdev); |
| 315 | − int i; | |
| 316 | 315 | |
| 317 | 316 | switch (usage->hid) { |
| 318 | 317 | case HID_DG_INPUTMODE: |
| 319 | − td->inputmode = field->report->id; | |
| 320 | − td->inputmode_index = 0; /* has to be updated below */ | |
| 321 | − | |
| 322 | − for (i=0; i < field->maxusage; i++) { | |
| 323 | − if (field->usage[i].hid == usage->hid) { | |
| 324 | − td->inputmode_index = i; | |
| 325 | − break; | |
| 326 | − } | |
| 318 | + /* Ignore if value index is out of bounds. */ | |
| 319 | + if (usage->usage_index >= field->report_count) { | |
| 320 | + dev_err(&hdev->dev, "HID_DG_INPUTMODE out of range\n"); | |
| 321 | + break; | |
| 327 | 322 | } |
| 328 | 323 | |
| 324 | + td->inputmode = field->report->id; | |
| 325 | + td->inputmode_index = usage->usage_index; | |
| 326 | + | |
| 329 | 327 | break; |
| 330 | 328 | case HID_DG_CONTACTMAX: |
| 331 | 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, · 179 unmodified lines | ||
| 511 | 509 | mt_store_field(usage, td, hi); |
| 512 | 510 | return 1; |
| 513 | 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 | 516 | td->cc_index = field->index; |
| 515 | 517 | td->cc_value_index = usage->usage_index; |
| 516 | 518 | return 1; |
| @@ -537,6 +537,10 @@ static int buzz_init(struct hid_device *hdev) · 536 unmodified lines | ||
| 537 | 537 | drv_data = hid_get_drvdata(hdev); |
| 538 | 538 | BUG_ON(!(drv_data->quirks & BUZZ_CONTROLLER)); |
| 539 | 539 | |
| 540 | + /* Validate expected report characteristics. */ | |
| 541 | + if (!hid_validate_values(hdev, HID_OUTPUT_REPORT, 0, 0, 7)) | |
| 542 | + return -ENODEV; | |
| 543 | + | |
| 540 | 544 | buzz = kzalloc(sizeof(*buzz), GFP_KERNEL); |
| 541 | 545 | if (!buzz) { |
| 542 | 546 | hid_err(hdev, "Insufficient memory, cannot allocate driver data\n"); |
| @@ -249,6 +249,11 @@ static int steelseries_srws1_probe(struct hid_device *hdev, · 248 unmodified lines | ||
| 249 | 249 | goto err_free; |
| 250 | 250 | } |
| 251 | 251 | |
| 252 | + if (!hid_validate_values(hdev, HID_OUTPUT_REPORT, 0, 0, 16)) { | |
| 253 | + ret = -ENODEV; | |
| 254 | + goto err_free; | |
| 255 | + } | |
| 256 | + | |
| 252 | 257 | ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); |
| 253 | 258 | if (ret) { |
| 254 | 259 | hid_err(hdev, "hw start failed\n"); |
| @@ -68,21 +68,13 @@ static int zpff_init(struct hid_device *hid) · 67 unmodified lines | ||
| 68 | 68 | struct hid_report *report; |
| 69 | 69 | struct hid_input *hidinput = list_entry(hid->inputs.next, |
| 70 | 70 | struct hid_input, list); |
| 71 | − struct list_head *report_list = | |
| 72 | − &hid->report_enum[HID_OUTPUT_REPORT].report_list; | |
| 73 | 71 | struct input_dev *dev = hidinput->input; |
| 74 | − int error; | |
| 72 | + int i, error; | |
| 75 | 73 | |
| 76 | − if (list_empty(report_list)) { | |
| 77 | − hid_err(hid, "no output report found\n"); | |
| 78 | − return -ENODEV; | |
| 79 | − } | |
| 80 | − | |
| 81 | − report = list_entry(report_list->next, struct hid_report, list); | |
| 82 | − | |
| 83 | − if (report->maxfield < 4) { | |
| 84 | − hid_err(hid, "not enough fields in report\n"); | |
| 85 | − return -ENODEV; | |
| 74 | + for (i = 0; i < 4; i++) { | |
| 75 | + report = hid_validate_values(hid, HID_OUTPUT_REPORT, 0, i, 1); | |
| 76 | + if (!report) | |
| 77 | + return -ENODEV; | |
| 86 | 78 | } |
| 87 | 79 | |
| 88 | 80 | zpff = kzalloc(sizeof(struct zpff_device), GFP_KERNEL); |
| @@ -756,6 +756,10 @@ u8 *hid_alloc_report_buf(struct hid_report *report, gfp_t flags); · 755 unmodified lines | ||
| 756 | 756 | struct hid_device *hid_allocate_device(void); |
| 757 | 757 | struct hid_report *hid_register_report(struct hid_device *device, unsigned type, unsigned id); |
| 758 | 758 | int hid_parse_report(struct hid_device *hid, __u8 *start, unsigned size); |
| 759 | +struct hid_report *hid_validate_values(struct hid_device *hid, | |
| 760 | + unsigned int type, unsigned int id, | |
| 761 | + unsigned int field_index, | |
| 762 | + unsigned int report_counts); | |
| 759 | 763 | int hid_open_report(struct hid_device *device); |
| 760 | 764 | int hid_check_keys_pressed(struct hid_device *hid); |
| 761 | 765 | int hid_connect(struct hid_device *hid, unsigned int connect_mask); |