]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
HID: usbhid: paper over wrong bNumDescriptor field
authorBenjamin Tissoires <bentiss@kernel.org>
Mon, 15 Dec 2025 11:57:21 +0000 (12:57 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 6 Feb 2026 15:43:57 +0000 (16:43 +0100)
commit f28beb69c51517aec7067dfb2074e7c751542384 upstream.

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>
Cc: Salvatore Bonaccorso <carnil@debian.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/hid/usbhid/hid-core.c

index eb6841d1957fa243ce0cdeda3176e5d27df1f6a1..352c9327d08b26f1edda7d5113bc3356396d6600 100644 (file)
@@ -983,6 +983,7 @@ static int usbhid_parse(struct hid_device *hid)
        struct usb_device *dev = interface_to_usbdev (intf);
        struct hid_descriptor *hdesc;
        struct hid_class_descriptor *hcdesc;
+       __u8 fixed_opt_descriptors_size;
        u32 quirks = 0;
        unsigned int rsize = 0;
        char *rdesc;
@@ -1013,7 +1014,21 @@ static int usbhid_parse(struct hid_device *hid)
                              (hdesc->bNumDescriptors - 1) * sizeof(*hcdesc)) {
                dbg_hid("hid descriptor invalid, bLen=%hhu bNum=%hhu\n",
                        hdesc->bLength, hdesc->bNumDescriptors);
-               return -EINVAL;
+
+               /*
+                * Some devices may expose a wrong number of descriptors compared
+                * to the provided length.
+                * However, we ignore the optional hid class descriptors entirely
+                * so we can safely recompute the proper field.
+                */
+               if (hdesc->bLength >= sizeof(*hdesc)) {
+                       fixed_opt_descriptors_size = hdesc->bLength - sizeof(*hdesc);
+
+                       hid_warn(intf, "fixing wrong optional hid class descriptors count\n");
+                       hdesc->bNumDescriptors = fixed_opt_descriptors_size / sizeof(*hcdesc) + 1;
+               } else {
+                       return -EINVAL;
+               }
        }
 
        hid->version = le16_to_cpu(hdesc->bcdHID);