ALSA: usb-audio: Fix out-of-bound error
[pandora-kernel.git] / sound / usb / mixer.c
index b6bef94..4e10164 100644 (file)
@@ -197,6 +197,10 @@ static void *find_audio_control_unit(struct mixer_build *state, unsigned char un
 static int snd_usb_copy_string_desc(struct mixer_build *state, int index, char *buf, int maxlen)
 {
        int len = usb_string(state->chip->dev, index, buf, maxlen - 1);
+
+       if (len < 0)
+               return 0;
+
        buf[len] = 0;
        return len;
 }
@@ -1255,6 +1259,12 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, void
        __u8 *bmaControls;
 
        if (state->mixer->protocol == UAC_VERSION_1) {
+               if (hdr->bLength < 7) {
+                       snd_printk(KERN_ERR
+                                  "usbaudio: unit %u: invalid UAC_FEATURE_UNIT descriptor\n",
+                                  unitid);
+                       return -EINVAL;
+               }
                csize = hdr->bControlSize;
                if (!csize) {
                        snd_printdd(KERN_ERR "usbaudio: unit %u: "
@@ -1271,6 +1281,12 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, void
                }
        } else {
                struct uac2_feature_unit_descriptor *ftr = _ftr;
+               if (hdr->bLength < 6) {
+                       snd_printk(KERN_ERR
+                                  "usbaudio: unit %u: invalid UAC_FEATURE_UNIT descriptor\n",
+                                  unitid);
+                       return -EINVAL;
+               }
                csize = 4;
                channels = (hdr->bLength - 6) / 4 - 1;
                bmaControls = ftr->bmaControls;
@@ -1833,7 +1849,8 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, void
        const struct usbmix_name_map *map;
        char **namelist;
 
-       if (!desc->bNrInPins || desc->bLength < 5 + desc->bNrInPins) {
+       if (desc->bLength < 5 || !desc->bNrInPins ||
+           desc->bLength < 5 + desc->bNrInPins) {
                snd_printk(KERN_ERR "invalid SELECTOR UNIT descriptor %d\n", unitid);
                return -EINVAL;
        }
@@ -1985,6 +2002,9 @@ static int parse_audio_unit(struct mixer_build *state, int unitid)
 
 static void snd_usb_mixer_free(struct usb_mixer_interface *mixer)
 {
+       /* kill pending URBs */
+       snd_usb_mixer_disconnect(&mixer->list);
+
        kfree(mixer->id_elems);
        if (mixer->urb) {
                kfree(mixer->urb->transfer_buffer);
@@ -2331,6 +2351,11 @@ void snd_usb_mixer_disconnect(struct list_head *p)
        struct usb_mixer_interface *mixer;
 
        mixer = list_entry(p, struct usb_mixer_interface, list);
-       usb_kill_urb(mixer->urb);
-       usb_kill_urb(mixer->rc_urb);
+       if (mixer->disconnected)
+               return;
+       if (mixer->urb)
+               usb_kill_urb(mixer->urb);
+       if (mixer->rc_urb)
+               usb_kill_urb(mixer->rc_urb);
+       mixer->disconnected = true;
 }