diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-09-17 21:54:05 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-09-17 21:54:05 -0400 |
commit | 84fca9f38c5d646e95cdeef70e41cf15db549b95 (patch) | |
tree | c904715c9b70a2f0716c84931e2d58b1a226a1e0 | |
parent | 03e1261778cca782d41a3d8e3945ca88cf93e01e (diff) | |
parent | 0ccdd9e7476680c16113131264ad6597bd10299d (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid
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
-rw-r--r-- | drivers/hid/hid-core.c | 74 | ||||
-rw-r--r-- | drivers/hid/hid-input.c | 11 | ||||
-rw-r--r-- | drivers/hid/hid-lenovo-tpkbd.c | 25 | ||||
-rw-r--r-- | drivers/hid/hid-lg2ff.c | 19 | ||||
-rw-r--r-- | drivers/hid/hid-lg3ff.c | 29 | ||||
-rw-r--r-- | drivers/hid/hid-lg4ff.c | 20 | ||||
-rw-r--r-- | drivers/hid/hid-lgff.c | 17 | ||||
-rw-r--r-- | drivers/hid/hid-logitech-dj.c | 10 | ||||
-rw-r--r-- | drivers/hid/hid-multitouch.c | 26 | ||||
-rw-r--r-- | drivers/hid/hid-sony.c | 4 | ||||
-rw-r--r-- | drivers/hid/hid-steelseries.c | 5 | ||||
-rw-r--r-- | drivers/hid/hid-zpff.c | 18 | ||||
-rw-r--r-- | include/linux/hid.h | 4 |
13 files changed, 146 insertions, 116 deletions
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index ae88a97f976e..b8470b1a10fe 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c | |||
@@ -94,7 +94,6 @@ EXPORT_SYMBOL_GPL(hid_register_report); | |||
94 | static struct hid_field *hid_register_field(struct hid_report *report, unsigned usages, unsigned values) | 94 | static struct hid_field *hid_register_field(struct hid_report *report, unsigned usages, unsigned values) |
95 | { | 95 | { |
96 | struct hid_field *field; | 96 | struct hid_field *field; |
97 | int i; | ||
98 | 97 | ||
99 | if (report->maxfield == HID_MAX_FIELDS) { | 98 | if (report->maxfield == HID_MAX_FIELDS) { |
100 | hid_err(report->device, "too many fields in report\n"); | 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 | |||
113 | field->value = (s32 *)(field->usage + usages); | 112 | field->value = (s32 *)(field->usage + usages); |
114 | field->report = report; | 113 | field->report = report; |
115 | 114 | ||
116 | for (i = 0; i < usages; i++) | ||
117 | field->usage[i].usage_index = i; | ||
118 | |||
119 | return field; | 115 | return field; |
120 | } | 116 | } |
121 | 117 | ||
@@ -226,9 +222,9 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign | |||
226 | { | 222 | { |
227 | struct hid_report *report; | 223 | struct hid_report *report; |
228 | struct hid_field *field; | 224 | struct hid_field *field; |
229 | int usages; | 225 | unsigned usages; |
230 | unsigned offset; | 226 | unsigned offset; |
231 | int i; | 227 | unsigned i; |
232 | 228 | ||
233 | report = hid_register_report(parser->device, report_type, parser->global.report_id); | 229 | report = hid_register_report(parser->device, report_type, parser->global.report_id); |
234 | if (!report) { | 230 | if (!report) { |
@@ -255,7 +251,8 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign | |||
255 | if (!parser->local.usage_index) /* Ignore padding fields */ | 251 | if (!parser->local.usage_index) /* Ignore padding fields */ |
256 | return 0; | 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 | field = hid_register_field(report, usages, parser->global.report_count); | 257 | field = hid_register_field(report, usages, parser->global.report_count); |
261 | if (!field) | 258 | if (!field) |
@@ -266,13 +263,14 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign | |||
266 | field->application = hid_lookup_collection(parser, HID_COLLECTION_APPLICATION); | 263 | field->application = hid_lookup_collection(parser, HID_COLLECTION_APPLICATION); |
267 | 264 | ||
268 | for (i = 0; i < usages; i++) { | 265 | for (i = 0; i < usages; i++) { |
269 | int j = i; | 266 | unsigned j = i; |
270 | /* Duplicate the last usage we parsed if we have excess values */ | 267 | /* Duplicate the last usage we parsed if we have excess values */ |
271 | if (i >= parser->local.usage_index) | 268 | if (i >= parser->local.usage_index) |
272 | j = parser->local.usage_index - 1; | 269 | j = parser->local.usage_index - 1; |
273 | field->usage[i].hid = parser->local.usage[j]; | 270 | field->usage[i].hid = parser->local.usage[j]; |
274 | field->usage[i].collection_index = | 271 | field->usage[i].collection_index = |
275 | parser->local.collection_index[j]; | 272 | parser->local.collection_index[j]; |
273 | field->usage[i].usage_index = i; | ||
276 | } | 274 | } |
277 | 275 | ||
278 | field->maxusage = usages; | 276 | field->maxusage = usages; |
@@ -801,6 +799,64 @@ int hid_parse_report(struct hid_device *hid, __u8 *start, unsigned size) | |||
801 | } | 799 | } |
802 | EXPORT_SYMBOL_GPL(hid_parse_report); | 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 | * hid_open_report - open a driver-specific device report | 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, | |||
1296 | goto out; | 1352 | goto out; |
1297 | } | 1353 | } |
1298 | 1354 | ||
1299 | if (hid->claimed != HID_CLAIMED_HIDRAW) { | 1355 | if (hid->claimed != HID_CLAIMED_HIDRAW && report->maxfield) { |
1300 | for (a = 0; a < report->maxfield; a++) | 1356 | for (a = 0; a < report->maxfield; a++) |
1301 | hid_input_field(hid, report->field[a], cdata, interrupt); | 1357 | hid_input_field(hid, report->field[a], cdata, interrupt); |
1302 | hdrv = hid->driver; | 1358 | hdrv = hid->driver; |
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index b420f4a0fd28..8741d953dcc8 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c | |||
@@ -485,6 +485,10 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel | |||
485 | if (field->flags & HID_MAIN_ITEM_CONSTANT) | 485 | if (field->flags & HID_MAIN_ITEM_CONSTANT) |
486 | goto ignore; | 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 | /* only LED usages are supported in output fields */ | 492 | /* only LED usages are supported in output fields */ |
489 | if (field->report_type == HID_OUTPUT_REPORT && | 493 | if (field->report_type == HID_OUTPUT_REPORT && |
490 | (usage->hid & HID_USAGE_PAGE) != HID_UP_LED) { | 494 | (usage->hid & HID_USAGE_PAGE) != HID_UP_LED) { |
@@ -1236,7 +1240,11 @@ static void report_features(struct hid_device *hid) | |||
1236 | 1240 | ||
1237 | rep_enum = &hid->report_enum[HID_FEATURE_REPORT]; | 1241 | rep_enum = &hid->report_enum[HID_FEATURE_REPORT]; |
1238 | list_for_each_entry(rep, &rep_enum->report_list, list) | 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 | for (j = 0; j < rep->field[i]->maxusage; j++) { | 1248 | for (j = 0; j < rep->field[i]->maxusage; j++) { |
1241 | /* Verify if Battery Strength feature is available */ | 1249 | /* Verify if Battery Strength feature is available */ |
1242 | hidinput_setup_battery(hid, HID_FEATURE_REPORT, rep->field[i]); | 1250 | hidinput_setup_battery(hid, HID_FEATURE_REPORT, rep->field[i]); |
@@ -1245,6 +1253,7 @@ static void report_features(struct hid_device *hid) | |||
1245 | drv->feature_mapping(hid, rep->field[i], | 1253 | drv->feature_mapping(hid, rep->field[i], |
1246 | rep->field[i]->usage + j); | 1254 | rep->field[i]->usage + j); |
1247 | } | 1255 | } |
1256 | } | ||
1248 | } | 1257 | } |
1249 | 1258 | ||
1250 | static struct hid_input *hidinput_allocate(struct hid_device *hid) | 1259 | static struct hid_input *hidinput_allocate(struct hid_device *hid) |
diff --git a/drivers/hid/hid-lenovo-tpkbd.c b/drivers/hid/hid-lenovo-tpkbd.c index 07837f5a4eb8..31cf29a6ba17 100644 --- a/drivers/hid/hid-lenovo-tpkbd.c +++ b/drivers/hid/hid-lenovo-tpkbd.c | |||
@@ -339,7 +339,15 @@ static int tpkbd_probe_tp(struct hid_device *hdev) | |||
339 | struct tpkbd_data_pointer *data_pointer; | 339 | struct tpkbd_data_pointer *data_pointer; |
340 | size_t name_sz = strlen(dev_name(dev)) + 16; | 340 | size_t name_sz = strlen(dev_name(dev)) + 16; |
341 | char *name_mute, *name_micmute; | 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 | if (sysfs_create_group(&hdev->dev.kobj, | 352 | if (sysfs_create_group(&hdev->dev.kobj, |
345 | &tpkbd_attr_group_pointer)) { | 353 | &tpkbd_attr_group_pointer)) { |
@@ -406,22 +414,27 @@ static int tpkbd_probe(struct hid_device *hdev, | |||
406 | ret = hid_parse(hdev); | 414 | ret = hid_parse(hdev); |
407 | if (ret) { | 415 | if (ret) { |
408 | hid_err(hdev, "hid_parse failed\n"); | 416 | hid_err(hdev, "hid_parse failed\n"); |
409 | goto err_free; | 417 | goto err; |
410 | } | 418 | } |
411 | 419 | ||
412 | ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); | 420 | ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); |
413 | if (ret) { | 421 | if (ret) { |
414 | hid_err(hdev, "hid_hw_start failed\n"); | 422 | hid_err(hdev, "hid_hw_start failed\n"); |
415 | goto err_free; | 423 | goto err; |
416 | } | 424 | } |
417 | 425 | ||
418 | uhdev = (struct usbhid_device *) hdev->driver_data; | 426 | uhdev = (struct usbhid_device *) hdev->driver_data; |
419 | 427 | ||
420 | if (uhdev->ifnum == 1) | 428 | if (uhdev->ifnum == 1) { |
421 | return tpkbd_probe_tp(hdev); | 429 | ret = tpkbd_probe_tp(hdev); |
430 | if (ret) | ||
431 | goto err_hid; | ||
432 | } | ||
422 | 433 | ||
423 | return 0; | 434 | return 0; |
424 | err_free: | 435 | err_hid: |
436 | hid_hw_stop(hdev); | ||
437 | err: | ||
425 | return ret; | 438 | return ret; |
426 | } | 439 | } |
427 | 440 | ||
diff --git a/drivers/hid/hid-lg2ff.c b/drivers/hid/hid-lg2ff.c index b3cd1507dda2..1a42eaa6ca02 100644 --- a/drivers/hid/hid-lg2ff.c +++ b/drivers/hid/hid-lg2ff.c | |||
@@ -64,26 +64,13 @@ int lg2ff_init(struct hid_device *hid) | |||
64 | struct hid_report *report; | 64 | struct hid_report *report; |
65 | struct hid_input *hidinput = list_entry(hid->inputs.next, | 65 | struct hid_input *hidinput = list_entry(hid->inputs.next, |
66 | struct hid_input, list); | 66 | struct hid_input, list); |
67 | struct list_head *report_list = | ||
68 | &hid->report_enum[HID_OUTPUT_REPORT].report_list; | ||
69 | struct input_dev *dev = hidinput->input; | 67 | struct input_dev *dev = hidinput->input; |
70 | int error; | 68 | int error; |
71 | 69 | ||
72 | if (list_empty(report_list)) { | 70 | /* Check that the report looks ok */ |
73 | hid_err(hid, "no output report found\n"); | 71 | report = hid_validate_values(hid, HID_OUTPUT_REPORT, 0, 0, 7); |
72 | if (!report) | ||
74 | return -ENODEV; | 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 | lg2ff = kmalloc(sizeof(struct lg2ff_device), GFP_KERNEL); | 75 | lg2ff = kmalloc(sizeof(struct lg2ff_device), GFP_KERNEL); |
89 | if (!lg2ff) | 76 | if (!lg2ff) |
diff --git a/drivers/hid/hid-lg3ff.c b/drivers/hid/hid-lg3ff.c index e52f181f6aa1..8c2da183d3bc 100644 --- a/drivers/hid/hid-lg3ff.c +++ b/drivers/hid/hid-lg3ff.c | |||
@@ -66,10 +66,11 @@ static int hid_lg3ff_play(struct input_dev *dev, void *data, | |||
66 | int x, y; | 66 | int x, y; |
67 | 67 | ||
68 | /* | 68 | /* |
69 | * Maxusage should always be 63 (maximum fields) | 69 | * Available values in the field should always be 63, but we only use up to |
70 | * likely a better way to ensure this data is clean | 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 | switch (effect->type) { | 75 | switch (effect->type) { |
75 | case FF_CONSTANT: | 76 | case FF_CONSTANT: |
@@ -129,32 +130,14 @@ static const signed short ff3_joystick_ac[] = { | |||
129 | int lg3ff_init(struct hid_device *hid) | 130 | int lg3ff_init(struct hid_device *hid) |
130 | { | 131 | { |
131 | struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list); | 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 | struct input_dev *dev = hidinput->input; | 133 | struct input_dev *dev = hidinput->input; |
134 | struct hid_report *report; | ||
135 | struct hid_field *field; | ||
136 | const signed short *ff_bits = ff3_joystick_ac; | 134 | const signed short *ff_bits = ff3_joystick_ac; |
137 | int error; | 135 | int error; |
138 | int i; | 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 | /* Check that the report looks ok */ | 138 | /* Check that the report looks ok */ |
147 | report = list_entry(report_list->next, struct hid_report, list); | 139 | if (!hid_validate_values(hid, HID_OUTPUT_REPORT, 0, 0, 35)) |
148 | if (!report) { | 140 | return -ENODEV; |
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 | } | ||
158 | 141 | ||
159 | /* Assume single fixed device G940 */ | 142 | /* Assume single fixed device G940 */ |
160 | for (i = 0; ff_bits[i] >= 0; i++) | 143 | for (i = 0; ff_bits[i] >= 0; i++) |
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++) { |
diff --git a/drivers/hid/hid-lgff.c b/drivers/hid/hid-lgff.c index d7ea8c845b40..e1394af0ae7b 100644 --- a/drivers/hid/hid-lgff.c +++ b/drivers/hid/hid-lgff.c | |||
@@ -128,27 +128,14 @@ static void hid_lgff_set_autocenter(struct input_dev *dev, u16 magnitude) | |||
128 | int lgff_init(struct hid_device* hid) | 128 | int lgff_init(struct hid_device* hid) |
129 | { | 129 | { |
130 | struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list); | 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 | struct input_dev *dev = hidinput->input; | 131 | struct input_dev *dev = hidinput->input; |
133 | struct hid_report *report; | ||
134 | struct hid_field *field; | ||
135 | const signed short *ff_bits = ff_joystick; | 132 | const signed short *ff_bits = ff_joystick; |
136 | int error; | 133 | int error; |
137 | int i; | 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 | /* Check that the report looks ok */ | 136 | /* Check that the report looks ok */ |
146 | report = list_entry(report_list->next, struct hid_report, list); | 137 | if (!hid_validate_values(hid, HID_OUTPUT_REPORT, 0, 0, 7)) |
147 | field = report->field[0]; | 138 | return -ENODEV; |
148 | if (!field) { | ||
149 | hid_err(hid, "NULL field\n"); | ||
150 | return -1; | ||
151 | } | ||
152 | 139 | ||
153 | for (i = 0; i < ARRAY_SIZE(devices); i++) { | 140 | for (i = 0; i < ARRAY_SIZE(devices); i++) { |
154 | if (dev->id.vendor == devices[i].idVendor && | 141 | if (dev->id.vendor == devices[i].idVendor && |
diff --git a/drivers/hid/hid-logitech-dj.c b/drivers/hid/hid-logitech-dj.c index 7800b1410562..2e5302462efb 100644 --- a/drivers/hid/hid-logitech-dj.c +++ b/drivers/hid/hid-logitech-dj.c | |||
@@ -461,7 +461,7 @@ static int logi_dj_recv_send_report(struct dj_receiver_dev *djrcv_dev, | |||
461 | struct hid_report *report; | 461 | struct hid_report *report; |
462 | struct hid_report_enum *output_report_enum; | 462 | struct hid_report_enum *output_report_enum; |
463 | u8 *data = (u8 *)(&dj_report->device_index); | 463 | u8 *data = (u8 *)(&dj_report->device_index); |
464 | int i; | 464 | unsigned int i; |
465 | 465 | ||
466 | output_report_enum = &hdev->report_enum[HID_OUTPUT_REPORT]; | 466 | output_report_enum = &hdev->report_enum[HID_OUTPUT_REPORT]; |
467 | report = output_report_enum->report_id_hash[REPORT_ID_DJ_SHORT]; | 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, | |||
471 | return -ENODEV; | 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 | report->field[0]->value[i] = data[i]; | 475 | report->field[0]->value[i] = data[i]; |
476 | 476 | ||
477 | hid_hw_request(hdev, report, HID_REQ_SET_REPORT); | 477 | hid_hw_request(hdev, report, HID_REQ_SET_REPORT); |
@@ -791,6 +791,12 @@ static int logi_dj_probe(struct hid_device *hdev, | |||
791 | goto hid_parse_fail; | 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 | /* Starts the usb device and connects to upper interfaces hiddev and | 800 | /* Starts the usb device and connects to upper interfaces hiddev and |
795 | * hidraw */ | 801 | * hidraw */ |
796 | retval = hid_hw_start(hdev, HID_CONNECT_DEFAULT); | 802 | retval = hid_hw_start(hdev, HID_CONNECT_DEFAULT); |
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; |
diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index 30dbb6b40bbf..b18320db5f7d 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c | |||
@@ -537,6 +537,10 @@ static int buzz_init(struct hid_device *hdev) | |||
537 | drv_data = hid_get_drvdata(hdev); | 537 | drv_data = hid_get_drvdata(hdev); |
538 | BUG_ON(!(drv_data->quirks & BUZZ_CONTROLLER)); | 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 | buzz = kzalloc(sizeof(*buzz), GFP_KERNEL); | 544 | buzz = kzalloc(sizeof(*buzz), GFP_KERNEL); |
541 | if (!buzz) { | 545 | if (!buzz) { |
542 | hid_err(hdev, "Insufficient memory, cannot allocate driver data\n"); | 546 | hid_err(hdev, "Insufficient memory, cannot allocate driver data\n"); |
diff --git a/drivers/hid/hid-steelseries.c b/drivers/hid/hid-steelseries.c index d16491192112..29f328f411fb 100644 --- a/drivers/hid/hid-steelseries.c +++ b/drivers/hid/hid-steelseries.c | |||
@@ -249,6 +249,11 @@ static int steelseries_srws1_probe(struct hid_device *hdev, | |||
249 | goto err_free; | 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 | ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); | 257 | ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); |
253 | if (ret) { | 258 | if (ret) { |
254 | hid_err(hdev, "hw start failed\n"); | 259 | hid_err(hdev, "hw start failed\n"); |
diff --git a/drivers/hid/hid-zpff.c b/drivers/hid/hid-zpff.c index 6ec28a37c146..a29756c6ca02 100644 --- a/drivers/hid/hid-zpff.c +++ b/drivers/hid/hid-zpff.c | |||
@@ -68,21 +68,13 @@ static int zpff_init(struct hid_device *hid) | |||
68 | struct hid_report *report; | 68 | struct hid_report *report; |
69 | struct hid_input *hidinput = list_entry(hid->inputs.next, | 69 | struct hid_input *hidinput = list_entry(hid->inputs.next, |
70 | struct hid_input, list); | 70 | struct hid_input, list); |
71 | struct list_head *report_list = | ||
72 | &hid->report_enum[HID_OUTPUT_REPORT].report_list; | ||
73 | struct input_dev *dev = hidinput->input; | 71 | struct input_dev *dev = hidinput->input; |
74 | int error; | 72 | int i, error; |
75 | 73 | ||
76 | if (list_empty(report_list)) { | 74 | for (i = 0; i < 4; i++) { |
77 | hid_err(hid, "no output report found\n"); | 75 | report = hid_validate_values(hid, HID_OUTPUT_REPORT, 0, i, 1); |
78 | return -ENODEV; | 76 | if (!report) |
79 | } | 77 | return -ENODEV; |
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; | ||
86 | } | 78 | } |
87 | 79 | ||
88 | zpff = kzalloc(sizeof(struct zpff_device), GFP_KERNEL); | 80 | zpff = kzalloc(sizeof(struct zpff_device), GFP_KERNEL); |
diff --git a/include/linux/hid.h b/include/linux/hid.h index ee1ffc5e19c9..31b9d299ef6c 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h | |||
@@ -756,6 +756,10 @@ u8 *hid_alloc_report_buf(struct hid_report *report, gfp_t flags); | |||
756 | struct hid_device *hid_allocate_device(void); | 756 | struct hid_device *hid_allocate_device(void); |
757 | struct hid_report *hid_register_report(struct hid_device *device, unsigned type, unsigned id); | 757 | struct hid_report *hid_register_report(struct hid_device *device, unsigned type, unsigned id); |
758 | int hid_parse_report(struct hid_device *hid, __u8 *start, unsigned size); | 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 | int hid_open_report(struct hid_device *device); | 763 | int hid_open_report(struct hid_device *device); |
760 | int hid_check_keys_pressed(struct hid_device *hid); | 764 | int hid_check_keys_pressed(struct hid_device *hid); |
761 | int hid_connect(struct hid_device *hid, unsigned int connect_mask); | 765 | int hid_connect(struct hid_device *hid, unsigned int connect_mask); |