There doesn't seem to be much interest in this problem, so I'll just use
this change locally to solve my issue.
Though isn't it a tiny buffer overflow if a malicious or broken USB
device sends a bLength of 255 and actually follows through with it?
usb_string_descriptor_t is only 254 bytes.
On Sun, Aug 21, 2022 at 12:35:00AM -0400, bug wrote:
> I got a StarTech SV431USBDDM KVM switch, and it specifically mangles the
> string descriptor responses for my keyboard (which otherwise works just
> fine) when probed about the vendor string after plugging in or resetting
> the device.
>
> After a ton of messing around, I also found out that this problem just
> isn't happening at all if OpenBSD only sends a single string descriptor
> request with the maximum possible length, rather than two as it
> currently does.
>
> According to the USB 2.0 and 3.2 specs, devices that receive a larger
> wLength than the descriptor's actual length /should/ just send the full
> descriptor in a short packet. Of course, the current behavior isn't
> wrong either, if the wLength is shorter, then only the initial bytes or
> length (depending on the spec) /should/ be sent.
>
> (So unless there's some deeper bug in OpenBSD, my KVM switch is totally
> dropping the ball either way. I'll probably post about it on Misc later,
> unless details are desired here...)
>
> But I'm curious if there's a reason for sending two separate packets
> when one should be fine. Do certain USB devices expect it that way?
>
> I suppose it seems Windows does it this way too (the only reason the
> switch works there is because they neglect to check the vendor string),
> so the answer to that could very well be a hard yes...
>
> This is my first post, so sorry in advance if I did anything dumb. Diff
> provided for context.
>
>
> Index: usb_subr.c
> ===
> RCS file: /cvs/src/sys/dev/usb/usb_subr.c,v
> retrieving revision 1.158
> diff -u -p -r1.158 usb_subr.c
> --- usb_subr.c16 Feb 2022 06:23:42 - 1.158
> +++ usb_subr.c21 Aug 2022 03:33:10 -
> @@ -125,20 +125,17 @@ usbd_get_string_desc(struct usbd_device
> req.bRequest = UR_GET_DESCRIPTOR;
> USETW2(req.wValue, UDESC_STRING, sindex);
> USETW(req.wIndex, langid);
> - USETW(req.wLength, 2); /* size and descriptor type first */
> + USETW(req.wLength, sizeof(*sdesc)); /* size and descriptor type
> first */
> +
> err = usbd_do_request_flags(dev, , sdesc, USBD_SHORT_XFER_OK,
> , USBD_DEFAULT_TIMEOUT);
> +
> if (err)
> return (err);
>
> if (actlen < 2)
> return (USBD_SHORT_XFER);
>
> - USETW(req.wLength, sdesc->bLength); /* the whole string */
> - err = usbd_do_request_flags(dev, , sdesc, USBD_SHORT_XFER_OK,
> - , USBD_DEFAULT_TIMEOUT);
> - if (err)
> - return (err);
>
> if (actlen != sdesc->bLength) {
> DPRINTFN(-1, ("%s: expected %d, got %d\n", __func__,
>