This is an automated email from the ASF dual-hosted git repository. acassis pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/nuttx.git
commit 6f6d141c65a29033a623f8c6519b2476299570c7 Author: chao an <[email protected]> AuthorDate: Thu Oct 29 14:27:46 2026 +0800 drivers/usbhost: Validate config descriptor walk The USB configuration descriptor walker trusted descriptor lengths while searching for an interface descriptor. Malformed descriptors with a zero or over-sized bLength could keep the walk from advancing or make it read fields past the received configuration buffer. Add runtime checks for the configuration descriptor header and for each nested descriptor before reading interface fields or advancing to the next entry. Signed-off-by: chao an <[email protected]> --- drivers/usbhost/usbhost_enumerate.c | 39 +++++++++++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/drivers/usbhost/usbhost_enumerate.c b/drivers/usbhost/usbhost_enumerate.c index cd27b9f8427..4f5f9587c6e 100644 --- a/drivers/usbhost/usbhost_enumerate.c +++ b/drivers/usbhost/usbhost_enumerate.c @@ -147,17 +147,23 @@ static inline int usbhost_configdesc(const uint8_t *configdesc, int cfglen, struct usbhost_id_s *id) { FAR struct usb_cfgdesc_s *cfgdesc; + FAR struct usb_desc_s *desc; FAR struct usb_ifdesc_s *ifdesc; int remaining; + int desclen; - DEBUGASSERT(configdesc != NULL && cfglen >= USB_SIZEOF_CFGDESC); + if (configdesc == NULL || cfglen < USB_SIZEOF_CFGDESC) + { + return -EINVAL; + } /* Verify that we were passed a configuration descriptor */ cfgdesc = (struct usb_cfgdesc_s *)configdesc; uinfo("cfg len:%d total len:%d\n", cfgdesc->len, cfglen); - if (cfgdesc->type != USB_DESC_TYPE_CONFIG) + if (cfgdesc->type != USB_DESC_TYPE_CONFIG || + cfgdesc->len < USB_SIZEOF_CFGDESC || cfgdesc->len > cfglen) { return -EINVAL; } @@ -174,17 +180,33 @@ static inline int usbhost_configdesc(const uint8_t *configdesc, int cfglen, { /* What is the next descriptor? Is it an interface descriptor? */ - ifdesc = (struct usb_ifdesc_s *)configdesc; - if (ifdesc->type == USB_DESC_TYPE_INTERFACE && - ifdesc->ifno >= start_ifnum) + desc = (FAR struct usb_desc_s *)configdesc; + desclen = desc->len; + + if (desclen < sizeof(struct usb_desc_s) || desclen > remaining) + { + return -EINVAL; + } + + if (desc->type == USB_DESC_TYPE_INTERFACE) { + if (desclen < USB_SIZEOF_IFDESC) + { + return -EINVAL; + } + + ifdesc = (FAR struct usb_ifdesc_s *)configdesc; + if (ifdesc->ifno < start_ifnum) + { + goto next_desc; + } + /* Yes, extract the class information from the interface * descriptor. * Typically these values are zero meaning that the "real" ID * information resides in the device descriptor. */ - DEBUGASSERT(remaining >= sizeof(struct usb_ifdesc_s)); id->base = ifdesc->classid; id->subclass = ifdesc->subclass; id->proto = ifdesc->protocol; @@ -196,8 +218,9 @@ static inline int usbhost_configdesc(const uint8_t *configdesc, int cfglen, /* Increment the address of the next descriptor */ - configdesc += ifdesc->len; - remaining -= ifdesc->len; +next_desc: + configdesc += desclen; + remaining -= desclen; } return -ENOENT;
