FAILED: patch "[PATCH] HID: usbhid: Eliminate recurrent out-of-bounds bug in" failed to apply to 5.15-stable tree
Subsystems (5)
[email protected]
maintainerThe patch below does not apply to the 5.15-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-5.15.y
git checkout FETCH_HEAD
git cherry-pick -x fe7f7ac8e0c708446ff017453add769ffc15deed
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2025061738-circus-skipping-ed0c@gregkh' --subject-prefix 'PATCH 5.15.y' HEAD^..
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From fe7f7ac8e0c708446ff017453add769ffc15deed Mon Sep 17 00:00:00 2001
From: Terry Junge <[email protected]>
Date: Wed, 12 Mar 2025 15:23:31 -0700
Subject: [PATCH] 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.
drivers/hid/hid-hyperv.c +2 -2
@@ -192,7 +192,7 @@ static void mousevsc_on_receive_device_info(struct mousevsc_dev *input_device, goto cleanup; input_device->report_desc_size =le16_to_cpu ( - desc->desc[0 ].wDescriptorLength); + desc->rpt_desc.wDescriptorLength);if (input_device->report_desc_size ==0 ) { input_device->dev_info_status = -EINVAL ; goto cleanup;
@@ -210,7 +210,7 @@ static void mousevsc_on_receive_device_info(struct mousevsc_dev *input_device,memcpy (input_device->report_desc, ((unsigned char *)desc) + desc->bLength, -le16_to_cpu (desc->desc[0 ].wDescriptorLength)); +le16_to_cpu (desc->rpt_desc.wDescriptorLength));/* Send the ack */ memset (&ack,0 ,sizeof (struct mousevsc_prt_msg ));
drivers/hid/usbhid/hid-core.c +14 -11
@@ -984,12 +984,11 @@ static int usbhid_parse(struct hid_device *hid)struct usb_host_interface *interface = intf->cur_altsetting;struct usb_device *dev =interface_to_usbdev (intf);struct hid_descriptor *hdesc; +struct hid_class_descriptor *hcdesc;u32 quirks =0 ;unsigned int rsize =0 ;char *rdesc; -int ret, n; -int num_descriptors; -size_t offset = offsetof(struct hid_descriptor , desc); +int ret; quirks =hid_lookup_quirk (hid);
@@ -1011,20 +1010,19 @@ static int usbhid_parse(struct hid_device *hid)return -ENODEV ; } -if (hdesc->bLength <sizeof (struct hid_descriptor )) { -dbg_hid ("hid descriptor is too short\n" ); +if (!hdesc->bNumDescriptors || + hdesc->bLength !=sizeof (*hdesc) + + (hdesc->bNumDescriptors -1 ) *sizeof (*hcdesc)) { +dbg_hid ("hid descriptor invalid, bLen=%hhu bNum=%hhu\n" , + hdesc->bLength, hdesc->bNumDescriptors);return -EINVAL ; } hid->version =le16_to_cpu (hdesc->bcdHID); hid->country = hdesc->bCountryCode; - num_descriptors =min_t (int, hdesc->bNumDescriptors, - (hdesc->bLength - offset) /sizeof (struct hid_class_descriptor )); - -for (n =0 ; n < num_descriptors; n++) -if (hdesc->desc[n].bDescriptorType ==HID_DT_REPORT ) - rsize =le16_to_cpu (hdesc->desc[n].wDescriptorLength); +if (hdesc->rpt_desc.bDescriptorType ==HID_DT_REPORT ) + rsize =le16_to_cpu (hdesc->rpt_desc.wDescriptorLength);if (!rsize || rsize >HID_MAX_DESCRIPTOR_SIZE ) {dbg_hid ("weird size of report descriptor (%u)\n" , rsize);
@@ -1052,6 +1050,11 @@ static int usbhid_parse(struct hid_device *hid) goto err; } +if (hdesc->bNumDescriptors >1 ) +hid_warn (intf, +"%u unsupported optional hid class descriptors\n" , + (int )(hdesc->bNumDescriptors -1 )); + hid->quirks |= quirks;return 0 ;
drivers/usb/gadget/function/f_hid.c +6 -6
@@ -144,8 +144,8 @@ static struct hid_descriptor hidg_desc = { .bcdHID = cpu_to_le16(0x0101), .bCountryCode = 0x00, .bNumDescriptors = 0x1, -/*.desc[0].bDescriptorType = DYNAMIC */ -/*.desc[0].wDescriptorLenght = DYNAMIC */ +/*.rpt_desc.bDescriptorType = DYNAMIC */ +/*.rpt_desc.wDescriptorLength = DYNAMIC */ };/* Super-Speed Support */
@@ -939,8 +939,8 @@ static int hidg_setup(struct usb_function *f,struct hid_descriptor hidg_desc_copy = hidg_desc;VDBG (cdev,"USB_REQ_GET_DESCRIPTOR: HID\n" ); - hidg_desc_copy.desc[0 ].bDescriptorType =HID_DT_REPORT ; - hidg_desc_copy.desc[0 ].wDescriptorLength = + hidg_desc_copy.rpt_desc.bDescriptorType =HID_DT_REPORT ; + hidg_desc_copy.rpt_desc.wDescriptorLength =cpu_to_le16 (hidg->report_desc_length); length = min_t(unsigned short, length,
@@ -1210,8 +1210,8 @@ static int hidg_bind(struct usb_configuration *c, struct usb_function *f)* We can use hidg_desc struct here but we should not relay * that its content won't change after returning from this function. */ - hidg_desc.desc[0 ].bDescriptorType =HID_DT_REPORT ; - hidg_desc.desc[0 ].wDescriptorLength = + hidg_desc.rpt_desc.bDescriptorType =HID_DT_REPORT ; + hidg_desc.rpt_desc.wDescriptorLength =cpu_to_le16 (hidg->report_desc_length); hidg_hs_in_ep_desc.bEndpointAddress =
include/linux/hid.h +2 -1
@@ -740,8 +740,9 @@ struct hid_descriptor {__le16 bcdHID;__u8 bCountryCode;__u8 bNumDescriptors; +struct hid_class_descriptor rpt_desc; -struct hid_class_descriptor desc[1 ]; +struct hid_class_descriptor opt_descs[]; } __attribute__ ((packed));#define HID_DEVICE (b, g, ven, prod) \
PATCH 1/1 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.
--- drivers/hid/hid-hyperv.c | 5 +++-- drivers/hid/usbhid/hid-core.c | 25 ++++++++++++++----------- drivers/usb/gadget/function/f_hid.c | 12 ++++++------ include/linux/hid.h | 3 ++- 4 files changed, 25 insertions(+), 20 deletions(-)
drivers/hid/hid-hyperv.c +3 -2
@@ -199,7 +199,8 @@ static void mousevsc_on_receive_device_info(struct mousevsc_dev *input_device,if (!input_device->hid_desc) goto cleanup; - input_device->report_desc_size = desc->desc[0 ].wDescriptorLength; + input_device->report_desc_size =le16_to_cpu ( + desc->rpt_desc.wDescriptorLength);if (input_device->report_desc_size ==0 ) { input_device->dev_info_status = -EINVAL ; goto cleanup;
@@ -217,7 +218,7 @@ static void mousevsc_on_receive_device_info(struct mousevsc_dev *input_device,memcpy (input_device->report_desc, ((unsigned char *)desc) + desc->bLength, - desc->desc[0 ].wDescriptorLength); +le16_to_cpu (desc->rpt_desc.wDescriptorLength));/* Send the ack */ memset (&ack,0 ,sizeof (struct mousevsc_prt_msg ));
drivers/hid/usbhid/hid-core.c +14 -11
@@ -982,12 +982,11 @@ static int usbhid_parse(struct hid_device *hid)struct usb_host_interface *interface = intf->cur_altsetting;struct usb_device *dev =interface_to_usbdev (intf);struct hid_descriptor *hdesc; +struct hid_class_descriptor *hcdesc;u32 quirks =0 ;unsigned int rsize =0 ;char *rdesc; -int ret, n; -int num_descriptors; -size_t offset = offsetof(struct hid_descriptor , desc); +int ret; quirks =hid_lookup_quirk (hid);
@@ -1009,20 +1008,19 @@ static int usbhid_parse(struct hid_device *hid)return -ENODEV ; } -if (hdesc->bLength <sizeof (struct hid_descriptor )) { -dbg_hid ("hid descriptor is too short\n" ); +if (!hdesc->bNumDescriptors || + hdesc->bLength !=sizeof (*hdesc) + + (hdesc->bNumDescriptors -1 ) *sizeof (*hcdesc)) { +dbg_hid ("hid descriptor invalid, bLen=%hhu bNum=%hhu\n" , + hdesc->bLength, hdesc->bNumDescriptors);return -EINVAL ; } hid->version =le16_to_cpu (hdesc->bcdHID); hid->country = hdesc->bCountryCode; - num_descriptors =min_t (int, hdesc->bNumDescriptors, - (hdesc->bLength - offset) /sizeof (struct hid_class_descriptor )); - -for (n =0 ; n < num_descriptors; n++) -if (hdesc->desc[n].bDescriptorType ==HID_DT_REPORT ) - rsize =le16_to_cpu (hdesc->desc[n].wDescriptorLength); +if (hdesc->rpt_desc.bDescriptorType ==HID_DT_REPORT ) + rsize =le16_to_cpu (hdesc->rpt_desc.wDescriptorLength);if (!rsize || rsize >HID_MAX_DESCRIPTOR_SIZE ) {dbg_hid ("weird size of report descriptor (%u)\n" , rsize);
@@ -1050,6 +1048,11 @@ static int usbhid_parse(struct hid_device *hid) goto err; } +if (hdesc->bNumDescriptors >1 ) +hid_warn (intf, +"%u unsupported optional hid class descriptors\n" , + (int )(hdesc->bNumDescriptors -1 )); + hid->quirks |= quirks;return 0 ;
drivers/usb/gadget/function/f_hid.c +6 -6
@@ -114,8 +114,8 @@ static struct hid_descriptor hidg_desc = { .bcdHID = cpu_to_le16(0x0101), .bCountryCode = 0x00, .bNumDescriptors = 0x1, -/*.desc[0].bDescriptorType = DYNAMIC */ -/*.desc[0].wDescriptorLenght = DYNAMIC */ +/*.rpt_desc.bDescriptorType = DYNAMIC */ +/*.rpt_desc.wDescriptorLength = DYNAMIC */ };/* Super-Speed Support */
@@ -724,8 +724,8 @@ static int hidg_setup(struct usb_function *f,struct hid_descriptor hidg_desc_copy = hidg_desc;VDBG (cdev,"USB_REQ_GET_DESCRIPTOR: HID\n" ); - hidg_desc_copy.desc[0 ].bDescriptorType =HID_DT_REPORT ; - hidg_desc_copy.desc[0 ].wDescriptorLength = + hidg_desc_copy.rpt_desc.bDescriptorType =HID_DT_REPORT ; + hidg_desc_copy.rpt_desc.wDescriptorLength =cpu_to_le16 (hidg->report_desc_length); length = min_t(unsigned short, length,
@@ -966,8 +966,8 @@ static int hidg_bind(struct usb_configuration *c, struct usb_function *f)* We can use hidg_desc struct here but we should not relay * that its content won't change after returning from this function. */ - hidg_desc.desc[0 ].bDescriptorType =HID_DT_REPORT ; - hidg_desc.desc[0 ].wDescriptorLength = + hidg_desc.rpt_desc.bDescriptorType =HID_DT_REPORT ; + hidg_desc.rpt_desc.wDescriptorLength =cpu_to_le16 (hidg->report_desc_length); hidg_hs_in_ep_desc.bEndpointAddress =
include/linux/hid.h +2 -1
@@ -680,8 +680,9 @@ struct hid_descriptor {__le16 bcdHID;__u8 bCountryCode;__u8 bNumDescriptors; +struct hid_class_descriptor rpt_desc; -struct hid_class_descriptor desc[1 ]; +struct hid_class_descriptor opt_descs[]; } __attribute__ ((packed));#define HID_DEVICE (b, g, ven, prod) \
Signature · 1 line
2.43.0
Sasha Levin
maintainerRe: [PATCH 5.15.y] HID: usbhid: Eliminate recurrent out-of-bounds bug in usbhid_parse()
[ Sasha's backport helper bot ]
Hi,
Summary of potential issues:
⚠️ Found matching upstream commit but patch is missing proper reference to it
Found matching upstream commit: fe7f7ac8e0c708446ff017453add769ffc15deed
Status in newer kernel trees:
6.15.y | Present (different SHA1: 6dffa4488614) 6.12.y | Present (different SHA1: 549d235f4f07) 6.6.y | Present (different SHA1: cd2287ce05d8) 6.1.y | Present (different SHA1: 345ab0a1113c)
Note: The patch differs from the upstream commit:
---
1: fe7f7ac8e0c70 ! 1: 46a4432fb0033 HID: usbhid: Eliminate recurrent out-of-bounds bug in usbhid_parse()
@@ Commit message
Signed-off-by: Terry Junge <[email protected]>
Reviewed-by: Michael Kelley <[email protected]>
Signed-off-by: Jiri Kosina <[email protected]>
+ (cherry picked from commit fe7f7ac8e0c708446ff017453add769ffc15deed)
+ Signed-off-by: Terry Junge <[email protected]>
## drivers/hid/hid-hyperv.c ##
@@ drivers/hid/hid-hyperv.c: static void mousevsc_on_receive_device_info(struct mousevsc_dev *input_device,
+ if (!input_device->hid_desc)
goto cleanup;
- input_device->report_desc_size = le16_to_cpu(
-- desc->desc[0].wDescriptorLength);
+- input_device->report_desc_size = desc->desc[0].wDescriptorLength;
++ input_device->report_desc_size = le16_to_cpu(
+ desc->rpt_desc.wDescriptorLength);
if (input_device->report_desc_size == 0) {
input_device->dev_info_status = -EINVAL;
@@ drivers/hid/hid-hyperv.c: static void mousevsc_on_receive_device_info(struct mou
memcpy(input_device->report_desc,
((unsigned char *)desc) + desc->bLength,
-- le16_to_cpu(desc->desc[0].wDescriptorLength));
+- desc->desc[0].wDescriptorLength);
+ le16_to_cpu(desc->rpt_desc.wDescriptorLength));
/* Send the ack */---
Results of testing on various branches:
| Branch | Patch Apply | Build Test | |---------------------------|-------------|------------| | stable/linux-5.15.y | Success | Success |