From 38ead6ef1d94e782bec49002ff65f2bdaddfeb15 Mon Sep 17 00:00:00 2001 From: Paul Chavent Date: Sun, 7 Jul 2013 17:43:56 +0200 Subject: HID: core: fix hid delimiter local tag parsing. When device with the DELIMITER tag in its report descriptor is encountered during parsing, it's mistakenly immediately refused by HID core for no justifiable reason. [jkosina@suse.cz: polish changelog] Signed-off-by: Paul Chavent Signed-off-by: Jiri Kosina --- drivers/hid/hid-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/hid/hid-core.c') diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index e39dac68063..8de5cb8319b 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -450,7 +450,7 @@ static int hid_parser_local(struct hid_parser *parser, struct hid_item *item) } parser->local.delimiter_depth--; } - return 1; + return 0; case HID_LOCAL_ITEM_TAG_USAGE: -- cgit v1.2.3-18-g5258 From 0adb9c2c5ed42f199cb2a630c37d18dee385fae2 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Mon, 15 Jul 2013 10:12:18 +0200 Subject: HID: kye: Add report fixup for Genius Gx Imperator Keyboard Genius Gx Imperator Keyboard presents the same problem in its report descriptors than Genius Gila Gaming Mouse. Use the same fixup for both. Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=928561 Reported-and-tested-by: Honza Brazdil Signed-off-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/hid-core.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/hid/hid-core.c') diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 8de5cb8319b..b0f2f459f59 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1594,6 +1594,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_KENSINGTON, USB_DEVICE_ID_KS_SLIMBLADE) }, { HID_USB_DEVICE(USB_VENDOR_ID_KEYTOUCH, USB_DEVICE_ID_KEYTOUCH_IEC) }, { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_GENIUS_GILA_GAMING_MOUSE) }, + { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_GENIUS_GX_IMPERATOR) }, { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_ERGO_525V) }, { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_I405X) }, { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_MOUSEPEN_I608X) }, -- cgit v1.2.3-18-g5258 From 27ce405039bfe6d3f4143415c638f56a3df77dca Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Wed, 10 Jul 2013 19:56:27 +0200 Subject: HID: fix data access in implement() implement() is setting bytes in LE data stream. In case the data is not aligned to 64bits, it reads past the allocated buffer. It doesn't really change any value there (it's properly bitmasked), but in case that this read past the boundary hits a page boundary, pagefault happens when accessing 64bits of 'x' in implement(), and kernel oopses. This happens much more often when numbered reports are in use, as the initial 8bit skip in the buffer makes the whole process work on values which are not aligned to 64bits. This problem dates back to attempts in 2005 and 2006 to make implement() and extract() as generic as possible, and even back then the problem was realized by Adam Kroperlin, but falsely assumed to be impossible to cause any harm: http://www.mail-archive.com/linux-usb-devel@lists.sourceforge.net/msg47690.html I have made several attempts at fixing it "on the spot" directly in implement(), but the results were horrible; the special casing for processing last 64bit chunk and switching to different math makes it unreadable mess. I therefore took a path to allocate a few bytes more which will never make it into final report, but are there as a cushion for all the 64bit math operations happening in implement() and extract(). All callers of hid_output_report() are converted at the same time to allocate the buffer by newly introduced hid_alloc_report_buf() helper. Bruno noticed that the whole raw_size test can be dropped as well, as hid_alloc_report_buf() makes sure that the buffer is always of a proper size. Reviewed-by: Benjamin Tissoires Acked-by: Gustavo Padovan Signed-off-by: Jiri Kosina --- drivers/hid/hid-core.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) (limited to 'drivers/hid/hid-core.c') diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index b0f2f459f59..a1b248cea5b 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1128,7 +1128,8 @@ static void hid_output_field(const struct hid_device *hid, } /* - * Create a report. + * Create a report. 'data' has to be allocated using + * hid_alloc_report_buf() so that it has proper size. */ void hid_output_report(struct hid_report *report, __u8 *data) @@ -1144,6 +1145,22 @@ void hid_output_report(struct hid_report *report, __u8 *data) } EXPORT_SYMBOL_GPL(hid_output_report); +/* + * Allocator for buffer that is going to be passed to hid_output_report() + */ +u8 *hid_alloc_report_buf(struct hid_report *report, gfp_t flags) +{ + /* + * 7 extra bytes are necessary to achieve proper functionality + * of implement() working on 8 byte chunks + */ + + int len = ((report->size - 1) >> 3) + 1 + (report->id > 0) + 7; + + return kmalloc(len, flags); +} +EXPORT_SYMBOL_GPL(hid_alloc_report_buf); + /* * Set a field value. The report this field belongs to has to be * created and transferred to the device, to set this value in the -- cgit v1.2.3-18-g5258 From cb2c9e3f92480a292670e2cc261723ce4de8059e Mon Sep 17 00:00:00 2001 From: Olivier Scherler Date: Sat, 27 Jul 2013 19:20:02 +0200 Subject: HID: Add new driver for non-compliant Xin-Mo devices. The driver currently only supports the Dual Arcade controller. It fixes the negative axis event values (the devices sends -2) to match the logical axis minimum of the HID report descriptor (the report announces -1). It is needed because hid-input discards out of bounds values. Signed-off-by: Olivier Scherler Signed-off-by: Jiri Kosina --- drivers/hid/hid-core.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/hid/hid-core.c') diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index a1b248cea5b..627fea6593a 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1751,6 +1751,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_14_1_INCH) }, { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_SIRIUS_BATTERY_FREE_TABLET) }, { HID_USB_DEVICE(USB_VENDOR_ID_X_TENSIONS, USB_DEVICE_ID_SPEEDLINK_VAD_CEZANNE) }, + { HID_USB_DEVICE(USB_VENDOR_ID_XIN_MO, USB_DEVICE_ID_XIN_MO_DUAL_ARCADE) }, { HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0005) }, { HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0030) }, { HID_USB_DEVICE(USB_VENDOR_ID_ZYDACRON, USB_DEVICE_ID_ZYDACRON_REMOTE_CONTROL) }, -- cgit v1.2.3-18-g5258 From 3dc8fc083dbfeede7b63a0c07581192e97711365 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Thu, 22 Aug 2013 14:51:07 +0200 Subject: HID: Use hid_parser for pre-scanning the report descriptors The Win 8 detection is sufficiently complex to warrant use of the full parser code, in spite of the inferred memory usage. Therefore, we can use the existing HID parser in hid-core for hid_scan_report() by re-using the code from hid_open_report(). hid_parser_global, hid_parser_local and hid_parser_reserved does not have any side effects. We just need to reimplement the MAIN_ITEM callback to have a proper parsing without side effects. Signed-off-by: Benjamin Tissoires Reviewed-by: Henrik Rydberg Tested-by: Srinivas Pandruvada Signed-off-by: Jiri Kosina --- drivers/hid/hid-core.c | 102 +++++++++++++++++++++++++++++++------------------ 1 file changed, 64 insertions(+), 38 deletions(-) (limited to 'drivers/hid/hid-core.c') diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index e39dac68063..ddd95f3e33c 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -677,12 +677,52 @@ static u8 *fetch_item(__u8 *start, __u8 *end, struct hid_item *item) return NULL; } -static void hid_scan_usage(struct hid_device *hid, u32 usage) +static void hid_scan_input_usage(struct hid_parser *parser, u32 usage) { + struct hid_device *hid = parser->device; + if (usage == HID_DG_CONTACTID) hid->group = HID_GROUP_MULTITOUCH; } +static void hid_scan_collection(struct hid_parser *parser, unsigned type) +{ + struct hid_device *hid = parser->device; + + if (((parser->global.usage_page << 16) == HID_UP_SENSOR) && + type == HID_COLLECTION_PHYSICAL) + hid->group = HID_GROUP_SENSOR_HUB; +} + +static int hid_scan_main(struct hid_parser *parser, struct hid_item *item) +{ + __u32 data; + int i; + + data = item_udata(item); + + switch (item->tag) { + case HID_MAIN_ITEM_TAG_BEGIN_COLLECTION: + hid_scan_collection(parser, data & 0xff); + break; + case HID_MAIN_ITEM_TAG_END_COLLECTION: + break; + case HID_MAIN_ITEM_TAG_INPUT: + for (i = 0; i < parser->local.usage_index; i++) + hid_scan_input_usage(parser, parser->local.usage[i]); + break; + case HID_MAIN_ITEM_TAG_OUTPUT: + break; + case HID_MAIN_ITEM_TAG_FEATURE: + break; + } + + /* Reset the local parser environment */ + memset(&parser->local, 0, sizeof(parser->local)); + + return 0; +} + /* * Scan a report descriptor before the device is added to the bus. * Sets device groups and other properties that determine what driver @@ -690,48 +730,34 @@ static void hid_scan_usage(struct hid_device *hid, u32 usage) */ static int hid_scan_report(struct hid_device *hid) { - unsigned int page = 0, delim = 0; + struct hid_parser *parser; + struct hid_item item; __u8 *start = hid->dev_rdesc; __u8 *end = start + hid->dev_rsize; - unsigned int u, u_min = 0, u_max = 0; - struct hid_item item; + static int (*dispatch_type[])(struct hid_parser *parser, + struct hid_item *item) = { + hid_scan_main, + hid_parser_global, + hid_parser_local, + hid_parser_reserved + }; + + parser = vzalloc(sizeof(struct hid_parser)); + if (!parser) + return -ENOMEM; + parser->device = hid; hid->group = HID_GROUP_GENERIC; - while ((start = fetch_item(start, end, &item)) != NULL) { - if (item.format != HID_ITEM_FORMAT_SHORT) - return -EINVAL; - if (item.type == HID_ITEM_TYPE_GLOBAL) { - if (item.tag == HID_GLOBAL_ITEM_TAG_USAGE_PAGE) - page = item_udata(&item) << 16; - } else if (item.type == HID_ITEM_TYPE_LOCAL) { - if (delim > 1) - break; - u = item_udata(&item); - if (item.size <= 2) - u += page; - switch (item.tag) { - case HID_LOCAL_ITEM_TAG_DELIMITER: - delim += !!u; - break; - case HID_LOCAL_ITEM_TAG_USAGE: - hid_scan_usage(hid, u); - break; - case HID_LOCAL_ITEM_TAG_USAGE_MINIMUM: - u_min = u; - break; - case HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM: - u_max = u; - for (u = u_min; u <= u_max; u++) - hid_scan_usage(hid, u); - break; - } - } else if (page == HID_UP_SENSOR && - item.type == HID_ITEM_TYPE_MAIN && - item.tag == HID_MAIN_ITEM_TAG_BEGIN_COLLECTION && - (item_udata(&item) & 0xff) == HID_COLLECTION_PHYSICAL) - hid->group = HID_GROUP_SENSOR_HUB; - } + /* + * The parsing is simpler than the one in hid_open_report() as we should + * be robust against hid errors. Those errors will be raised by + * hid_open_report() anyway. + */ + while ((start = fetch_item(start, end, &item)) != NULL) + dispatch_type[item.type](parser, &item); + + vfree(parser); return 0; } -- cgit v1.2.3-18-g5258 From f961bd3516e4f699bbacff5d7f5247d6d87c59f0 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Thu, 22 Aug 2013 14:51:08 +0200 Subject: HID: detect Win 8 multitouch devices in core Detecting Win 8 multitouch devices in core allows us to set quirks before the device is parsed through hid_hw_start(). It also simplifies the detection of those devices in hid-multitouch and makes the handling of those devices cleaner. As Win 8 multitouch panels are in the group multitouch and rely on a special feature to be detected, this patch adds a bitfield in the parser. Signed-off-by: Benjamin Tissoires Reviewed-by: Henrik Rydberg Tested-by: Srinivas Pandruvada Signed-off-by: Jiri Kosina --- drivers/hid/hid-core.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'drivers/hid/hid-core.c') diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index ddd95f3e33c..660dce96416 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -685,6 +685,13 @@ static void hid_scan_input_usage(struct hid_parser *parser, u32 usage) hid->group = HID_GROUP_MULTITOUCH; } +static void hid_scan_feature_usage(struct hid_parser *parser, u32 usage) +{ + if (usage == 0xff0000c5 && parser->global.report_count == 256 && + parser->global.report_size == 8) + parser->scan_flags |= HID_SCAN_FLAG_MT_WIN_8; +} + static void hid_scan_collection(struct hid_parser *parser, unsigned type) { struct hid_device *hid = parser->device; @@ -714,6 +721,8 @@ static int hid_scan_main(struct hid_parser *parser, struct hid_item *item) case HID_MAIN_ITEM_TAG_OUTPUT: break; case HID_MAIN_ITEM_TAG_FEATURE: + for (i = 0; i < parser->local.usage_index; i++) + hid_scan_feature_usage(parser, parser->local.usage[i]); break; } @@ -757,6 +766,13 @@ static int hid_scan_report(struct hid_device *hid) while ((start = fetch_item(start, end, &item)) != NULL) dispatch_type[item.type](parser, &item); + /* + * Handle special flags set during scanning. + */ + if ((parser->scan_flags & HID_SCAN_FLAG_MT_WIN_8) && + (hid->group == HID_GROUP_MULTITOUCH)) + hid->group = HID_GROUP_MULTITOUCH_WIN_8; + vfree(parser); return 0; } -- cgit v1.2.3-18-g5258 From 43622021d2e2b82ea03d883926605bdd0525e1d1 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 28 Aug 2013 22:29:55 +0200 Subject: HID: validate HID report id size The "Report ID" field of a HID report is used to build indexes of reports. The kernel's index of these is limited to 256 entries, so any malicious device that sets a Report ID greater than 255 will trigger memory corruption on the host: [ 1347.156239] BUG: unable to handle kernel paging request at ffff88094958a878 [ 1347.156261] IP: [] hid_register_report+0x2a/0x8b CVE-2013-2888 Signed-off-by: Kees Cook Cc: stable@kernel.org Signed-off-by: Jiri Kosina --- drivers/hid/hid-core.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers/hid/hid-core.c') diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 36668d1aca8..5ea7d51e45b 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -63,6 +63,8 @@ struct hid_report *hid_register_report(struct hid_device *device, unsigned type, struct hid_report_enum *report_enum = device->report_enum + type; struct hid_report *report; + if (id >= HID_MAX_IDS) + return NULL; if (report_enum->report_id_hash[id]) return report_enum->report_id_hash[id]; @@ -404,8 +406,10 @@ static int hid_parser_global(struct hid_parser *parser, struct hid_item *item) case HID_GLOBAL_ITEM_TAG_REPORT_ID: parser->global.report_id = item_udata(item); - if (parser->global.report_id == 0) { - hid_err(parser->device, "report_id 0 is invalid\n"); + if (parser->global.report_id == 0 || + parser->global.report_id >= HID_MAX_IDS) { + hid_err(parser->device, "report_id %u is invalid\n", + parser->global.report_id); return -1; } return 0; @@ -575,7 +579,7 @@ static void hid_close_report(struct hid_device *device) for (i = 0; i < HID_REPORT_TYPES; i++) { struct hid_report_enum *report_enum = device->report_enum + i; - for (j = 0; j < 256; j++) { + for (j = 0; j < HID_MAX_IDS; j++) { struct hid_report *report = report_enum->report_id_hash[j]; if (report) hid_free_report(report); -- cgit v1.2.3-18-g5258 From a4be0ed39f2b1ea990804ea54e39bc42d17ed5a5 Mon Sep 17 00:00:00 2001 From: Stefan Achatz Date: Fri, 30 Aug 2013 14:10:07 +0200 Subject: HID: roccat: add support for KonePureOptical v2 KonePureOptical is a KonePure with different sensor. Signed-off-by: Stefan Achatz Signed-off-by: Jiri Kosina --- drivers/hid/hid-core.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/hid/hid-core.c') diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 627fea6593a..3c28e5bf367 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1694,6 +1694,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_ISKU) }, { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONEPLUS) }, { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONEPURE) }, + { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONEPURE_OPTICAL) }, { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KOVAPLUS) }, { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_LUA) }, { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_PYRA_WIRED) }, -- cgit v1.2.3-18-g5258 From be67b68d52fa28b9b721c47bb42068f0c1214855 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 28 Aug 2013 22:32:01 +0200 Subject: HID: check for NULL field when setting values Defensively check that the field to be worked on is not NULL. Signed-off-by: Kees Cook Cc: stable@kernel.org Signed-off-by: Jiri Kosina --- drivers/hid/hid-core.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/hid/hid-core.c') diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index ebf57813d31..dcd60eb3d5e 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1169,7 +1169,12 @@ EXPORT_SYMBOL_GPL(hid_alloc_report_buf); int hid_set_field(struct hid_field *field, unsigned offset, __s32 value) { - unsigned size = field->report_size; + unsigned size; + + if (!field) + return -1; + + size = field->report_size; hid_dump_input(field->report->device, field->usage + offset, value); -- cgit v1.2.3-18-g5258