Re: [PATCH] HID: usbhid: fix recurrent out-of-bounds bug in usbhid_parse()
From: Nikita Zhandarovich <hidden>
Date: 2025-01-28 13:45:24
Also in:
linux-hardening, linux-usb, lkml
Hello, On 6/4/24 10:45, Alan Stern wrote:
On Tue, Jun 04, 2024 at 10:21:15AM -0700, Kees Cook wrote:quoted
On Tue, Jun 04, 2024 at 10:09:43AM -0700, Nikita Zhandarovich wrote:quoted
Hi, On 6/4/24 07:15, Jiri Kosina wrote:quoted
On Tue, 4 Jun 2024, Kees Cook wrote:quoted
This isn't the right solution. The problem is that hid_class_descriptor is a flexible array but was sized as a single element fake flexible array: struct hid_descriptor { __u8 bLength; __u8 bDescriptorType; __le16 bcdHID; __u8 bCountryCode; __u8 bNumDescriptors; struct hid_class_descriptor desc[1]; } __attribute__ ((packed)); This likely needs to be: struct hid_class_descriptor desc[] __counted_by(bNumDescriptors); And then check for any sizeof() uses of the struct that might have changed.
Alan, I finally got around to preparing a revised version of the required patch and encountered a few issues. I could use some advice in this matter... If we change 'struct hid_descriptor' as you suggested, which does make sense, most occurrences of that type are easy enough to fix. 1) usbhid_parse() starts working properly if there are more than 1 descriptors, sizeof(struct hid_descriptor) may be turned into something crude but straightforward like sizeof(struct hid_descriptor) + sizeof(struct hid_class_descriptor). 2) 'hid_descriptor' in drivers/hid/hid-hyperv.c remains innocuous as well as only 1 descriptor expected there. My impression is only some small changes are needed there. However, the issue that stumps me is the following: static struct hid_descriptor hidg_desc in drivers/usb/gadget/function/f_hid.c relies on a static nature of that one descriptor. hidg_desc ends up being used elsewhere, in other static structures. Basically, using __counted_by requires a lot of changes, as I see it, out of scope of merely closing an UBSAN error. Is this approach still worthy pursuing or should I look into some neater solution? Best regards, Nikita
quoted
quoted
quoted
Ah, you are of course right, not sure what I was thinking. Thanks a lot for catching my brainfart. I am dropping the patch for now; Nikita, will you please send a refreshed one?Thanks for catching my mistake. I'll gladly send a revised version, hoping to do it very soon.I spent a little more time looking at this, and I'm not sure I understand where the actual space for the descriptors comes from? There's interface->extra that is being parsed, and effectively hid_descriptor is being mapped into it, but it uses "sizeof(struct hid_descriptor)" for the limit.That's a lower limit, not an upper limit. The hid_descriptor must include at least one hid_class_descriptor, but it can include more. That's what the min_t() calculation of num_descriptors is meant to figure out.quoted
Is more than 1 descriptor expected to work correctly?More than one hid_class_descriptor -- yes.quoted
Or is the limit being ignored? I'm a bit confused by this code...Does this explain it? Alan Stern