Skip to content

Commit fe7f7ac

Browse files
Terry JungeJiri Kosina
authored andcommitted
HID: usbhid: Eliminate recurrent out-of-bounds bug in usbhid_parse()
Update struct hid_descriptor to better reflect the mandatory and optional parts of the HID Descriptor as per USB HID 1.11 specification. Note: the kernel currently does not parse any optional HID class descriptors, only the mandatory report descriptor. Update all references to member element desc[0] to rpt_desc. Add test to verify bLength and bNumDescriptors values are valid. Replace the for loop with direct access to the mandatory HID class descriptor member for the report descriptor. This eliminates the possibility of getting an out-of-bounds fault. Add a warning message if the HID descriptor contains any unsupported optional HID class descriptors. Reported-by: syzbot+c52569baf0c843f35495@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=c52569baf0c843f35495 Fixes: f043bfc ("HID: usbhid: fix out-of-bounds bug") Cc: stable@vger.kernel.org Signed-off-by: Terry Junge <linuxhid@cosmicgizmosystems.com> Reviewed-by: Michael Kelley <mhklinux@outlook.com> Signed-off-by: Jiri Kosina <jkosina@suse.com>
1 parent 5e06802 commit fe7f7ac

File tree

4 files changed

+24
-20
lines changed

4 files changed

+24
-20
lines changed

drivers/hid/hid-hyperv.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ static void mousevsc_on_receive_device_info(struct mousevsc_dev *input_device,
192192
goto cleanup;
193193

194194
input_device->report_desc_size = le16_to_cpu(
195-
desc->desc[0].wDescriptorLength);
195+
desc->rpt_desc.wDescriptorLength);
196196
if (input_device->report_desc_size == 0) {
197197
input_device->dev_info_status = -EINVAL;
198198
goto cleanup;
@@ -210,7 +210,7 @@ static void mousevsc_on_receive_device_info(struct mousevsc_dev *input_device,
210210

211211
memcpy(input_device->report_desc,
212212
((unsigned char *)desc) + desc->bLength,
213-
le16_to_cpu(desc->desc[0].wDescriptorLength));
213+
le16_to_cpu(desc->rpt_desc.wDescriptorLength));
214214

215215
/* Send the ack */
216216
memset(&ack, 0, sizeof(struct mousevsc_prt_msg));

drivers/hid/usbhid/hid-core.c

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -984,12 +984,11 @@ static int usbhid_parse(struct hid_device *hid)
984984
struct usb_host_interface *interface = intf->cur_altsetting;
985985
struct usb_device *dev = interface_to_usbdev (intf);
986986
struct hid_descriptor *hdesc;
987+
struct hid_class_descriptor *hcdesc;
987988
u32 quirks = 0;
988989
unsigned int rsize = 0;
989990
char *rdesc;
990-
int ret, n;
991-
int num_descriptors;
992-
size_t offset = offsetof(struct hid_descriptor, desc);
991+
int ret;
993992

994993
quirks = hid_lookup_quirk(hid);
995994

@@ -1011,20 +1010,19 @@ static int usbhid_parse(struct hid_device *hid)
10111010
return -ENODEV;
10121011
}
10131012

1014-
if (hdesc->bLength < sizeof(struct hid_descriptor)) {
1015-
dbg_hid("hid descriptor is too short\n");
1013+
if (!hdesc->bNumDescriptors ||
1014+
hdesc->bLength != sizeof(*hdesc) +
1015+
(hdesc->bNumDescriptors - 1) * sizeof(*hcdesc)) {
1016+
dbg_hid("hid descriptor invalid, bLen=%hhu bNum=%hhu\n",
1017+
hdesc->bLength, hdesc->bNumDescriptors);
10161018
return -EINVAL;
10171019
}
10181020

10191021
hid->version = le16_to_cpu(hdesc->bcdHID);
10201022
hid->country = hdesc->bCountryCode;
10211023

1022-
num_descriptors = min_t(int, hdesc->bNumDescriptors,
1023-
(hdesc->bLength - offset) / sizeof(struct hid_class_descriptor));
1024-
1025-
for (n = 0; n < num_descriptors; n++)
1026-
if (hdesc->desc[n].bDescriptorType == HID_DT_REPORT)
1027-
rsize = le16_to_cpu(hdesc->desc[n].wDescriptorLength);
1024+
if (hdesc->rpt_desc.bDescriptorType == HID_DT_REPORT)
1025+
rsize = le16_to_cpu(hdesc->rpt_desc.wDescriptorLength);
10281026

10291027
if (!rsize || rsize > HID_MAX_DESCRIPTOR_SIZE) {
10301028
dbg_hid("weird size of report descriptor (%u)\n", rsize);
@@ -1052,6 +1050,11 @@ static int usbhid_parse(struct hid_device *hid)
10521050
goto err;
10531051
}
10541052

1053+
if (hdesc->bNumDescriptors > 1)
1054+
hid_warn(intf,
1055+
"%u unsupported optional hid class descriptors\n",
1056+
(int)(hdesc->bNumDescriptors - 1));
1057+
10551058
hid->quirks |= quirks;
10561059

10571060
return 0;

drivers/usb/gadget/function/f_hid.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -144,8 +144,8 @@ static struct hid_descriptor hidg_desc = {
144144
.bcdHID = cpu_to_le16(0x0101),
145145
.bCountryCode = 0x00,
146146
.bNumDescriptors = 0x1,
147-
/*.desc[0].bDescriptorType = DYNAMIC */
148-
/*.desc[0].wDescriptorLenght = DYNAMIC */
147+
/*.rpt_desc.bDescriptorType = DYNAMIC */
148+
/*.rpt_desc.wDescriptorLength = DYNAMIC */
149149
};
150150

151151
/* Super-Speed Support */
@@ -939,8 +939,8 @@ static int hidg_setup(struct usb_function *f,
939939
struct hid_descriptor hidg_desc_copy = hidg_desc;
940940

941941
VDBG(cdev, "USB_REQ_GET_DESCRIPTOR: HID\n");
942-
hidg_desc_copy.desc[0].bDescriptorType = HID_DT_REPORT;
943-
hidg_desc_copy.desc[0].wDescriptorLength =
942+
hidg_desc_copy.rpt_desc.bDescriptorType = HID_DT_REPORT;
943+
hidg_desc_copy.rpt_desc.wDescriptorLength =
944944
cpu_to_le16(hidg->report_desc_length);
945945

946946
length = min_t(unsigned short, length,
@@ -1210,8 +1210,8 @@ static int hidg_bind(struct usb_configuration *c, struct usb_function *f)
12101210
* We can use hidg_desc struct here but we should not relay
12111211
* that its content won't change after returning from this function.
12121212
*/
1213-
hidg_desc.desc[0].bDescriptorType = HID_DT_REPORT;
1214-
hidg_desc.desc[0].wDescriptorLength =
1213+
hidg_desc.rpt_desc.bDescriptorType = HID_DT_REPORT;
1214+
hidg_desc.rpt_desc.wDescriptorLength =
12151215
cpu_to_le16(hidg->report_desc_length);
12161216

12171217
hidg_hs_in_ep_desc.bEndpointAddress =

include/linux/hid.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -740,8 +740,9 @@ struct hid_descriptor {
740740
__le16 bcdHID;
741741
__u8 bCountryCode;
742742
__u8 bNumDescriptors;
743+
struct hid_class_descriptor rpt_desc;
743744

744-
struct hid_class_descriptor desc[1];
745+
struct hid_class_descriptor opt_descs[];
745746
} __attribute__ ((packed));
746747

747748
#define HID_DEVICE(b, g, ven, prod) \

0 commit comments

Comments
 (0)