--- /dev/null
+From 0ccdd9e7476680c16113131264ad6597bd10299d Mon Sep 17 00:00:00 2001
+From: Benjamin Tissoires <benjamin.tissoires@redhat.com>
+Date: Wed, 11 Sep 2013 21:56:59 +0200
+Subject: HID: lenovo-tpkbd: fix leak if tpkbd_probe_tp fails
+
+From: Benjamin Tissoires <benjamin.tissoires@redhat.com>
+
+commit 0ccdd9e7476680c16113131264ad6597bd10299d upstream.
+
+If tpkbd_probe_tp() bails out, the probe() function return an error,
+but hid_hw_stop() is never called.
+
+fixes:
+https://bugzilla.redhat.com/show_bug.cgi?id=1003998
+
+Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
+Signed-off-by: Jiri Kosina <jkosina@suse.cz>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/hid/hid-lenovo-tpkbd.c | 15 ++++++++++-----
+ 1 file changed, 10 insertions(+), 5 deletions(-)
+
+--- a/drivers/hid/hid-lenovo-tpkbd.c
++++ b/drivers/hid/hid-lenovo-tpkbd.c
+@@ -406,22 +406,27 @@ static int tpkbd_probe(struct hid_device
+ ret = hid_parse(hdev);
+ if (ret) {
+ hid_err(hdev, "hid_parse failed\n");
+- goto err_free;
++ goto err;
+ }
+
+ ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+ if (ret) {
+ hid_err(hdev, "hid_hw_start failed\n");
+- goto err_free;
++ goto err;
+ }
+
+ uhdev = (struct usbhid_device *) hdev->driver_data;
+
+- if (uhdev->ifnum == 1)
+- return tpkbd_probe_tp(hdev);
++ if (uhdev->ifnum == 1) {
++ ret = tpkbd_probe_tp(hdev);
++ if (ret)
++ goto err_hid;
++ }
+
+ return 0;
+-err_free:
++err_hid:
++ hid_hw_stop(hdev);
++err:
+ return ret;
+ }
+
--- /dev/null
+From 0a9cd0a80ac559357c6a90d26c55270ed752aa26 Mon Sep 17 00:00:00 2001
+From: Kees Cook <keescook@chromium.org>
+Date: Wed, 11 Sep 2013 21:56:55 +0200
+Subject: HID: lenovo-tpkbd: validate output report details
+
+From: Kees Cook <keescook@chromium.org>
+
+commit 0a9cd0a80ac559357c6a90d26c55270ed752aa26 upstream.
+
+A HID device could send a malicious output report that would cause the
+lenovo-tpkbd HID driver to write just beyond the output report allocation
+during initialization, causing a heap overflow:
+
+[ 76.109807] usb 1-1: New USB device found, idVendor=17ef, idProduct=6009
+...
+[ 80.462540] BUG kmalloc-192 (Tainted: G W ): Redzone overwritten
+
+CVE-2013-2894
+
+Signed-off-by: Kees Cook <keescook@chromium.org>
+Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
+Signed-off-by: Jiri Kosina <jkosina@suse.cz>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/hid/hid-lenovo-tpkbd.c | 10 +++++++++-
+ 1 file changed, 9 insertions(+), 1 deletion(-)
+
+--- a/drivers/hid/hid-lenovo-tpkbd.c
++++ b/drivers/hid/hid-lenovo-tpkbd.c
+@@ -339,7 +339,15 @@ static int tpkbd_probe_tp(struct hid_dev
+ struct tpkbd_data_pointer *data_pointer;
+ size_t name_sz = strlen(dev_name(dev)) + 16;
+ char *name_mute, *name_micmute;
+- int ret;
++ int i, ret;
++
++ /* Validate required reports. */
++ for (i = 0; i < 4; i++) {
++ if (!hid_validate_values(hdev, HID_FEATURE_REPORT, 4, i, 1))
++ return -ENODEV;
++ }
++ if (!hid_validate_values(hdev, HID_OUTPUT_REPORT, 3, 0, 2))
++ return -ENODEV;
+
+ if (sysfs_create_group(&hdev->dev.kobj,
+ &tpkbd_attr_group_pointer)) {
--- /dev/null
+From 0fb6bd06e06792469acc15bbe427361b56ada528 Mon Sep 17 00:00:00 2001
+From: Kees Cook <keescook@chromium.org>
+Date: Wed, 11 Sep 2013 21:56:54 +0200
+Subject: HID: LG: validate HID output report details
+
+From: Kees Cook <keescook@chromium.org>
+
+commit 0fb6bd06e06792469acc15bbe427361b56ada528 upstream.
+
+A HID device could send a malicious output report that would cause the
+lg, lg3, and lg4 HID drivers to write beyond the output report allocation
+during an event, causing a heap overflow:
+
+[ 325.245240] usb 1-1: New USB device found, idVendor=046d, idProduct=c287
+...
+[ 414.518960] BUG kmalloc-4096 (Not tainted): Redzone overwritten
+
+Additionally, while lg2 did correctly validate the report details, it was
+cleaned up and shortened.
+
+CVE-2013-2893
+
+Signed-off-by: Kees Cook <keescook@chromium.org>
+Reviewed-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
+Signed-off-by: Jiri Kosina <jkosina@suse.cz>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/hid/hid-lg2ff.c | 19 +++----------------
+ drivers/hid/hid-lg3ff.c | 29 ++++++-----------------------
+ drivers/hid/hid-lg4ff.c | 20 +-------------------
+ drivers/hid/hid-lgff.c | 17 ++---------------
+ 4 files changed, 12 insertions(+), 73 deletions(-)
+
+--- a/drivers/hid/hid-lg2ff.c
++++ b/drivers/hid/hid-lg2ff.c
+@@ -64,26 +64,13 @@ int lg2ff_init(struct hid_device *hid)
+ struct hid_report *report;
+ struct hid_input *hidinput = list_entry(hid->inputs.next,
+ struct hid_input, list);
+- struct list_head *report_list =
+- &hid->report_enum[HID_OUTPUT_REPORT].report_list;
+ struct input_dev *dev = hidinput->input;
+ int error;
+
+- if (list_empty(report_list)) {
+- hid_err(hid, "no output report found\n");
++ /* Check that the report looks ok */
++ report = hid_validate_values(hid, HID_OUTPUT_REPORT, 0, 0, 7);
++ if (!report)
+ return -ENODEV;
+- }
+-
+- report = list_entry(report_list->next, struct hid_report, list);
+-
+- if (report->maxfield < 1) {
+- hid_err(hid, "output report is empty\n");
+- return -ENODEV;
+- }
+- if (report->field[0]->report_count < 7) {
+- hid_err(hid, "not enough values in the field\n");
+- return -ENODEV;
+- }
+
+ lg2ff = kmalloc(sizeof(struct lg2ff_device), GFP_KERNEL);
+ if (!lg2ff)
+--- a/drivers/hid/hid-lg3ff.c
++++ b/drivers/hid/hid-lg3ff.c
+@@ -66,10 +66,11 @@ static int hid_lg3ff_play(struct input_d
+ int x, y;
+
+ /*
+- * Maxusage should always be 63 (maximum fields)
+- * likely a better way to ensure this data is clean
++ * Available values in the field should always be 63, but we only use up to
++ * 35. Instead, clear the entire area, however big it is.
+ */
+- memset(report->field[0]->value, 0, sizeof(__s32)*report->field[0]->maxusage);
++ memset(report->field[0]->value, 0,
++ sizeof(__s32) * report->field[0]->report_count);
+
+ switch (effect->type) {
+ case FF_CONSTANT:
+@@ -129,32 +130,14 @@ static const signed short ff3_joystick_a
+ int lg3ff_init(struct hid_device *hid)
+ {
+ struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list);
+- struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
+ struct input_dev *dev = hidinput->input;
+- struct hid_report *report;
+- struct hid_field *field;
+ const signed short *ff_bits = ff3_joystick_ac;
+ int error;
+ int i;
+
+- /* Find the report to use */
+- if (list_empty(report_list)) {
+- hid_err(hid, "No output report found\n");
+- return -1;
+- }
+-
+ /* Check that the report looks ok */
+- report = list_entry(report_list->next, struct hid_report, list);
+- if (!report) {
+- hid_err(hid, "NULL output report\n");
+- return -1;
+- }
+-
+- field = report->field[0];
+- if (!field) {
+- hid_err(hid, "NULL field\n");
+- return -1;
+- }
++ if (!hid_validate_values(hid, HID_OUTPUT_REPORT, 0, 0, 35))
++ return -ENODEV;
+
+ /* Assume single fixed device G940 */
+ for (i = 0; ff_bits[i] >= 0; i++)
+--- a/drivers/hid/hid-lg4ff.c
++++ b/drivers/hid/hid-lg4ff.c
+@@ -484,34 +484,16 @@ static enum led_brightness lg4ff_led_get
+ int lg4ff_init(struct hid_device *hid)
+ {
+ struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list);
+- struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
+ struct input_dev *dev = hidinput->input;
+- struct hid_report *report;
+- struct hid_field *field;
+ struct lg4ff_device_entry *entry;
+ struct lg_drv_data *drv_data;
+ struct usb_device_descriptor *udesc;
+ int error, i, j;
+ __u16 bcdDevice, rev_maj, rev_min;
+
+- /* Find the report to use */
+- if (list_empty(report_list)) {
+- hid_err(hid, "No output report found\n");
+- return -1;
+- }
+-
+ /* Check that the report looks ok */
+- report = list_entry(report_list->next, struct hid_report, list);
+- if (!report) {
+- hid_err(hid, "NULL output report\n");
+- return -1;
+- }
+-
+- field = report->field[0];
+- if (!field) {
+- hid_err(hid, "NULL field\n");
++ if (!hid_validate_values(hid, HID_OUTPUT_REPORT, 0, 0, 7))
+ return -1;
+- }
+
+ /* Check what wheel has been connected */
+ for (i = 0; i < ARRAY_SIZE(lg4ff_devices); i++) {
+--- a/drivers/hid/hid-lgff.c
++++ b/drivers/hid/hid-lgff.c
+@@ -128,27 +128,14 @@ static void hid_lgff_set_autocenter(stru
+ int lgff_init(struct hid_device* hid)
+ {
+ struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list);
+- struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
+ struct input_dev *dev = hidinput->input;
+- struct hid_report *report;
+- struct hid_field *field;
+ const signed short *ff_bits = ff_joystick;
+ int error;
+ int i;
+
+- /* Find the report to use */
+- if (list_empty(report_list)) {
+- hid_err(hid, "No output report found\n");
+- return -1;
+- }
+-
+ /* Check that the report looks ok */
+- report = list_entry(report_list->next, struct hid_report, list);
+- field = report->field[0];
+- if (!field) {
+- hid_err(hid, "NULL field\n");
+- return -1;
+- }
++ if (!hid_validate_values(hid, HID_OUTPUT_REPORT, 0, 0, 7))
++ return -ENODEV;
+
+ for (i = 0; i < ARRAY_SIZE(devices); i++) {
+ if (dev->id.vendor == devices[i].idVendor &&
--- /dev/null
+From 297502abb32e225fb23801fcdb0e4f6f8e17099a Mon Sep 17 00:00:00 2001
+From: Kees Cook <keescook@chromium.org>
+Date: Wed, 11 Sep 2013 21:56:56 +0200
+Subject: HID: logitech-dj: validate output report details
+
+From: Kees Cook <keescook@chromium.org>
+
+commit 297502abb32e225fb23801fcdb0e4f6f8e17099a upstream.
+
+A HID device could send a malicious output report that would cause the
+logitech-dj HID driver to leak kernel memory contents to the device, or
+trigger a NULL dereference during initialization:
+
+[ 304.424553] usb 1-1: New USB device found, idVendor=046d, idProduct=c52b
+...
+[ 304.780467] BUG: unable to handle kernel NULL pointer dereference at 0000000000000028
+[ 304.781409] IP: [<ffffffff815d50aa>] logi_dj_recv_send_report.isra.11+0x1a/0x90
+
+CVE-2013-2895
+
+Signed-off-by: Kees Cook <keescook@chromium.org>
+Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
+Signed-off-by: Jiri Kosina <jkosina@suse.cz>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/hid/hid-logitech-dj.c | 10 ++++++++--
+ 1 file changed, 8 insertions(+), 2 deletions(-)
+
+--- a/drivers/hid/hid-logitech-dj.c
++++ b/drivers/hid/hid-logitech-dj.c
+@@ -461,7 +461,7 @@ static int logi_dj_recv_send_report(stru
+ struct hid_report *report;
+ struct hid_report_enum *output_report_enum;
+ u8 *data = (u8 *)(&dj_report->device_index);
+- int i;
++ unsigned int i;
+
+ output_report_enum = &hdev->report_enum[HID_OUTPUT_REPORT];
+ report = output_report_enum->report_id_hash[REPORT_ID_DJ_SHORT];
+@@ -471,7 +471,7 @@ static int logi_dj_recv_send_report(stru
+ return -ENODEV;
+ }
+
+- for (i = 0; i < report->field[0]->report_count; i++)
++ for (i = 0; i < DJREPORT_SHORT_LENGTH - 1; i++)
+ report->field[0]->value[i] = data[i];
+
+ hid_hw_request(hdev, report, HID_REQ_SET_REPORT);
+@@ -783,6 +783,12 @@ static int logi_dj_probe(struct hid_devi
+ goto hid_parse_fail;
+ }
+
++ if (!hid_validate_values(hdev, HID_OUTPUT_REPORT, REPORT_ID_DJ_SHORT,
++ 0, DJREPORT_SHORT_LENGTH - 1)) {
++ retval = -ENODEV;
++ goto hid_parse_fail;
++ }
++
+ /* Starts the usb device and connects to upper interfaces hiddev and
+ * hidraw */
+ retval = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
--- /dev/null
+From 8821f5dc187bdf16cfb32ef5aa8c3035273fa79a Mon Sep 17 00:00:00 2001
+From: Benjamin Tissoires <benjamin.tissoires@redhat.com>
+Date: Wed, 11 Sep 2013 21:56:58 +0200
+Subject: HID: multitouch: validate indexes details
+
+From: Benjamin Tissoires <benjamin.tissoires@redhat.com>
+
+commit 8821f5dc187bdf16cfb32ef5aa8c3035273fa79a upstream.
+
+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
+
+Note that we need to change the indexes from s8 to s16 as they can
+be between -1 and 255.
+
+CVE-2013-2897
+
+Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
+Acked-by: Kees Cook <keescook@chromium.org>
+Signed-off-by: Jiri Kosina <jkosina@suse.cz>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/hid/hid-multitouch.c | 26 ++++++++++++++------------
+ 1 file changed, 14 insertions(+), 12 deletions(-)
+
+--- a/drivers/hid/hid-multitouch.c
++++ b/drivers/hid/hid-multitouch.c
+@@ -101,9 +101,9 @@ struct mt_device {
+ unsigned last_slot_field; /* the last field of a slot */
+ unsigned mt_report_id; /* the report ID of the multitouch device */
+ unsigned pen_report_id; /* the report ID of the pen device */
+- __s8 inputmode; /* InputMode HID feature, -1 if non-existent */
+- __s8 inputmode_index; /* InputMode HID feature index in the report */
+- __s8 maxcontact_report_id; /* Maximum Contact Number HID feature,
++ __s16 inputmode; /* InputMode HID feature, -1 if non-existent */
++ __s16 inputmode_index; /* InputMode HID feature index in the report */
++ __s16 maxcontact_report_id; /* Maximum Contact Number HID feature,
+ -1 if non-existent */
+ __u8 num_received; /* how many contacts we received */
+ __u8 num_expected; /* expected last contact index */
+@@ -317,20 +317,18 @@ static void mt_feature_mapping(struct hi
+ struct hid_field *field, struct hid_usage *usage)
+ {
+ struct mt_device *td = hid_get_drvdata(hdev);
+- int i;
+
+ switch (usage->hid) {
+ case HID_DG_INPUTMODE:
+- td->inputmode = field->report->id;
+- td->inputmode_index = 0; /* has to be updated below */
+-
+- for (i=0; i < field->maxusage; i++) {
+- if (field->usage[i].hid == usage->hid) {
+- td->inputmode_index = i;
+- break;
+- }
++ /* Ignore if value index is out of bounds. */
++ if (usage->usage_index >= field->report_count) {
++ dev_err(&hdev->dev, "HID_DG_INPUTMODE out of range\n");
++ break;
+ }
+
++ td->inputmode = field->report->id;
++ td->inputmode_index = usage->usage_index;
++
+ break;
+ case HID_DG_CONTACTMAX:
+ td->maxcontact_report_id = field->report->id;
+@@ -536,6 +534,10 @@ static int mt_touch_input_mapping(struct
+ mt_store_field(usage, td, hi);
+ return 1;
+ case HID_DG_CONTACTCOUNT:
++ /* Ignore if indexes are out of bounds. */
++ if (field->index >= field->report->maxfield ||
++ usage->usage_index >= field->report_count)
++ return 1;
+ td->cc_index = field->index;
+ td->cc_value_index = usage->usage_index;
+ return 1;
--- /dev/null
+From 9446edb9a1740989cf6c20daf7510fb9a23be14a Mon Sep 17 00:00:00 2001
+From: Kees Cook <keescook@chromium.org>
+Date: Wed, 11 Sep 2013 21:56:52 +0200
+Subject: HID: sony: validate HID output report details
+
+From: Kees Cook <keescook@chromium.org>
+
+commit 9446edb9a1740989cf6c20daf7510fb9a23be14a upstream.
+
+This driver must validate the availability of the HID output report and
+its size before it can write LED states via buzz_set_leds(). This stops
+a heap overflow that is possible if a device provides a malicious HID
+output report:
+
+[ 108.171280] usb 1-1: New USB device found, idVendor=054c, idProduct=0002
+...
+[ 117.507877] BUG kmalloc-192 (Not tainted): Redzone overwritten
+
+CVE-2013-2890
+
+Signed-off-by: Kees Cook <keescook@chromium.org>
+Reviewed-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
+Signed-off-by: Jiri Kosina <jkosina@suse.cz>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/hid/hid-sony.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/drivers/hid/hid-sony.c
++++ b/drivers/hid/hid-sony.c
+@@ -537,6 +537,10 @@ static int buzz_init(struct hid_device *
+ drv_data = hid_get_drvdata(hdev);
+ BUG_ON(!(drv_data->quirks & BUZZ_CONTROLLER));
+
++ /* Validate expected report characteristics. */
++ if (!hid_validate_values(hdev, HID_OUTPUT_REPORT, 0, 0, 7))
++ return -ENODEV;
++
+ buzz = kzalloc(sizeof(*buzz), GFP_KERNEL);
+ if (!buzz) {
+ hid_err(hdev, "Insufficient memory, cannot allocate driver data\n");
--- /dev/null
+From 41df7f6d43723deb7364340b44bc5d94bf717456 Mon Sep 17 00:00:00 2001
+From: Kees Cook <keescook@chromium.org>
+Date: Wed, 11 Sep 2013 21:56:53 +0200
+Subject: HID: steelseries: validate output report details
+
+From: Kees Cook <keescook@chromium.org>
+
+commit 41df7f6d43723deb7364340b44bc5d94bf717456 upstream.
+
+A HID device could send a malicious output report that would cause the
+steelseries HID driver to write beyond the output report allocation
+during initialization, causing a heap overflow:
+
+[ 167.981534] usb 1-1: New USB device found, idVendor=1038, idProduct=1410
+...
+[ 182.050547] BUG kmalloc-256 (Tainted: G W ): Redzone overwritten
+
+CVE-2013-2891
+
+Signed-off-by: Kees Cook <keescook@chromium.org>
+Reviewed-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
+Signed-off-by: Jiri Kosina <jkosina@suse.cz>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/hid/hid-steelseries.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+--- a/drivers/hid/hid-steelseries.c
++++ b/drivers/hid/hid-steelseries.c
+@@ -249,6 +249,11 @@ static int steelseries_srws1_probe(struc
+ goto err_free;
+ }
+
++ if (!hid_validate_values(hdev, HID_OUTPUT_REPORT, 0, 0, 16)) {
++ ret = -ENODEV;
++ goto err_free;
++ }
++
+ ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+ if (ret) {
+ hid_err(hdev, "hw start failed\n");
--- /dev/null
+From cc6b54aa54bf40b762cab45a9fc8aa81653146eb Mon Sep 17 00:00:00 2001
+From: Benjamin Tissoires <benjamin.tissoires@redhat.com>
+Date: Wed, 11 Sep 2013 21:56:57 +0200
+Subject: HID: validate feature and input report details
+
+From: Benjamin Tissoires <benjamin.tissoires@redhat.com>
+
+commit cc6b54aa54bf40b762cab45a9fc8aa81653146eb upstream.
+
+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
+
+Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
+Acked-by: Kees Cook <keescook@chromium.org>
+Signed-off-by: Jiri Kosina <jkosina@suse.cz>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/hid/hid-core.c | 16 +++++++---------
+ drivers/hid/hid-input.c | 11 ++++++++++-
+ 2 files changed, 17 insertions(+), 10 deletions(-)
+
+--- a/drivers/hid/hid-core.c
++++ b/drivers/hid/hid-core.c
+@@ -94,7 +94,6 @@ EXPORT_SYMBOL_GPL(hid_register_report);
+ 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) {
+ hid_err(report->device, "too many fields in report\n");
+@@ -113,9 +112,6 @@ static struct hid_field *hid_register_fi
+ field->value = (s32 *)(field->usage + usages);
+ field->report = report;
+
+- for (i = 0; i < usages; i++)
+- field->usage[i].usage_index = i;
+-
+ return field;
+ }
+
+@@ -226,9 +222,9 @@ static int hid_add_field(struct hid_pars
+ {
+ struct hid_report *report;
+ struct hid_field *field;
+- int usages;
++ unsigned usages;
+ unsigned offset;
+- int i;
++ unsigned i;
+
+ report = hid_register_report(parser->device, report_type, parser->global.report_id);
+ if (!report) {
+@@ -255,7 +251,8 @@ static int hid_add_field(struct hid_pars
+ 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);
+
+ field = hid_register_field(report, usages, parser->global.report_count);
+ if (!field)
+@@ -266,13 +263,14 @@ static int hid_add_field(struct hid_pars
+ 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;
+@@ -1295,7 +1293,7 @@ int hid_report_raw_event(struct hid_devi
+ goto out;
+ }
+
+- if (hid->claimed != HID_CLAIMED_HIDRAW) {
++ if (hid->claimed != HID_CLAIMED_HIDRAW && report->maxfield) {
+ for (a = 0; a < report->maxfield; a++)
+ hid_input_field(hid, report->field[a], cdata, interrupt);
+ hdrv = hid->driver;
+--- a/drivers/hid/hid-input.c
++++ b/drivers/hid/hid-input.c
+@@ -485,6 +485,10 @@ static void hidinput_configure_usage(str
+ 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) {
+@@ -1168,7 +1172,11 @@ static void report_features(struct hid_d
+
+ rep_enum = &hid->report_enum[HID_FEATURE_REPORT];
+ list_for_each_entry(rep, &rep_enum->report_list, list)
+- for (i = 0; i < rep->maxfield; i++)
++ for (i = 0; i < rep->maxfield; i++) {
++ /* Ignore if report count is out of bounds. */
++ if (rep->field[i]->report_count < 1)
++ continue;
++
+ for (j = 0; j < rep->field[i]->maxusage; j++) {
+ /* Verify if Battery Strength feature is available */
+ hidinput_setup_battery(hid, HID_FEATURE_REPORT, rep->field[i]);
+@@ -1177,6 +1185,7 @@ static void report_features(struct hid_d
+ drv->feature_mapping(hid, rep->field[i],
+ rep->field[i]->usage + j);
+ }
++ }
+ }
+
+ static struct hid_input *hidinput_allocate(struct hid_device *hid)
--- /dev/null
+From 78214e81a1bf43740ce89bb5efda78eac2f8ef83 Mon Sep 17 00:00:00 2001
+From: Kees Cook <keescook@chromium.org>
+Date: Wed, 11 Sep 2013 21:56:51 +0200
+Subject: HID: zeroplus: validate output report details
+
+From: Kees Cook <keescook@chromium.org>
+
+commit 78214e81a1bf43740ce89bb5efda78eac2f8ef83 upstream.
+
+The zeroplus HID driver was not checking the size of allocated values
+in fields it used. A HID device could send a malicious output report
+that would cause the driver to write beyond the output report allocation
+during initialization, causing a heap overflow:
+
+[ 1442.728680] usb 1-1: New USB device found, idVendor=0c12, idProduct=0005
+...
+[ 1466.243173] BUG kmalloc-192 (Tainted: G W ): Redzone overwritten
+
+CVE-2013-2889
+
+Signed-off-by: Kees Cook <keescook@chromium.org>
+Reviewed-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
+Signed-off-by: Jiri Kosina <jkosina@suse.cz>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/hid/hid-zpff.c | 18 +++++-------------
+ 1 file changed, 5 insertions(+), 13 deletions(-)
+
+--- a/drivers/hid/hid-zpff.c
++++ b/drivers/hid/hid-zpff.c
+@@ -68,21 +68,13 @@ static int zpff_init(struct hid_device *
+ struct hid_report *report;
+ struct hid_input *hidinput = list_entry(hid->inputs.next,
+ struct hid_input, list);
+- struct list_head *report_list =
+- &hid->report_enum[HID_OUTPUT_REPORT].report_list;
+ struct input_dev *dev = hidinput->input;
+- int error;
++ int i, error;
+
+- if (list_empty(report_list)) {
+- hid_err(hid, "no output report found\n");
+- return -ENODEV;
+- }
+-
+- report = list_entry(report_list->next, struct hid_report, list);
+-
+- if (report->maxfield < 4) {
+- hid_err(hid, "not enough fields in report\n");
+- return -ENODEV;
++ for (i = 0; i < 4; i++) {
++ report = hid_validate_values(hid, HID_OUTPUT_REPORT, 0, i, 1);
++ if (!report)
++ return -ENODEV;
+ }
+
+ zpff = kzalloc(sizeof(struct zpff_device), GFP_KERNEL);
sched-cputime-do-not-scale-when-utime-0.patch
sched-fair-fix-small-race-where-child-se.parent-cfs_rq-might-point-to-invalid-ones.patch
hid-provide-a-helper-for-validating-hid-reports.patch
+hid-validate-feature-and-input-report-details.patch
+hid-multitouch-validate-indexes-details.patch
+hid-lg-validate-hid-output-report-details.patch
+hid-zeroplus-validate-output-report-details.patch
+hid-lenovo-tpkbd-fix-leak-if-tpkbd_probe_tp-fails.patch
+hid-steelseries-validate-output-report-details.patch
+hid-sony-validate-hid-output-report-details.patch
+hid-lenovo-tpkbd-validate-output-report-details.patch
+hid-logitech-dj-validate-output-report-details.patch