| From 89a0ec67e036a04205cbe0fef754ffe22816dbb2 Mon Sep 17 00:00:00 2001 |
| From: Kees Cook <keescook@chromium.org> |
| Date: Wed, 11 Sep 2013 21:56:50 +0200 |
| Subject: [PATCH] HID: provide a helper for validating hid reports |
| |
| commit 331415ff16a12147d57d5c953f3a961b7ede348b 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: Kees Cook <keescook@chromium.org> |
| Reviewed-by: Benjamin Tissoires <benjamin.tissoires@redhat.com> |
| Signed-off-by: Jiri Kosina <jkosina@suse.cz> |
| [PG: in 2.6.34 it is err_hid(), original baseline had hid_err().] |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| --- |
| drivers/hid/hid-core.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++ |
| include/linux/hid.h | 4 ++++ |
| 2 files changed, 62 insertions(+) |
| |
| diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c |
| index 195e366ea18d..b71ff324bec9 100644 |
| --- a/drivers/hid/hid-core.c |
| +++ b/drivers/hid/hid-core.c |
| @@ -808,6 +808,64 @@ static __inline__ 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) { |
| + err_hid("invalid HID report type %u\n", type); |
| + return NULL; |
| + } |
| + |
| + if (id >= HID_MAX_IDS) { |
| + 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) { |
| + err_hid("missing %s %u\n", hid_report_names[type], id); |
| + return NULL; |
| + } |
| + if (report->maxfield <= field_index) { |
| + 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) { |
| + 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 |
| * |
| diff --git a/include/linux/hid.h b/include/linux/hid.h |
| index 85e0942cfd76..cd7049a670bc 100644 |
| --- a/include/linux/hid.h |
| +++ b/include/linux/hid.h |
| @@ -694,6 +694,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); |
| -- |
| 1.8.5.2 |
| |