[Lucid][CVE 2/2] HID: validate feature and input report details

Luis Henriques luis.henriques at canonical.com
Thu Oct 10 13:48:10 UTC 2013


From: Benjamin Tissoires <benjamin.tissoires at redhat.com>

BugLink: http://bugs.launchpad.net/bugs/1220205

When dealing with usage_index, be sure to properly use unsigned instead of
int to avoid overflows.

When working on report fields, always validate that their report_counts are
in bounds.
Without this, a HID device could report a malicious feature report that
could trick the driver into a heap overflow:

[  634.885003] usb 1-1: New USB device found, idVendor=0596, idProduct=0500
...
[  676.469629] BUG kmalloc-192 (Tainted: G        W   ): Redzone overwritten

CVE-2013-2897

Cc: stable at vger.kernel.org
Signed-off-by: Benjamin Tissoires <benjamin.tissoires at redhat.com>
Acked-by: Kees Cook <keescook at chromium.org>
Signed-off-by: Jiri Kosina <jkosina at suse.cz>
(back ported from commit cc6b54aa54bf40b762cab45a9fc8aa81653146eb)
[ luis: dropped changes to hid_report_raw_event() and to report_features() ]
Signed-off-by: Luis Henriques <luis.henriques at canonical.com>
---
 drivers/hid/hid-core.c  | 14 ++++++--------
 drivers/hid/hid-input.c |  4 ++++
 2 files changed, 10 insertions(+), 8 deletions(-)

diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 0fb4906..7f60100 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -87,7 +87,6 @@ static struct hid_report *hid_register_report(struct hid_device *device, unsigne
 static struct hid_field *hid_register_field(struct hid_report *report, unsigned usages, unsigned values)
 {
 	struct hid_field *field;
-	int i;
 
 	if (report->maxfield == HID_MAX_FIELDS) {
 		dbg_hid("too many fields in report\n");
@@ -103,9 +102,6 @@ static struct hid_field *hid_register_field(struct hid_report *report, unsigned
 	field->value = (s32 *)(field->usage + usages);
 	field->report = report;
 
-	for (i = 0; i < usages; i++)
-		field->usage[i].usage_index = i;
-
 	return field;
 }
 
@@ -212,9 +208,9 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign
 {
 	struct hid_report *report;
 	struct hid_field *field;
-	int usages;
+	unsigned usages;
 	unsigned offset;
-	int i;
+	unsigned i;
 
 	if (!(report = hid_register_report(parser->device, report_type, parser->global.report_id))) {
 		dbg_hid("hid_register_report failed\n");
@@ -232,7 +228,8 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign
 	if (!parser->local.usage_index) /* Ignore padding fields */
 		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);
 
 	if ((field = hid_register_field(report, usages, parser->global.report_count)) == NULL)
 		return 0;
@@ -242,13 +239,14 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign
 	field->application = hid_lookup_collection(parser, HID_COLLECTION_APPLICATION);
 
 	for (i = 0; i < usages; i++) {
-		int j = i;
+		unsigned j = i;
 		/* Duplicate the last usage we parsed if we have excess values */
 		if (i >= parser->local.usage_index)
 			j = parser->local.usage_index - 1;
 		field->usage[i].hid = parser->local.usage[j];
 		field->usage[i].collection_index =
 			parser->local.collection_index[j];
+		field->usage[i].usage_index = i;
 	}
 
 	field->maxusage = usages;
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index e0bc3e7..428865e 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -162,6 +162,10 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
 	if (field->flags & HID_MAIN_ITEM_CONSTANT)
 		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 */
 	if (field->report_type == HID_OUTPUT_REPORT &&
 			(usage->hid & HID_USAGE_PAGE) != HID_UP_LED) {
-- 
1.8.3.2





More information about the kernel-team mailing list