Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

HID: usbhid: paper over wrong bNumDescriptor field

Some faulty devices (ZWO EFWmini) have a wrong optional HID class
descriptor count compared to the provided length.

Given that we plainly ignore those optional descriptor, we can attempt
to fix the provided number so we do not lock out those devices.

Signed-off-by: Benjamin Tissoires <bentiss@kernel.org>

+16 -1
+16 -1
drivers/hid/usbhid/hid-core.c
··· 985 985 struct usb_device *dev = interface_to_usbdev (intf); 986 986 struct hid_descriptor *hdesc; 987 987 struct hid_class_descriptor *hcdesc; 988 + __u8 fixed_opt_descriptors_size; 988 989 u32 quirks = 0; 989 990 unsigned int rsize = 0; 990 991 char *rdesc; ··· 1016 1015 (hdesc->bNumDescriptors - 1) * sizeof(*hcdesc)) { 1017 1016 dbg_hid("hid descriptor invalid, bLen=%hhu bNum=%hhu\n", 1018 1017 hdesc->bLength, hdesc->bNumDescriptors); 1019 - return -EINVAL; 1018 + 1019 + /* 1020 + * Some devices may expose a wrong number of descriptors compared 1021 + * to the provided length. 1022 + * However, we ignore the optional hid class descriptors entirely 1023 + * so we can safely recompute the proper field. 1024 + */ 1025 + if (hdesc->bLength >= sizeof(*hdesc)) { 1026 + fixed_opt_descriptors_size = hdesc->bLength - sizeof(*hdesc); 1027 + 1028 + hid_warn(intf, "fixing wrong optional hid class descriptors count\n"); 1029 + hdesc->bNumDescriptors = fixed_opt_descriptors_size / sizeof(*hcdesc) + 1; 1030 + } else { 1031 + return -EINVAL; 1032 + } 1020 1033 } 1021 1034 1022 1035 hid->version = le16_to_cpu(hdesc->bcdHID);