diff options
| author | sakumisu <[email protected]> | 2026-10-22 12:41:45 +0800 |
|---|---|---|
| committer | sakumisu <[email protected]> | 2026-10-23 18:29:36 +0800 |
| commit | 2397226c48fea88bdb742651f9280f47eef3197a (patch) | |
| tree | 333db0904d5d3591a93a79f564c4a859f9957ae0 /class/audio | |
| parent | 26b0feb09bb58ebb7a3161b5605f8e186b96db1f (diff) | |
fix(security): check array overflowdev
Signed-off-by: sakumisu <[email protected]>
Diffstat (limited to 'class/audio')
| -rw-r--r-- | class/audio/usbh_audio.c | 71 |
1 files changed, 49 insertions, 22 deletions
diff --git a/class/audio/usbh_audio.c b/class/audio/usbh_audio.c index 5ef08c90..53fbcaa8 100644 --- a/class/audio/usbh_audio.c +++ b/class/audio/usbh_audio.c @@ -37,7 +37,8 @@ static int16_t volume_float2hex(float volume_db) return (int16_t)(volume_db * 256); } -static float volume_roundf(float x) { +static float volume_roundf(float x) +{ if (x >= 0.0f) { int intpart = (int)x; float frac = x - (float)intpart; @@ -367,12 +368,12 @@ intf_found: } static int usbh_audio_get_volume_info(struct usbh_audio *audio_class, - uint8_t ch, - int16_t *volume_cur, - int16_t *volume_min, - int16_t *volume_max, - int16_t *volume_res, - bool is_tx) + uint8_t ch, + int16_t *volume_cur, + int16_t *volume_min, + int16_t *volume_max, + int16_t *volume_res, + bool is_tx) { struct usb_setup_packet *setup; int ret; @@ -496,6 +497,10 @@ feature_found: return ret; } + if (volume_res <= 0 || volume_min > volume_max) { + return -USB_ERR_INVAL; + } + setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE; setup->bRequest = AUDIO_REQUEST_SET_CUR; setup->wValue = (AUDIO_FU_CONTROL_VOLUME << 8) | ch; @@ -660,10 +665,15 @@ static int usbh_audio_ctrl_connect(struct usbh_hubport *hport, uint8_t intf) hport->config.intf[intf].priv = audio_class; p = hport->raw_config_desc; - while (p[DESC_bLength]) { + while (desc_len < hport->config.config_desc.wTotalLength) { switch (p[DESC_bDescriptorType]) { case USB_DESCRIPTOR_TYPE_INTERFACE_ASSOCIATION: cur_iface_count = p[3]; + + if ((cur_iface_count - 1) > CONFIG_USBHOST_AUDIO_MAX_STREAMS) { + USB_LOG_ERR("Audio stream %u exceeds max %u\r\n", (cur_iface_count - 1), CONFIG_USBHOST_AUDIO_MAX_STREAMS); + return -USB_ERR_INVAL; + } break; case USB_DESCRIPTOR_TYPE_INTERFACE: cur_iface = p[INTF_DESC_bInterfaceNumber]; @@ -671,6 +681,7 @@ static int usbh_audio_ctrl_connect(struct usbh_hubport *hport, uint8_t intf) break; case USB_DESCRIPTOR_TYPE_ENDPOINT: if (cur_iface == audio_class->ctrl_intf) { + /* ignore endpoint descriptor for control interface */ } else if ((cur_iface > audio_class->ctrl_intf) && (cur_iface < (audio_class->ctrl_intf + cur_iface_count))) { struct usb_endpoint_descriptor *ep_desc = (struct usb_endpoint_descriptor *)p; if (ep_desc->bEndpointAddress & 0x80) { @@ -682,14 +693,13 @@ static int usbh_audio_ctrl_connect(struct usbh_hubport *hport, uint8_t intf) } break; case AUDIO_INTERFACE_DESCRIPTOR_TYPE: - if (cur_iface_count == 0xff) { - USB_LOG_ERR("Audio descriptor must have iad descriptor\r\n"); - return -USB_ERR_INVAL; - } - if (cur_iface == audio_class->ctrl_intf) { switch (p[DESC_bDescriptorSubType]) { case AUDIO_CONTROL_HEADER: { + if (p[DESC_bLength] < sizeof(struct audio_cs_if_ac_header_descriptor)) { + return -USB_ERR_INVAL; + } + struct audio_cs_if_ac_header_descriptor *desc = (struct audio_cs_if_ac_header_descriptor *)p; audio_class->bcdADC = desc->bcdADC; audio_class->bInCollection = desc->bInCollection; @@ -704,6 +714,10 @@ static int usbh_audio_ctrl_connect(struct usbh_hubport *hport, uint8_t intf) } else if ((cur_iface > audio_class->ctrl_intf) && (cur_iface < (audio_class->ctrl_intf + cur_iface_count))) { switch (p[DESC_bDescriptorSubType]) { case AUDIO_STREAMING_GENERAL: { + if (p[DESC_bLength] < sizeof(struct audio_cs_if_as_general_descriptor)) { + return -USB_ERR_INVAL; + } + struct audio_cs_if_as_general_descriptor *desc = (struct audio_cs_if_as_general_descriptor *)p; /* all altsetting have the same general */ @@ -711,11 +725,18 @@ static int usbh_audio_ctrl_connect(struct usbh_hubport *hport, uint8_t intf) audio_class->as_msg_table[cur_iface - audio_class->ctrl_intf - 1].bTerminalLink = desc->bTerminalLink; } break; case AUDIO_STREAMING_FORMAT_TYPE: { + if (p[DESC_bLength] < 8) { + return -USB_ERR_INVAL; + } + struct audio_cs_if_as_format_type_descriptor *desc = (struct audio_cs_if_as_format_type_descriptor *)p; - USB_ASSERT(desc->bSamFreqType <= CONFIG_USBHOST_AUDIO_MAX_SAMPLE_FREQ_NUM && desc->bSamFreqType > 0); - USB_ASSERT(desc->bNrChannels <= CONFIG_USBHOST_AUDIO_MAX_CHANNELS); - USB_ASSERT(cur_alt_setting < CONFIG_USBHOST_MAX_INTF_ALTSETTINGS); + if (desc->bSamFreqType == 0 || + desc->bSamFreqType > CONFIG_USBHOST_AUDIO_MAX_SAMPLE_FREQ_NUM || + desc->bNrChannels == 0 || desc->bNrChannels > CONFIG_USBHOST_AUDIO_MAX_CHANNELS || + cur_alt_setting >= CONFIG_USBHOST_MAX_INTF_ALTSETTINGS) { + return -USB_ERR_INVAL; + } audio_class->as_msg_table[cur_iface - audio_class->ctrl_intf - 1].bNrChannels = desc->bNrChannels; memcpy(&audio_class->as_msg_table[cur_iface - audio_class->ctrl_intf - 1].as_format[cur_alt_setting], desc, AUDIO_SIZEOF_FORMAT_TYPE_DESC(desc->bSamFreqType)); @@ -728,6 +749,10 @@ static int usbh_audio_ctrl_connect(struct usbh_hubport *hport, uint8_t intf) case AUDIO_ENDPOINT_DESCRIPTOR_TYPE: if ((cur_iface > audio_class->ctrl_intf) && (cur_iface < (audio_class->ctrl_intf + cur_iface_count))) { if (p[DESC_bDescriptorSubType] == AUDIO_ENDPOINT_GENERAL) { + if (p[DESC_bLength] < sizeof(struct audio_cs_ep_ep_general_descriptor)) { + return -USB_ERR_INVAL; + } + struct audio_cs_ep_ep_general_descriptor *desc = (struct audio_cs_ep_ep_general_descriptor *)p; audio_class->as_msg_table[cur_iface - audio_class->ctrl_intf - 1].ep_attr = desc->bmAttributes; @@ -740,10 +765,6 @@ static int usbh_audio_ctrl_connect(struct usbh_hubport *hport, uint8_t intf) /* skip to next descriptor */ desc_len += p[DESC_bLength]; p += p[DESC_bLength]; - - if (desc_len > hport->config.config_desc.wTotalLength) { - return -USB_ERR_INVAL; - } } if (p_ac_desc == NULL) { @@ -757,11 +778,17 @@ static int usbh_audio_ctrl_connect(struct usbh_hubport *hport, uint8_t intf) USB_LOG_ERR("Fail to find feature unit for stream %s\r\n", audio_class->as_msg_table[i].is_tx ? "tx" : "rx"); return -USB_ERR_INVAL; } + + if ((feature_desc->bLength < 7) || + (feature_desc->bLength > sizeof(struct audio_cs_if_ac_feature_unit_descriptor)) || + (feature_desc->bControlSize != 1) || + (feature_desc->bLength != (7 + feature_desc->bControlSize * (feature_desc->bNrChannels + 1)))) { + return -USB_ERR_INVAL; + } + audio_class->as_msg_table[i].feature_unit_id = feature_desc->bUnitID; audio_class->as_msg_table[i].bControlSize = feature_desc->bControlSize; - USB_ASSERT(feature_desc->bLength > 7); - USB_ASSERT((feature_desc->bLength - 7) <= sizeof(audio_class->as_msg_table[i].bmaControls)); usb_memcpy(&audio_class->as_msg_table[i].bmaControls[0], feature_desc->bmaControls, feature_desc->bLength - 7); ret = usbh_audio_close(audio_class, audio_class->as_msg_table[i].is_tx); |
