GHSA-r6h5-fmhc-v3j7: Potential out-of-bounds read in _ux_host_class_audio_streaming_sampling_get()

GHSA ID

GHSA‑r6h5‑fmhc‑v3j7

CVE ID

CVE‑2025‑55097

Severity

Low

CWE

CWE-125

Published

2025‑10‑17

Last updated

2025‑10‑17

Affected packages

Package Vulnerable versions Patched versions

USBX

⇐ 6.4.2

6.4.3

Description

The function _ux_host_class_audio_streaming_sampling_get() parses a USB audio streaming interface descriptor to extract supported audio sampling characteristics. It iterates through descriptors in the configuration buffer and attempts to read specific frequency values when bSamFreqType is non-zero.

When bSamFreqType is non-zero, the descriptor includes an array of bSamFreqType 3-byte values starting at a fixed offset. However, the function does not validate that the buffer contains at least 3 × `bSamFreqTyp`e bytes before performing the read. This leads to a possible out-of-bounds read if the descriptor is malformed or shorter than claimed.

A malicious USB device could exploit this by setting a large bSamFreqType value while providing an insufficient descriptor length, causing the host to read beyond valid memory. This could lead to crashes or memory disclosure.

code:

UINT  _ux_host_class_audio_streaming_sampling_get(UX_HOST_CLASS_AUDIO *audio, UX_HOST_CLASS_AUDIO_SAMPLING_CHARACTERISTICS *audio_sampling)

{

...

    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_HOST_CLASS_AUDIO_CS_INTERFACE:

...

                if ((audio_sampling -> ux_host_class_audio_sampling_characteristics_channels == 0) &&

                    (audio_sampling -> ux_host_class_audio_sampling_characteristics_resolution == 0))

                {

...

                else

                {



                    /* This is not the second time we ask for the characteristics, we need

                       to find 1st where we left off and look at the next characteristics.  */

                    if ((audio_sampling -> ux_host_class_audio_sampling_characteristics_channels == audio_interface_descriptor.bNrChannels) &&

                        (audio_sampling -> ux_host_class_audio_sampling_characteristics_resolution == audio_interface_descriptor.bBitResolution))

                    {

...

                        if (audio_interface_descriptor.bSamFreqType == 0)

                        {

...

                        }

                        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++) <-- this for look can go out of bound

                            {



                                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;

...