GHSA-93mv-fcpr-9488: Potential out-of-bounds read in _ux_host_class_audio_alternate_setting_locate()
GHSA ID |
|
|---|---|
CVE ID |
CVE‑2025‑55099 |
Severity |
Low |
CWE |
|
Published |
2025‑10‑17 |
Last updated |
2025‑10‑17 |
Description
The function _ux_host_class_audio_alternate_setting_locate() walks through a USB audio configuration descriptor, parsing each section to identify alternate interface settings and extract sampling frequency information.
A vulnerability exists in how this function accesses fields in the descriptor when bSamFreqType indicates either a range of frequencies (type 0) or a list of specific frequencies (non-zero). In both cases, the function blindly reads additional bytes from the descriptor without verifying that enough data remains.
For example, if the descriptor is truncated but reports a valid bSamFreqType, the function may read six bytes for min/max frequency in type 0, or 3 × N bytes for N specific frequency values. Without bounds checks, a malformed or malicious USB device could craft a short descriptor that causes the host to read past the buffer—potentially leading to crashes or information leakage.
code:
UINT _ux_host_class_audio_alternate_setting_locate(UX_HOST_CLASS_AUDIO *audio, UX_HOST_CLASS_AUDIO_SAMPLING *audio_sampling,
UINT *alternate_setting)
{
...
descriptor = audio -> ux_host_class_audio_configuration_descriptor;
total_descriptor_length = audio -> ux_host_class_audio_configuration_descriptor_length;
...
while (total_descriptor_length)
{
/* Gather the length, type and subtype of the descriptor. */
descriptor_length = *descriptor;
descriptor_type = *(descriptor + 1);
descriptor_subtype = *(descriptor + 2);
...
switch (descriptor_type)
{
case UX_INTERFACE_DESCRIPTOR_ITEM:
/* Parse the interface descriptor and make it machine independent. */
_ux_utility_descriptor_parse(descriptor, _ux_system_interface_descriptor_structure,
UX_INTERFACE_DESCRIPTOR_ENTRIES, (UCHAR *) &interface_descriptor);
...
case UX_HOST_CLASS_AUDIO_CS_INTERFACE:
...
_ux_utility_descriptor_parse(descriptor, _ux_system_class_audio_interface_descriptor_structure,
UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_ENTRIES, (UCHAR *) &audio_interface_descriptor);
...
if (audio_interface_descriptor.bSamFreqType == 0)
{
/* The declaration of frequency is contiguous, so get the minimum and maximum */
lower_frequency = (ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH) |
((ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + 1)) << 8 |
((ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + 2)) << 16;
higher_frequency = (ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + 3) |
((ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + 4)) << 8 |
((ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + 5)) << 16;
...
}
else
{
/* The declaration of the frequency is declared as an array of specific values. */
for (specific_frequency_count = 0; specific_frequency_count < audio_interface_descriptor.bSamFreqType;
specific_frequency_count++)
{
lower_frequency = (ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + (specific_frequency_count * 3)) |
((ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + 1 + (specific_frequency_count * 3))) << 8 |
((ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + 2 + (specific_frequency_count * 3))) << 16;
...
}