From: Greg Kroah-Hartman Date: Thu, 3 Oct 2013 03:22:09 +0000 (-0700) Subject: 3.4-stable patches X-Git-Tag: v3.0.99~3 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=955ad6d0b789e18fd36d032af4bcacb1e51e74d7;p=thirdparty%2Fkernel%2Fstable-queue.git 3.4-stable patches added patches: hid-lg-validate-hid-output-report-details.patch --- diff --git a/queue-3.4/hid-lg-validate-hid-output-report-details.patch b/queue-3.4/hid-lg-validate-hid-output-report-details.patch new file mode 100644 index 00000000000..b973f99586e --- /dev/null +++ b/queue-3.4/hid-lg-validate-hid-output-report-details.patch @@ -0,0 +1,187 @@ +From 0fb6bd06e06792469acc15bbe427361b56ada528 Mon Sep 17 00:00:00 2001 +From: Kees Cook +Date: Wed, 11 Sep 2013 21:56:54 +0200 +Subject: HID: LG: validate HID output report details + +From: Kees Cook + +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 +Reviewed-by: Benjamin Tissoires +Signed-off-by: Jiri Kosina +Signed-off-by: Greg Kroah-Hartman + +--- + 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 +@@ -66,26 +66,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 +@@ -68,10 +68,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: +@@ -131,32 +132,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 +@@ -339,33 +339,15 @@ static ssize_t lg4ff_range_store(struct + 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 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 +@@ -130,27 +130,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 && diff --git a/queue-3.4/series b/queue-3.4/series index c054f6bc05e..f174e9677a0 100644 --- a/queue-3.4/series +++ b/queue-3.4/series @@ -13,3 +13,4 @@ hwmon-applesmc-check-key-count-before-proceeding.patch alsa-compress-fix-compress-device-unregister.patch mm-memcg-give-exiting-processes-access-to-memory-reserves.patch mm-fix-aio-performance-regression-for-database-caused-by-thp.patch +hid-lg-validate-hid-output-report-details.patch