Commit 84fca9f3 authored by Linus Torvalds's avatar Linus Torvalds

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
parents 03e12617 0ccdd9e7
...@@ -94,7 +94,6 @@ EXPORT_SYMBOL_GPL(hid_register_report); ...@@ -94,7 +94,6 @@ EXPORT_SYMBOL_GPL(hid_register_report);
static struct hid_field *hid_register_field(struct hid_report *report, unsigned usages, unsigned values) static struct hid_field *hid_register_field(struct hid_report *report, unsigned usages, unsigned values)
{ {
struct hid_field *field; struct hid_field *field;
int i;
if (report->maxfield == HID_MAX_FIELDS) { if (report->maxfield == HID_MAX_FIELDS) {
hid_err(report->device, "too many fields in report\n"); 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,9 +112,6 @@ static struct hid_field *hid_register_field(struct hid_report *report, unsigned
field->value = (s32 *)(field->usage + usages); field->value = (s32 *)(field->usage + usages);
field->report = report; field->report = report;
for (i = 0; i < usages; i++)
field->usage[i].usage_index = i;
return field; return field;
} }
...@@ -226,9 +222,9 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign ...@@ -226,9 +222,9 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign
{ {
struct hid_report *report; struct hid_report *report;
struct hid_field *field; struct hid_field *field;
int usages; unsigned usages;
unsigned offset; unsigned offset;
int i; unsigned i;
report = hid_register_report(parser->device, report_type, parser->global.report_id); report = hid_register_report(parser->device, report_type, parser->global.report_id);
if (!report) { if (!report) {
...@@ -255,7 +251,8 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign ...@@ -255,7 +251,8 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign
if (!parser->local.usage_index) /* Ignore padding fields */ if (!parser->local.usage_index) /* Ignore padding fields */
return 0; return 0;
usages = max_t(int, parser->local.usage_index, parser->global.report_count); usages = max_t(unsigned, parser->local.usage_index,
parser->global.report_count);
field = hid_register_field(report, usages, parser->global.report_count); field = hid_register_field(report, usages, parser->global.report_count);
if (!field) if (!field)
...@@ -266,13 +263,14 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign ...@@ -266,13 +263,14 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign
field->application = hid_lookup_collection(parser, HID_COLLECTION_APPLICATION); field->application = hid_lookup_collection(parser, HID_COLLECTION_APPLICATION);
for (i = 0; i < usages; i++) { for (i = 0; i < usages; i++) {
int j = i; unsigned j = i;
/* Duplicate the last usage we parsed if we have excess values */ /* Duplicate the last usage we parsed if we have excess values */
if (i >= parser->local.usage_index) if (i >= parser->local.usage_index)
j = parser->local.usage_index - 1; j = parser->local.usage_index - 1;
field->usage[i].hid = parser->local.usage[j]; field->usage[i].hid = parser->local.usage[j];
field->usage[i].collection_index = field->usage[i].collection_index =
parser->local.collection_index[j]; parser->local.collection_index[j];
field->usage[i].usage_index = i;
} }
field->maxusage = usages; field->maxusage = usages;
...@@ -801,6 +799,64 @@ int hid_parse_report(struct hid_device *hid, __u8 *start, unsigned size) ...@@ -801,6 +799,64 @@ int hid_parse_report(struct hid_device *hid, __u8 *start, unsigned size)
} }
EXPORT_SYMBOL_GPL(hid_parse_report); EXPORT_SYMBOL_GPL(hid_parse_report);
static const char * const hid_report_names[] = {
"HID_INPUT_REPORT",
"HID_OUTPUT_REPORT",
"HID_FEATURE_REPORT",
};
/**
* hid_validate_values - validate existing device report's value indexes
*
* @device: hid device
* @type: which report type to examine
* @id: which report ID to examine (0 for first)
* @field_index: which report field to examine
* @report_counts: expected number of values
*
* Validate the number of values in a given field of a given report, after
* parsing.
*/
struct hid_report *hid_validate_values(struct hid_device *hid,
unsigned int type, unsigned int id,
unsigned int field_index,
unsigned int report_counts)
{
struct hid_report *report;
if (type > HID_FEATURE_REPORT) {
hid_err(hid, "invalid HID report type %u\n", type);
return NULL;
}
if (id >= HID_MAX_IDS) {
hid_err(hid, "invalid HID report id %u\n", id);
return NULL;
}
/*
* Explicitly not using hid_get_report() here since it depends on
* ->numbered being checked, which may not always be the case when
* drivers go to access report values.
*/
report = hid->report_enum[type].report_id_hash[id];
if (!report) {
hid_err(hid, "missing %s %u\n", hid_report_names[type], id);
return NULL;
}
if (report->maxfield <= field_index) {
hid_err(hid, "not enough fields in %s %u\n",
hid_report_names[type], id);
return NULL;
}
if (report->field[field_index]->report_count < report_counts) {
hid_err(hid, "not enough values in %s %u field %u\n",
hid_report_names[type], id, field_index);
return NULL;
}
return report;
}
EXPORT_SYMBOL_GPL(hid_validate_values);
/** /**
* hid_open_report - open a driver-specific device report * hid_open_report - open a driver-specific device report
* *
...@@ -1296,7 +1352,7 @@ int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size, ...@@ -1296,7 +1352,7 @@ int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size,
goto out; goto out;
} }
if (hid->claimed != HID_CLAIMED_HIDRAW) { if (hid->claimed != HID_CLAIMED_HIDRAW && report->maxfield) {
for (a = 0; a < report->maxfield; a++) for (a = 0; a < report->maxfield; a++)
hid_input_field(hid, report->field[a], cdata, interrupt); hid_input_field(hid, report->field[a], cdata, interrupt);
hdrv = hid->driver; hdrv = hid->driver;
......
...@@ -485,6 +485,10 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel ...@@ -485,6 +485,10 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
if (field->flags & HID_MAIN_ITEM_CONSTANT) if (field->flags & HID_MAIN_ITEM_CONSTANT)
goto ignore; goto ignore;
/* Ignore if report count is out of bounds. */
if (field->report_count < 1)
goto ignore;
/* only LED usages are supported in output fields */ /* only LED usages are supported in output fields */
if (field->report_type == HID_OUTPUT_REPORT && if (field->report_type == HID_OUTPUT_REPORT &&
(usage->hid & HID_USAGE_PAGE) != HID_UP_LED) { (usage->hid & HID_USAGE_PAGE) != HID_UP_LED) {
...@@ -1236,7 +1240,11 @@ static void report_features(struct hid_device *hid) ...@@ -1236,7 +1240,11 @@ static void report_features(struct hid_device *hid)
rep_enum = &hid->report_enum[HID_FEATURE_REPORT]; rep_enum = &hid->report_enum[HID_FEATURE_REPORT];
list_for_each_entry(rep, &rep_enum->report_list, list) list_for_each_entry(rep, &rep_enum->report_list, list)
for (i = 0; i < rep->maxfield; i++) for (i = 0; i < rep->maxfield; i++) {
/* Ignore if report count is out of bounds. */
if (rep->field[i]->report_count < 1)
continue;
for (j = 0; j < rep->field[i]->maxusage; j++) { for (j = 0; j < rep->field[i]->maxusage; j++) {
/* Verify if Battery Strength feature is available */ /* Verify if Battery Strength feature is available */
hidinput_setup_battery(hid, HID_FEATURE_REPORT, rep->field[i]); hidinput_setup_battery(hid, HID_FEATURE_REPORT, rep->field[i]);
...@@ -1245,6 +1253,7 @@ static void report_features(struct hid_device *hid) ...@@ -1245,6 +1253,7 @@ static void report_features(struct hid_device *hid)
drv->feature_mapping(hid, rep->field[i], drv->feature_mapping(hid, rep->field[i],
rep->field[i]->usage + j); rep->field[i]->usage + j);
} }
}
} }
static struct hid_input *hidinput_allocate(struct hid_device *hid) static struct hid_input *hidinput_allocate(struct hid_device *hid)
......
...@@ -339,7 +339,15 @@ static int tpkbd_probe_tp(struct hid_device *hdev) ...@@ -339,7 +339,15 @@ static int tpkbd_probe_tp(struct hid_device *hdev)
struct tpkbd_data_pointer *data_pointer; struct tpkbd_data_pointer *data_pointer;
size_t name_sz = strlen(dev_name(dev)) + 16; size_t name_sz = strlen(dev_name(dev)) + 16;
char *name_mute, *name_micmute; char *name_mute, *name_micmute;
int ret; int i, ret;
/* Validate required reports. */
for (i = 0; i < 4; i++) {
if (!hid_validate_values(hdev, HID_FEATURE_REPORT, 4, i, 1))
return -ENODEV;
}
if (!hid_validate_values(hdev, HID_OUTPUT_REPORT, 3, 0, 2))
return -ENODEV;
if (sysfs_create_group(&hdev->dev.kobj, if (sysfs_create_group(&hdev->dev.kobj,
&tpkbd_attr_group_pointer)) { &tpkbd_attr_group_pointer)) {
...@@ -406,22 +414,27 @@ static int tpkbd_probe(struct hid_device *hdev, ...@@ -406,22 +414,27 @@ static int tpkbd_probe(struct hid_device *hdev,
ret = hid_parse(hdev); ret = hid_parse(hdev);
if (ret) { if (ret) {
hid_err(hdev, "hid_parse failed\n"); hid_err(hdev, "hid_parse failed\n");
goto err_free; goto err;
} }
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
if (ret) { if (ret) {
hid_err(hdev, "hid_hw_start failed\n"); hid_err(hdev, "hid_hw_start failed\n");
goto err_free; goto err;
} }
uhdev = (struct usbhid_device *) hdev->driver_data; uhdev = (struct usbhid_device *) hdev->driver_data;
if (uhdev->ifnum == 1) if (uhdev->ifnum == 1) {
return tpkbd_probe_tp(hdev); ret = tpkbd_probe_tp(hdev);
if (ret)
goto err_hid;
}
return 0; return 0;
err_free: err_hid:
hid_hw_stop(hdev);
err:
return ret; return ret;
} }
......
...@@ -64,26 +64,13 @@ int lg2ff_init(struct hid_device *hid) ...@@ -64,26 +64,13 @@ int lg2ff_init(struct hid_device *hid)
struct hid_report *report; struct hid_report *report;
struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input *hidinput = list_entry(hid->inputs.next,
struct hid_input, list); struct hid_input, list);
struct list_head *report_list =
&hid->report_enum[HID_OUTPUT_REPORT].report_list;
struct input_dev *dev = hidinput->input; struct input_dev *dev = hidinput->input;
int error; int error;
if (list_empty(report_list)) { /* Check that the report looks ok */
hid_err(hid, "no output report found\n"); report = hid_validate_values(hid, HID_OUTPUT_REPORT, 0, 0, 7);
if (!report)
return -ENODEV; return -ENODEV;
}
report = list_entry(report_list->next, struct hid_report, list);
if (report->maxfield < 1) {
hid_err(hid, "output report is empty\n");
return -ENODEV;
}
if (report->field[0]->report_count < 7) {
hid_err(hid, "not enough values in the field\n");
return -ENODEV;
}
lg2ff = kmalloc(sizeof(struct lg2ff_device), GFP_KERNEL); lg2ff = kmalloc(sizeof(struct lg2ff_device), GFP_KERNEL);
if (!lg2ff) if (!lg2ff)
......
...@@ -66,10 +66,11 @@ static int hid_lg3ff_play(struct input_dev *dev, void *data, ...@@ -66,10 +66,11 @@ static int hid_lg3ff_play(struct input_dev *dev, void *data,
int x, y; int x, y;
/* /*
* Maxusage should always be 63 (maximum fields) * Available values in the field should always be 63, but we only use up to
* likely a better way to ensure this data is clean * 35. Instead, clear the entire area, however big it is.
*/ */
memset(report->field[0]->value, 0, sizeof(__s32)*report->field[0]->maxusage); memset(report->field[0]->value, 0,
sizeof(__s32) * report->field[0]->report_count);
switch (effect->type) { switch (effect->type) {
case FF_CONSTANT: case FF_CONSTANT:
...@@ -129,32 +130,14 @@ static const signed short ff3_joystick_ac[] = { ...@@ -129,32 +130,14 @@ static const signed short ff3_joystick_ac[] = {
int lg3ff_init(struct hid_device *hid) int lg3ff_init(struct hid_device *hid)
{ {
struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list); struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list);
struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
struct input_dev *dev = hidinput->input; struct input_dev *dev = hidinput->input;
struct hid_report *report;
struct hid_field *field;
const signed short *ff_bits = ff3_joystick_ac; const signed short *ff_bits = ff3_joystick_ac;
int error; int error;
int i; int i;
/* Find the report to use */
if (list_empty(report_list)) {
hid_err(hid, "No output report found\n");
return -1;
}
/* Check that the report looks ok */ /* Check that the report looks ok */
report = list_entry(report_list->next, struct hid_report, list); if (!hid_validate_values(hid, HID_OUTPUT_REPORT, 0, 0, 35))
if (!report) { return -ENODEV;
hid_err(hid, "NULL output report\n");
return -1;
}
field = report->field[0];
if (!field) {
hid_err(hid, "NULL field\n");
return -1;
}
/* Assume single fixed device G940 */ /* Assume single fixed device G940 */
for (i = 0; ff_bits[i] >= 0; i++) 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 ...@@ -484,34 +484,16 @@ static enum led_brightness lg4ff_led_get_brightness(struct led_classdev *led_cde
int lg4ff_init(struct hid_device *hid) int lg4ff_init(struct hid_device *hid)
{ {
struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list); struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list);
struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
struct input_dev *dev = hidinput->input; struct input_dev *dev = hidinput->input;
struct hid_report *report;
struct hid_field *field;
struct lg4ff_device_entry *entry; struct lg4ff_device_entry *entry;
struct lg_drv_data *drv_data; struct lg_drv_data *drv_data;
struct usb_device_descriptor *udesc; struct usb_device_descriptor *udesc;
int error, i, j; int error, i, j;
__u16 bcdDevice, rev_maj, rev_min; __u16 bcdDevice, rev_maj, rev_min;
/* Find the report to use */
if (list_empty(report_list)) {
hid_err(hid, "No output report found\n");
return -1;
}
/* Check that the report looks ok */ /* Check that the report looks ok */
report = list_entry(report_list->next, struct hid_report, list); if (!hid_validate_values(hid, HID_OUTPUT_REPORT, 0, 0, 7))
if (!report) {
hid_err(hid, "NULL output report\n");
return -1; return -1;
}
field = report->field[0];
if (!field) {
hid_err(hid, "NULL field\n");
return -1;
}
/* Check what wheel has been connected */ /* Check what wheel has been connected */
for (i = 0; i < ARRAY_SIZE(lg4ff_devices); i++) { 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) ...@@ -128,27 +128,14 @@ static void hid_lgff_set_autocenter(struct input_dev *dev, u16 magnitude)
int lgff_init(struct hid_device* hid) int lgff_init(struct hid_device* hid)
{ {
struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list); struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list);
struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
struct input_dev *dev = hidinput->input; struct input_dev *dev = hidinput->input;
struct hid_report *report;
struct hid_field *field;
const signed short *ff_bits = ff_joystick; const signed short *ff_bits = ff_joystick;
int error; int error;
int i; int i;
/* Find the report to use */
if (list_empty(report_list)) {
hid_err(hid, "No output report found\n");
return -1;
}
/* Check that the report looks ok */ /* Check that the report looks ok */
report = list_entry(report_list->next, struct hid_report, list); if (!hid_validate_values(hid, HID_OUTPUT_REPORT, 0, 0, 7))
field = report->field[0]; return -ENODEV;
if (!field) {
hid_err(hid, "NULL field\n");
return -1;
}
for (i = 0; i < ARRAY_SIZE(devices); i++) { for (i = 0; i < ARRAY_SIZE(devices); i++) {
if (dev->id.vendor == devices[i].idVendor && if (dev->id.vendor == devices[i].idVendor &&
......
...@@ -461,7 +461,7 @@ static int logi_dj_recv_send_report(struct dj_receiver_dev *djrcv_dev, ...@@ -461,7 +461,7 @@ static int logi_dj_recv_send_report(struct dj_receiver_dev *djrcv_dev,
struct hid_report *report; struct hid_report *report;
struct hid_report_enum *output_report_enum; struct hid_report_enum *output_report_enum;
u8 *data = (u8 *)(&dj_report->device_index); u8 *data = (u8 *)(&dj_report->device_index);
int i; unsigned int i;
output_report_enum = &hdev->report_enum[HID_OUTPUT_REPORT]; output_report_enum = &hdev->report_enum[HID_OUTPUT_REPORT];
report = output_report_enum->report_id_hash[REPORT_ID_DJ_SHORT]; 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,7 +471,7 @@ static int logi_dj_recv_send_report(struct dj_receiver_dev *djrcv_dev,
return -ENODEV; return -ENODEV;
} }
for (i = 0; i < report->field[0]->report_count; i++) for (i = 0; i < DJREPORT_SHORT_LENGTH - 1; i++)
report->field[0]->value[i] = data[i]; report->field[0]->value[i] = data[i];
hid_hw_request(hdev, report, HID_REQ_SET_REPORT); hid_hw_request(hdev, report, HID_REQ_SET_REPORT);
...@@ -791,6 +791,12 @@ static int logi_dj_probe(struct hid_device *hdev, ...@@ -791,6 +791,12 @@ static int logi_dj_probe(struct hid_device *hdev,
goto hid_parse_fail; goto hid_parse_fail;
} }
if (!hid_validate_values(hdev, HID_OUTPUT_REPORT, REPORT_ID_DJ_SHORT,
0, DJREPORT_SHORT_LENGTH - 1)) {
retval = -ENODEV;
goto hid_parse_fail;
}
/* Starts the usb device and connects to upper interfaces hiddev and /* Starts the usb device and connects to upper interfaces hiddev and
* hidraw */ * hidraw */
retval = hid_hw_start(hdev, HID_CONNECT_DEFAULT); retval = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
......
...@@ -101,9 +101,9 @@ struct mt_device { ...@@ -101,9 +101,9 @@ struct mt_device {
unsigned last_slot_field; /* the last field of a slot */ unsigned last_slot_field; /* the last field of a slot */
unsigned mt_report_id; /* the report ID of the multitouch device */ unsigned mt_report_id; /* the report ID of the multitouch device */
unsigned pen_report_id; /* the report ID of the pen device */ unsigned pen_report_id; /* the report ID of the pen device */
__s8 inputmode; /* InputMode HID feature, -1 if non-existent */ __s16 inputmode; /* InputMode HID feature, -1 if non-existent */
__s8 inputmode_index; /* InputMode HID feature index in the report */ __s16 inputmode_index; /* InputMode HID feature index in the report */
__s8 maxcontact_report_id; /* Maximum Contact Number HID feature, __s16 maxcontact_report_id; /* Maximum Contact Number HID feature,
-1 if non-existent */ -1 if non-existent */
__u8 num_received; /* how many contacts we received */ __u8 num_received; /* how many contacts we received */
__u8 num_expected; /* expected last contact index */ __u8 num_expected; /* expected last contact index */
...@@ -312,19 +312,17 @@ static void mt_feature_mapping(struct hid_device *hdev, ...@@ -312,19 +312,17 @@ static void mt_feature_mapping(struct hid_device *hdev,
struct hid_field *field, struct hid_usage *usage) struct hid_field *field, struct hid_usage *usage)
{ {
struct mt_device *td = hid_get_drvdata(hdev); struct mt_device *td = hid_get_drvdata(hdev);
int i;
switch (usage->hid) { switch (usage->hid) {
case HID_DG_INPUTMODE: case HID_DG_INPUTMODE:
td->inputmode = field->report->id; /* Ignore if value index is out of bounds. */
td->inputmode_index = 0; /* has to be updated below */ if (usage->usage_index >= field->report_count) {
dev_err(&hdev->dev, "HID_DG_INPUTMODE out of range\n");
for (i=0; i < field->maxusage; i++) {
if (field->usage[i].hid == usage->hid) {
td->inputmode_index = i;
break; break;
} }
}
td->inputmode = field->report->id;
td->inputmode_index = usage->usage_index;
break; break;
case HID_DG_CONTACTMAX: case HID_DG_CONTACTMAX:
...@@ -511,6 +509,10 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi, ...@@ -511,6 +509,10 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
mt_store_field(usage, td, hi); mt_store_field(usage, td, hi);
return 1; return 1;
case HID_DG_CONTACTCOUNT: case HID_DG_CONTACTCOUNT:
/* Ignore if indexes are out of bounds. */
if (field->index >= field->report->maxfield ||
usage->usage_index >= field->report_count)
return 1;
td->cc_index = field->index; td->cc_index = field->index;
td->cc_value_index = usage->usage_index; td->cc_value_index = usage->usage_index;
return 1; return 1;
......
...@@ -537,6 +537,10 @@ static int buzz_init(struct hid_device *hdev) ...@@ -537,6 +537,10 @@ static int buzz_init(struct hid_device *hdev)
drv_data = hid_get_drvdata(hdev); drv_data = hid_get_drvdata(hdev);
BUG_ON(!(drv_data->quirks & BUZZ_CONTROLLER)); BUG_ON(!(drv_data->quirks & BUZZ_CONTROLLER));
/* Validate expected report characteristics. */
if (!hid_validate_values(hdev, HID_OUTPUT_REPORT, 0, 0, 7))
return -ENODEV;
buzz = kzalloc(sizeof(*buzz), GFP_KERNEL); buzz = kzalloc(sizeof(*buzz), GFP_KERNEL);
if (!buzz) { if (!buzz) {
hid_err(hdev, "Insufficient memory, cannot allocate driver data\n"); hid_err(hdev, "Insufficient memory, cannot allocate driver data\n");
......
...@@ -249,6 +249,11 @@ static int steelseries_srws1_probe(struct hid_device *hdev, ...@@ -249,6 +249,11 @@ static int steelseries_srws1_probe(struct hid_device *hdev,
goto err_free; goto err_free;
} }
if (!hid_validate_values(hdev, HID_OUTPUT_REPORT, 0, 0, 16)) {
ret = -ENODEV;
goto err_free;
}
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
if (ret) { if (ret) {
hid_err(hdev, "hw start failed\n"); hid_err(hdev, "hw start failed\n");
......
...@@ -68,20 +68,12 @@ static int zpff_init(struct hid_device *hid) ...@@ -68,20 +68,12 @@ static int zpff_init(struct hid_device *hid)
struct hid_report *report; struct hid_report *report;
struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input *hidinput = list_entry(hid->inputs.next,
struct hid_input, list); struct hid_input, list);
struct list_head *report_list =
&hid->report_enum[HID_OUTPUT_REPORT].report_list;
struct input_dev *dev = hidinput->input; struct input_dev *dev = hidinput->input;
int error; int i, error;
if (list_empty(report_list)) { for (i = 0; i < 4; i++) {
hid_err(hid, "no output report found\n"); report = hid_validate_values(hid, HID_OUTPUT_REPORT, 0, i, 1);
return -ENODEV; if (!report)
}
report = list_entry(report_list->next, struct hid_report, list);
if (report->maxfield < 4) {
hid_err(hid, "not enough fields in report\n");
return -ENODEV; return -ENODEV;
} }
......
...@@ -756,6 +756,10 @@ u8 *hid_alloc_report_buf(struct hid_report *report, gfp_t flags); ...@@ -756,6 +756,10 @@ u8 *hid_alloc_report_buf(struct hid_report *report, gfp_t flags);
struct hid_device *hid_allocate_device(void); struct hid_device *hid_allocate_device(void);
struct hid_report *hid_register_report(struct hid_device *device, unsigned type, unsigned id); struct hid_report *hid_register_report(struct hid_device *device, unsigned type, unsigned id);
int hid_parse_report(struct hid_device *hid, __u8 *start, unsigned size); int hid_parse_report(struct hid_device *hid, __u8 *start, unsigned size);
struct hid_report *hid_validate_values(struct hid_device *hid,
unsigned int type, unsigned int id,
unsigned int field_index,
unsigned int report_counts);
int hid_open_report(struct hid_device *device); int hid_open_report(struct hid_device *device);
int hid_check_keys_pressed(struct hid_device *hid); int hid_check_keys_pressed(struct hid_device *hid);
int hid_connect(struct hid_device *hid, unsigned int connect_mask); int hid_connect(struct hid_device *hid, unsigned int connect_mask);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment