]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blobdiff - sound/usb/card.c
ALSA: usb-audio: Check out-of-bounds access by corrupted buffer descriptor
[mirror_ubuntu-artful-kernel.git] / sound / usb / card.c
index 6640277a725b6565adfb9665077903ff51940c34..383facf2dc11a43af3450135466398a995eb3775 100644 (file)
@@ -221,6 +221,7 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif)
        struct usb_interface_descriptor *altsd;
        void *control_header;
        int i, protocol;
+       int rest_bytes;
 
        /* find audiocontrol interface */
        host_iface = &usb_ifnum_to_if(dev, ctrlif)->altsetting[0];
@@ -235,6 +236,15 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif)
                return -EINVAL;
        }
 
+       rest_bytes = (void *)(host_iface->extra + host_iface->extralen) -
+               control_header;
+
+       /* just to be sure -- this shouldn't hit at all */
+       if (rest_bytes <= 0) {
+               dev_err(&dev->dev, "invalid control header\n");
+               return -EINVAL;
+       }
+
        switch (protocol) {
        default:
                dev_warn(&dev->dev,
@@ -245,11 +255,21 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif)
        case UAC_VERSION_1: {
                struct uac1_ac_header_descriptor *h1 = control_header;
 
+               if (rest_bytes < sizeof(*h1)) {
+                       dev_err(&dev->dev, "too short v1 buffer descriptor\n");
+                       return -EINVAL;
+               }
+
                if (!h1->bInCollection) {
                        dev_info(&dev->dev, "skipping empty audio interface (v1)\n");
                        return -EINVAL;
                }
 
+               if (rest_bytes < h1->bLength) {
+                       dev_err(&dev->dev, "invalid buffer length (v1)\n");
+                       return -EINVAL;
+               }
+
                if (h1->bLength < sizeof(*h1) + h1->bInCollection) {
                        dev_err(&dev->dev, "invalid UAC_HEADER (v1)\n");
                        return -EINVAL;