Re: [PATCH] HID: usbhid: fix recurrent out-of-bounds bug in usbhid_parse()
From: Kees Cook <kees@kernel.org>
Date: 2025-01-29 01:53:18
Also in:
linux-hardening, linux-usb, lkml
On Tue, Jan 28, 2025 at 12:00:41PM -0500, Alan Stern wrote:
On Tue, Jan 28, 2025 at 05:45:21AM -0800, Nikita Zhandarovich wrote:quoted
Hello, On 6/4/24 10:45, Alan Stern wrote:quoted
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,I didn't make that suggestion. Kees Cook did.quoted
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.The hidg_desc structure needs to contain room for a single hid_descriptor containing a single hid_class_descriptor. I think you can define it that way by doing something like this: static struct hid_descriptor hidg_desc = { .bLength = sizeof hidg_desc, .bDescriptorType = HID_DT_HID, .bcdHID = cpu_to_le16(0x0101), .bCountryCode = 0x00, .bNumDescriptors = 0x1, .desc = { { .bDescriptorType = 0, /* DYNAMIC */ .wDescriptorLength = 0, /* DYNAMIC */ } } }; Or maybe it needs to be: .desc = { {0, 0} } /* DYNAMIC */ I'm not sure what is the correct syntax; you'll have to figure that out.
Either should work.
You'll have to be more careful about the definition of hidg_desc_copy in hidg_setup(), however. You might want to define hidg_desc_copy as an alias to the start of a byte array of the right size.
For an on-stack fixed-size flex array structure, you can use: DEFINE_FLEX(struct hid_descriptor, hidg_desc_copy, desc, bNumDescriptors, 1); *hidg_desc_copy = hidg_desc; and then adjust the "hidg_desc_copy." instances to "hidg_desc_copy->"
quoted
Is this approach still worthy pursuing or should I look into some neater solution?I think you should persist with this approach. Alan Stern
-- Kees Cook