diff options
| author | seteiro <[email protected]> | 2026-11-11 16:19:37 +0000 |
|---|---|---|
| committer | Rbb666 <[email protected]> | 2026-11-13 09:47:14 +0800 |
| commit | 5114bfecc77b3f433edb8db776b7e5e7ce776f35 (patch) | |
| tree | 60fc6c583c5176e065f49cb857adad6554415caf | |
| parent | def57de5964ee93614ad803af19abc610a720269 (diff) | |
[legacy][usbhost] validate device descriptor bLength before full read
Fix #12026
rt_usbh_attatch_instance() reads the 8-byte device descriptor head and then
reuses the device-supplied bLength as the transfer length for the full
descriptor into the 18-byte dev_desc field of the static dev[] array. A
peripheral that reports a larger bLength can overwrite the following
instance fields (cfg_desc, hcd, pipe, intf) with device-controlled bytes,
which are then used as pointers and indirect call targets.
Reject any bLength other than sizeof(struct udevice_descriptor) right after
the head read, so enumeration stops before the full transfer.
Also bound the sibling lengths called out by the same audit:
- the hub class descriptor length must cover the 8-byte head read and fit
struct uhub_descriptor before the full read;
- hub and HID interrupt transfers clamp the endpoint wMaxPacketSize to the
8-byte hub/hid buffer instead of trusting the device value.
No device-side changes and no malicious descriptor PoC.
| -rw-r--r-- | components/legacy/usb/usbhost/class/hid.c | 14 | ||||
| -rw-r--r-- | components/legacy/usb/usbhost/class/ukbd.c | 15 | ||||
| -rw-r--r-- | components/legacy/usb/usbhost/class/umouse.c | 15 | ||||
| -rw-r--r-- | components/legacy/usb/usbhost/core/hub.c | 32 | ||||
| -rw-r--r-- | components/legacy/usb/usbhost/core/usbhost_core.c | 8 |
5 files changed, 71 insertions, 13 deletions
diff --git a/components/legacy/usb/usbhost/class/hid.c b/components/legacy/usb/usbhost/class/hid.c index 5911faf1aa..ccd3183269 100644 --- a/components/legacy/usb/usbhost/class/hid.c +++ b/components/legacy/usb/usbhost/class/hid.c @@ -244,6 +244,7 @@ static void rt_usbh_hid_callback(void* context) upipe_t pipe; struct uhid* hid; int timeout = USB_TIMEOUT_LONG; + rt_size_t xfer_len; /* parameter check */ RT_ASSERT(context != RT_NULL); @@ -254,11 +255,18 @@ static void rt_usbh_hid_callback(void* context) /* invoke protocal callback function */ hid->protocal->callback((void*)hid); + /* the endpoint packet size is device controlled and may exceed buffer */ + xfer_len = pipe->ep.wMaxPacketSize; + if (xfer_len > sizeof(hid->buffer)) + { + xfer_len = sizeof(hid->buffer); + } + /* parameter check */ - RT_ASSERT(((struct uhintf*)pipe->inst)->device->hcd != RT_NULL); + RT_ASSERT(((struct uhintf *)pipe->inst)->device->hcd != RT_NULL); - rt_usb_hcd_pipe_xfer(((struct uhintf*)pipe->inst)->device->hcd, pipe, - hid->buffer, pipe->ep.wMaxPacketSize, timeout); + rt_usb_hcd_pipe_xfer(((struct uhintf *)pipe->inst)->device->hcd, pipe, + hid->buffer, xfer_len, timeout); } /** diff --git a/components/legacy/usb/usbhost/class/ukbd.c b/components/legacy/usb/usbhost/class/ukbd.c index db080ed406..1c55df407a 100644 --- a/components/legacy/usb/usbhost/class/ukbd.c +++ b/components/legacy/usb/usbhost/class/ukbd.c @@ -42,11 +42,20 @@ static rt_thread_t kbd_thread; static void kbd_task(void* param) { struct uhintf* intf = (struct uhintf*)param; + struct uhid *hid = (struct uhid *)intf->user_data; + rt_size_t xfer_len; + + /* the endpoint packet size is device controlled and may exceed buffer */ + xfer_len = hid->pipe_in->ep.wMaxPacketSize; + if (xfer_len > sizeof(hid->buffer)) + { + xfer_len = sizeof(hid->buffer); + } + while (1) { - if (rt_usb_hcd_pipe_xfer(intf->device->hcd, ((struct uhid*)intf->user_data)->pipe_in, - ((struct uhid*)intf->user_data)->buffer, ((struct uhid*)intf->user_data)->pipe_in->ep.wMaxPacketSize, - USB_TIMEOUT_BASIC) == 0) + if (rt_usb_hcd_pipe_xfer(intf->device->hcd, hid->pipe_in, + hid->buffer, xfer_len, USB_TIMEOUT_BASIC) == 0) { break; } diff --git a/components/legacy/usb/usbhost/class/umouse.c b/components/legacy/usb/usbhost/class/umouse.c index dfd6e9081c..53a4234876 100644 --- a/components/legacy/usb/usbhost/class/umouse.c +++ b/components/legacy/usb/usbhost/class/umouse.c @@ -135,11 +135,20 @@ static rt_thread_t mouse_thread; static void mouse_task(void* param) { struct uhintf* intf = (struct uhintf*)param; + struct uhid *hid = (struct uhid *)intf->user_data; + rt_size_t xfer_len; + + /* the endpoint packet size is device controlled and may exceed buffer */ + xfer_len = hid->pipe_in->ep.wMaxPacketSize; + if (xfer_len > sizeof(hid->buffer)) + { + xfer_len = sizeof(hid->buffer); + } + while (1) { - if (rt_usb_hcd_pipe_xfer(intf->device->hcd, ((struct uhid*)intf->user_data)->pipe_in, - ((struct uhid*)intf->user_data)->buffer, ((struct uhid*)intf->user_data)->pipe_in->ep.wMaxPacketSize, - USB_TIMEOUT_BASIC) == 0) + if (rt_usb_hcd_pipe_xfer(intf->device->hcd, hid->pipe_in, + hid->buffer, xfer_len, USB_TIMEOUT_BASIC) == 0) { break; } diff --git a/components/legacy/usb/usbhost/core/hub.c b/components/legacy/usb/usbhost/core/hub.c index d8e6716099..614e448165 100644 --- a/components/legacy/usb/usbhost/core/hub.c +++ b/components/legacy/usb/usbhost/core/hub.c @@ -468,6 +468,7 @@ static void rt_usbh_hub_irq(void* context) upipe_t pipe; uhub_t hub; int timeout = USB_TIMEOUT_BASIC; + rt_size_t xfer_len; RT_ASSERT(context != RT_NULL); @@ -484,10 +485,17 @@ static void rt_usbh_hub_irq(void* context) LOG_D("hub int xfer..."); + /* the endpoint packet size is device controlled and may exceed buffer */ + xfer_len = pipe->ep.wMaxPacketSize; + if (xfer_len > sizeof(hub->buffer)) + { + xfer_len = sizeof(hub->buffer); + } + /* parameter check */ - RT_ASSERT(pipe->inst->hcd != RT_NULL); + RT_ASSERT(pipe->inst->hcd != RT_NULL); - rt_usb_hcd_pipe_xfer(hub->self->hcd, pipe, hub->buffer, pipe->ep.wMaxPacketSize, timeout); + rt_usb_hcd_pipe_xfer(hub->self->hcd, pipe, hub->buffer, xfer_len, timeout); } /** @@ -509,6 +517,7 @@ static rt_err_t rt_usbh_hub_enable(void *arg) struct uhintf* intf = (struct uhintf*)arg; upipe_t pipe_in = RT_NULL; int timeout = USB_TIMEOUT_LONG; + rt_size_t xfer_len; /* paremeter check */ RT_ASSERT(intf != RT_NULL); @@ -531,6 +540,15 @@ static rt_err_t rt_usbh_hub_enable(void *arg) return -RT_ERROR; } + /* length is device supplied and is reused as the next read size into + * hub_desc; it must cover the head read and fit the descriptor field. */ + if (hub->hub_desc.length < 8 || + hub->hub_desc.length > sizeof(struct uhub_descriptor)) + { + rt_kprintf("invalid hub descriptor length %d\n", hub->hub_desc.length); + return -RT_ERROR; + } + /* get full hub descriptor */ ret = rt_usbh_hub_get_descriptor(device, (rt_uint8_t*)&hub->hub_desc, hub->hub_desc.length); @@ -589,8 +607,14 @@ static rt_err_t rt_usbh_hub_enable(void *arg) /* parameter check */ RT_ASSERT(device->hcd != RT_NULL); pipe_in->user_data = hub; - rt_usb_hcd_pipe_xfer(hub->hcd, pipe_in, hub->buffer, - pipe_in->ep.wMaxPacketSize, timeout); + + xfer_len = pipe_in->ep.wMaxPacketSize; + if (xfer_len > sizeof(hub->buffer)) + { + xfer_len = sizeof(hub->buffer); + } + + rt_usb_hcd_pipe_xfer(hub->hcd, pipe_in, hub->buffer, xfer_len, timeout); return RT_EOK; } diff --git a/components/legacy/usb/usbhost/core/usbhost_core.c b/components/legacy/usb/usbhost/core/usbhost_core.c index 6fea444b02..c81a3be10c 100644 --- a/components/legacy/usb/usbhost/core/usbhost_core.c +++ b/components/legacy/usb/usbhost/core/usbhost_core.c @@ -145,6 +145,14 @@ rt_err_t rt_usbh_attatch_instance(uinst_t device) LOG_D("get device descriptor length %d", dev_desc->bLength); + /* bLength is device controlled and is reused as the size of the next + * transfer into dev_desc. Reject anything but the standard size. */ + if (dev_desc->bLength != sizeof(struct udevice_descriptor)) + { + LOG_E("invalid device descriptor length %d", dev_desc->bLength); + return -RT_EINVAL; + } + /* get full device descriptor again */ ret = rt_usbh_get_descriptor(device, USB_DESC_TYPE_DEVICE, (void*)dev_desc, dev_desc->bLength); if(ret != RT_EOK) |
