Vulnerability: The hid_input_field function in drivers/hid/hid-core.c in the Linux kernel before 4.6 allows physically proximate attackers to obtain sensitive information from kernel memory or cause a denial of service (out-of-bounds read) by connecting a device, as demonstrated by a Logitech DJ receiver.
Vulnerability ID: CVE-2016-7915
CWE: CWE-125
Severity score: 2.9
Project: https://github.com/torvalds/linux
Published: 2016-11-16
File: drivers/hid/hid-core.c
Commit message: HID: core: prevent out-of-bound readings

Plugging a Logitech DJ receiver with KASAN activated raises a bunch of
out-of-bound readings.

The fields are allocated up to MAX_USAGE, meaning that potentially, we do
not have enough fields to fit the incoming values.
Add checks and silence KASAN.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Commit author: Benjamin Tissoires

Vulnerable version (before fix):
 static void hid_input_field(struct hid_device *hid, struct hid_field *field, 		/* Ignore report if ErrorRollOver */ 		if (!(field->flags & HID_MAIN_ITEM_VARIABLE) && 		    value[n] >= min && value[n] <= max && 		    field->usage[value[n] - min].hid == HID_UP_KEYBOARD + 1) 			goto exit; 	} static void hid_input_field(struct hid_device *hid, struct hid_field *field, 		}  		if (field->value[n] >= min && field->value[n] <= max 			&& field->usage[field->value[n] - min].hid 			&& search(value, field->value[n], count)) 				hid_process_event(hid, field, &field->usage[field->value[n] - min], 0, interrupt);  		if (value[n] >= min && value[n] <= max 			&& field->usage[value[n] - min].hid 			&& search(field->value, value[n], count)) 				hid_process_event(hid, field, &field->usage[value[n] - min], 1, interrupt);

Fixed version (after fix):
 static void hid_input_field(struct hid_device *hid, struct hid_field *field, 		/* Ignore report if ErrorRollOver */ 		if (!(field->flags & HID_MAIN_ITEM_VARIABLE) && 		    value[n] >= min && value[n] <= max && 		    value[n] - min < field->maxusage && 		    field->usage[value[n] - min].hid == HID_UP_KEYBOARD + 1) 			goto exit; 	} static void hid_input_field(struct hid_device *hid, struct hid_field *field, 		}  		if (field->value[n] >= min && field->value[n] <= max 			&& field->value[n] - min < field->maxusage 			&& field->usage[field->value[n] - min].hid 			&& search(value, field->value[n], count)) 				hid_process_event(hid, field, &field->usage[field->value[n] - min], 0, interrupt);  		if (value[n] >= min && value[n] <= max 			&& value[n] - min < field->maxusage 			&& field->usage[value[n] - min].hid 			&& search(field->value, value[n], count)) 				hid_process_event(hid, field, &field->usage[value[n] - min], 1, interrupt);

Patch:
patch: @@ -1293,6 +1293,7 @@ static void hid_input_field(struct hid_device *hid, struct hid_field *field,
 		/* Ignore report if ErrorRollOver */
 		if (!(field->flags & HID_MAIN_ITEM_VARIABLE) &&
 		    value[n] >= min && value[n] <= max &&
+		    value[n] - min < field->maxusage &&
 		    field->usage[value[n] - min].hid == HID_UP_KEYBOARD + 1)
 			goto exit;
 	}
@@ -1305,11 +1306,13 @@ static void hid_input_field(struct hid_device *hid, struct hid_field *field,
 		}
 
 		if (field->value[n] >= min && field->value[n] <= max
+			&& field->value[n] - min < field->maxusage
 			&& field->usage[field->value[n] - min].hid
 			&& search(value, field->value[n], count))
 				hid_process_event(hid, field, &field->usage[field->value[n] - min], 0, interrupt);
 
 		if (value[n] >= min && value[n] <= max
+			&& value[n] - min < field->maxusage
 			&& field->usage[value[n] - min].hid
 			&& search(field->value, value[n], count))
 				hid_process_event(hid, field, &field->usage[value[n] - min], 1, interrupt);
path: drivers/hid/hid-core.c