Skip to content

Commit 84fca9f

Browse files
committed
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
2 parents 03e1261 + 0ccdd9e commit 84fca9f

File tree

13 files changed

+146
-116
lines changed

13 files changed

+146
-116
lines changed

drivers/hid/hid-core.c

Lines changed: 65 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,6 @@ EXPORT_SYMBOL_GPL(hid_register_report);
9494
static struct hid_field *hid_register_field(struct hid_report *report, unsigned usages, unsigned values)
9595
{
9696
struct hid_field *field;
97-
int i;
9897

9998
if (report->maxfield == HID_MAX_FIELDS) {
10099
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
113112
field->value = (s32 *)(field->usage + usages);
114113
field->report = report;
115114

116-
for (i = 0; i < usages; i++)
117-
field->usage[i].usage_index = i;
118-
119115
return field;
120116
}
121117

@@ -226,9 +222,9 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign
226222
{
227223
struct hid_report *report;
228224
struct hid_field *field;
229-
int usages;
225+
unsigned usages;
230226
unsigned offset;
231-
int i;
227+
unsigned i;
232228

233229
report = hid_register_report(parser->device, report_type, parser->global.report_id);
234230
if (!report) {
@@ -255,7 +251,8 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign
255251
if (!parser->local.usage_index) /* Ignore padding fields */
256252
return 0;
257253

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);
259256

260257
field = hid_register_field(report, usages, parser->global.report_count);
261258
if (!field)
@@ -266,13 +263,14 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign
266263
field->application = hid_lookup_collection(parser, HID_COLLECTION_APPLICATION);
267264

268265
for (i = 0; i < usages; i++) {
269-
int j = i;
266+
unsigned j = i;
270267
/* Duplicate the last usage we parsed if we have excess values */
271268
if (i >= parser->local.usage_index)
272269
j = parser->local.usage_index - 1;
273270
field->usage[i].hid = parser->local.usage[j];
274271
field->usage[i].collection_index =
275272
parser->local.collection_index[j];
273+
field->usage[i].usage_index = i;
276274
}
277275

278276
field->maxusage = usages;
@@ -801,6 +799,64 @@ int hid_parse_report(struct hid_device *hid, __u8 *start, unsigned size)
801799
}
802800
EXPORT_SYMBOL_GPL(hid_parse_report);
803801

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+
804860
/**
805861
* hid_open_report - open a driver-specific device report
806862
*
@@ -1296,7 +1352,7 @@ int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size,
12961352
goto out;
12971353
}
12981354

1299-
if (hid->claimed != HID_CLAIMED_HIDRAW) {
1355+
if (hid->claimed != HID_CLAIMED_HIDRAW && report->maxfield) {
13001356
for (a = 0; a < report->maxfield; a++)
13011357
hid_input_field(hid, report->field[a], cdata, interrupt);
13021358
hdrv = hid->driver;

drivers/hid/hid-input.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -485,6 +485,10 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
485485
if (field->flags & HID_MAIN_ITEM_CONSTANT)
486486
goto ignore;
487487

488+
/* Ignore if report count is out of bounds. */
489+
if (field->report_count < 1)
490+
goto ignore;
491+
488492
/* only LED usages are supported in output fields */
489493
if (field->report_type == HID_OUTPUT_REPORT &&
490494
(usage->hid & HID_USAGE_PAGE) != HID_UP_LED) {
@@ -1236,7 +1240,11 @@ static void report_features(struct hid_device *hid)
12361240

12371241
rep_enum = &hid->report_enum[HID_FEATURE_REPORT];
12381242
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+
12401248
for (j = 0; j < rep->field[i]->maxusage; j++) {
12411249
/* Verify if Battery Strength feature is available */
12421250
hidinput_setup_battery(hid, HID_FEATURE_REPORT, rep->field[i]);
@@ -1245,6 +1253,7 @@ static void report_features(struct hid_device *hid)
12451253
drv->feature_mapping(hid, rep->field[i],
12461254
rep->field[i]->usage + j);
12471255
}
1256+
}
12481257
}
12491258

12501259
static struct hid_input *hidinput_allocate(struct hid_device *hid)

drivers/hid/hid-lenovo-tpkbd.c

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,15 @@ static int tpkbd_probe_tp(struct hid_device *hdev)
339339
struct tpkbd_data_pointer *data_pointer;
340340
size_t name_sz = strlen(dev_name(dev)) + 16;
341341
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;
343351

344352
if (sysfs_create_group(&hdev->dev.kobj,
345353
&tpkbd_attr_group_pointer)) {
@@ -406,22 +414,27 @@ static int tpkbd_probe(struct hid_device *hdev,
406414
ret = hid_parse(hdev);
407415
if (ret) {
408416
hid_err(hdev, "hid_parse failed\n");
409-
goto err_free;
417+
goto err;
410418
}
411419

412420
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
413421
if (ret) {
414422
hid_err(hdev, "hid_hw_start failed\n");
415-
goto err_free;
423+
goto err;
416424
}
417425

418426
uhdev = (struct usbhid_device *) hdev->driver_data;
419427

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+
}
422433

423434
return 0;
424-
err_free:
435+
err_hid:
436+
hid_hw_stop(hdev);
437+
err:
425438
return ret;
426439
}
427440

drivers/hid/hid-lg2ff.c

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -64,26 +64,13 @@ int lg2ff_init(struct hid_device *hid)
6464
struct hid_report *report;
6565
struct hid_input *hidinput = list_entry(hid->inputs.next,
6666
struct hid_input, list);
67-
struct list_head *report_list =
68-
&hid->report_enum[HID_OUTPUT_REPORT].report_list;
6967
struct input_dev *dev = hidinput->input;
7068
int error;
7169

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)
7473
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-
}
8774

8875
lg2ff = kmalloc(sizeof(struct lg2ff_device), GFP_KERNEL);
8976
if (!lg2ff)

drivers/hid/hid-lg3ff.c

Lines changed: 6 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,11 @@ static int hid_lg3ff_play(struct input_dev *dev, void *data,
6666
int x, y;
6767

6868
/*
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.
7171
*/
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);
7374

7475
switch (effect->type) {
7576
case FF_CONSTANT:
@@ -129,32 +130,14 @@ static const signed short ff3_joystick_ac[] = {
129130
int lg3ff_init(struct hid_device *hid)
130131
{
131132
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;
133133
struct input_dev *dev = hidinput->input;
134-
struct hid_report *report;
135-
struct hid_field *field;
136134
const signed short *ff_bits = ff3_joystick_ac;
137135
int error;
138136
int i;
139137

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-
146138
/* 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;
158141

159142
/* Assume single fixed device G940 */
160143
for (i = 0; ff_bits[i] >= 0; i++)

drivers/hid/hid-lg4ff.c

Lines changed: 1 addition & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -484,34 +484,16 @@ static enum led_brightness lg4ff_led_get_brightness(struct led_classdev *led_cde
484484
int lg4ff_init(struct hid_device *hid)
485485
{
486486
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;
488487
struct input_dev *dev = hidinput->input;
489-
struct hid_report *report;
490-
struct hid_field *field;
491488
struct lg4ff_device_entry *entry;
492489
struct lg_drv_data *drv_data;
493490
struct usb_device_descriptor *udesc;
494491
int error, i, j;
495492
__u16 bcdDevice, rev_maj, rev_min;
496493

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-
503494
/* 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))
507496
return -1;
508-
}
509-
510-
field = report->field[0];
511-
if (!field) {
512-
hid_err(hid, "NULL field\n");
513-
return -1;
514-
}
515497

516498
/* Check what wheel has been connected */
517499
for (i = 0; i < ARRAY_SIZE(lg4ff_devices); i++) {

drivers/hid/hid-lgff.c

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -128,27 +128,14 @@ static void hid_lgff_set_autocenter(struct input_dev *dev, u16 magnitude)
128128
int lgff_init(struct hid_device* hid)
129129
{
130130
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;
132131
struct input_dev *dev = hidinput->input;
133-
struct hid_report *report;
134-
struct hid_field *field;
135132
const signed short *ff_bits = ff_joystick;
136133
int error;
137134
int i;
138135

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-
145136
/* 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;
152139

153140
for (i = 0; i < ARRAY_SIZE(devices); i++) {
154141
if (dev->id.vendor == devices[i].idVendor &&

drivers/hid/hid-logitech-dj.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -461,7 +461,7 @@ static int logi_dj_recv_send_report(struct dj_receiver_dev *djrcv_dev,
461461
struct hid_report *report;
462462
struct hid_report_enum *output_report_enum;
463463
u8 *data = (u8 *)(&dj_report->device_index);
464-
int i;
464+
unsigned int i;
465465

466466
output_report_enum = &hdev->report_enum[HID_OUTPUT_REPORT];
467467
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,
471471
return -ENODEV;
472472
}
473473

474-
for (i = 0; i < report->field[0]->report_count; i++)
474+
for (i = 0; i < DJREPORT_SHORT_LENGTH - 1; i++)
475475
report->field[0]->value[i] = data[i];
476476

477477
hid_hw_request(hdev, report, HID_REQ_SET_REPORT);
@@ -791,6 +791,12 @@ static int logi_dj_probe(struct hid_device *hdev,
791791
goto hid_parse_fail;
792792
}
793793

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+
794800
/* Starts the usb device and connects to upper interfaces hiddev and
795801
* hidraw */
796802
retval = hid_hw_start(hdev, HID_CONNECT_DEFAULT);

0 commit comments

Comments
 (0)