Commit 0049b62c authored by Kees Cook's avatar Kees Cook Committed by Greg Kroah-Hartman

HID: provide a helper for validating hid reports

commit 331415ff upstream.

Many drivers need to validate the characteristics of their HID report
during initialization to avoid misusing the reports. This adds a common
helper to perform validation of the report exisitng, the field existing,
and the expected number of values within the field.
Signed-off-by: default avatarKees Cook <keescook@chromium.org>
Reviewed-by: default avatarBenjamin Tissoires <benjamin.tissoires@redhat.com>
Signed-off-by: default avatarJiri Kosina <jkosina@suse.cz>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 62875332
......@@ -821,6 +821,64 @@ static int search(__s32 *array, __s32 value, unsigned n)
return -1;
}
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_match_report - check if driver's raw_event should be called
*
......
......@@ -737,6 +737,10 @@ void hid_output_report(struct hid_report *report, __u8 *data);
struct hid_device *hid_allocate_device(void);
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);
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_check_keys_pressed(struct hid_device *hid);
int hid_connect(struct hid_device *hid, unsigned int connect_mask);
void hid_disconnect(struct hid_device *hid);
......
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