From: Kees Cook <[email protected]>

When working on report indexes, always validate that they 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

Signed-off-by: Kees Cook <[email protected]>
Cc: [email protected]
---
 drivers/hid/hid-multitouch.c |   25 ++++++++++++++++++++-----
 1 file changed, 20 insertions(+), 5 deletions(-)

diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
index cb0e361..2aa275e 100644
--- a/drivers/hid/hid-multitouch.c
+++ b/drivers/hid/hid-multitouch.c
@@ -330,9 +330,18 @@ static void mt_feature_mapping(struct hid_device *hdev,
                                break;
                        }
                }
+               /* Ignore if value index is out of bounds. */
+               if (td->inputmode_index < 0 ||
+                   td->inputmode_index >= field->report_count) {
+                       dev_err(&hdev->dev, "HID_DG_INPUTMODE out of range\n");
+                       td->inputmode = -1;
+               }
 
                break;
        case HID_DG_CONTACTMAX:
+               /* Ignore if value count is out of bounds. */
+               if (field->report_count < 1)
+                       break;
                td->maxcontact_report_id = field->report->id;
                td->maxcontacts = field->value[0];
                if (!td->maxcontacts &&
@@ -743,15 +752,21 @@ static void mt_touch_report(struct hid_device *hid, 
struct hid_report *report)
        unsigned count;
        int r, n;
 
+       if (report->maxfield == 0)
+               return;
+
        /*
         * Includes multi-packet support where subsequent
         * packets are sent with zero contactcount.
         */
-       if (td->cc_index >= 0) {
-               struct hid_field *field = report->field[td->cc_index];
-               int value = field->value[td->cc_value_index];
-               if (value)
-                       td->num_expected = value;
+       if (td->cc_index >= 0 && td->cc_index < report->maxfield) {
+               field = report->field[td->cc_index];
+               if (td->cc_value_index >= 0 &&
+                   td->cc_value_index < field->report_count) {
+                       int value = field->value[td->cc_value_index];
+                       if (value)
+                               td->num_expected = value;
+               }
        }
 
        for (r = 0; r < report->maxfield; r++) {

-- 
Jiri Kosina
SUSE Labs
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to