]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
ALSA: usb-audio: Validate UAC3 cluster segment descriptors
authorTakashi Iwai <tiwai@suse.de>
Thu, 14 Aug 2025 08:12:43 +0000 (10:12 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 20 Aug 2025 16:40:44 +0000 (18:40 +0200)
commit ecfd41166b72b67d3bdeb88d224ff445f6163869 upstream.

UAC3 class segment descriptors need to be verified whether their sizes
match with the declared lengths and whether they fit with the
allocated buffer sizes, too.  Otherwise malicious firmware may lead to
the unexpected OOB accesses.

Fixes: 11785ef53228 ("ALSA: usb-audio: Initial Power Domain support")
Reported-and-tested-by: Youngjun Lee <yjjuny.lee@samsung.com>
Cc: <stable@vger.kernel.org>
Link: https://patch.msgid.link/20250814081245.8902-2-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
sound/usb/stream.c

index aa91d63749f2ca34e906d1e1366ca9f095ac01ae..1cb52373e70f647cfd11fa4ec8a29711c192aa7e 100644 (file)
@@ -341,20 +341,28 @@ snd_pcm_chmap_elem *convert_chmap_v3(struct uac3_cluster_header_descriptor
 
        len = le16_to_cpu(cluster->wLength);
        c = 0;
-       p += sizeof(struct uac3_cluster_header_descriptor);
+       p += sizeof(*cluster);
+       len -= sizeof(*cluster);
 
-       while (((p - (void *)cluster) < len) && (c < channels)) {
+       while (len > 0 && (c < channels)) {
                struct uac3_cluster_segment_descriptor *cs_desc = p;
                u16 cs_len;
                u8 cs_type;
 
+               if (len < sizeof(*p))
+                       break;
                cs_len = le16_to_cpu(cs_desc->wLength);
+               if (len < cs_len)
+                       break;
                cs_type = cs_desc->bSegmentType;
 
                if (cs_type == UAC3_CHANNEL_INFORMATION) {
                        struct uac3_cluster_information_segment_descriptor *is = p;
                        unsigned char map;
 
+                       if (cs_len < sizeof(*is))
+                               break;
+
                        /*
                         * TODO: this conversion is not complete, update it
                         * after adding UAC3 values to asound.h
@@ -456,6 +464,7 @@ snd_pcm_chmap_elem *convert_chmap_v3(struct uac3_cluster_header_descriptor
                        chmap->map[c++] = map;
                }
                p += cs_len;
+               len -= cs_len;
        }
 
        if (channels < c)
@@ -880,7 +889,7 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip,
        u64 badd_formats = 0;
        unsigned int num_channels;
        struct audioformat *fp;
-       u16 cluster_id, wLength;
+       u16 cluster_id, wLength, cluster_wLength;
        int clock = 0;
        int err;
 
@@ -1010,6 +1019,16 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip,
                return ERR_PTR(-EIO);
        }
 
+       cluster_wLength = le16_to_cpu(cluster->wLength);
+       if (cluster_wLength < sizeof(*cluster) ||
+           cluster_wLength > wLength) {
+               dev_err(&dev->dev,
+                       "%u:%d : invalid Cluster Descriptor size\n",
+                       iface_no, altno);
+               kfree(cluster);
+               return ERR_PTR(-EIO);
+       }
+
        num_channels = cluster->bNrChannels;
        chmap = convert_chmap_v3(cluster);
        kfree(cluster);