ALSA: usb-audio: Fix double-free in error paths after snd_usb_add_audio_stream()...
[pandora-kernel.git] / sound / usb / stream.c
index 5ff8010..7dce074 100644 (file)
@@ -77,7 +77,9 @@ static void snd_usb_audio_pcm_free(struct snd_pcm *pcm)
 /*
  * add this endpoint to the chip instance.
  * if a stream with the same endpoint already exists, append to it.
- * if not, create a new pcm stream.
+ * if not, create a new pcm stream. note, fp is added to the substream
+ * fmt_list and will be freed on the chip instance release. do not free
+ * fp or do remove it from the substream fmt_list to avoid double-free.
  */
 int snd_usb_add_audio_stream(struct snd_usb_audio *chip,
                             int stream,
@@ -168,6 +170,14 @@ static int parse_uac_endpoint_attributes(struct snd_usb_audio *chip,
        if (!csep && altsd->bNumEndpoints >= 2)
                csep = snd_usb_find_desc(alts->endpoint[1].extra, alts->endpoint[1].extralen, NULL, USB_DT_CS_ENDPOINT);
 
+       /*
+        * If we can't locate the USB_DT_CS_ENDPOINT descriptor in the extra
+        * bytes after the first endpoint, go search the entire interface.
+        * Some devices have it directly *before* the standard endpoint.
+        */
+       if (!csep)
+               csep = snd_usb_find_desc(alts->extra, alts->extralen, NULL, USB_DT_CS_ENDPOINT);
+
        if (!csep || csep->bLength < 7 ||
            csep->bDescriptorSubtype != UAC_EP_GENERAL) {
                snd_printk(KERN_WARNING "%d:%u:%d : no or invalid"
@@ -395,6 +405,7 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no)
                                        * (fp->maxpacksize & 0x7ff);
                fp->attributes = parse_uac_endpoint_attributes(chip, alts, protocol, iface_no);
                fp->clock = clock;
+               INIT_LIST_HEAD(&fp->list);
 
                /* some quirks for attributes here */
 
@@ -438,6 +449,7 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no)
                snd_printdd(KERN_INFO "%d:%u:%d: add audio endpoint %#x\n", dev->devnum, iface_no, altno, fp->endpoint);
                err = snd_usb_add_audio_stream(chip, stream, fp);
                if (err < 0) {
+                       list_del(&fp->list); /* unlink for avoiding double-free */
                        kfree(fp->rate_table);
                        kfree(fp);
                        return err;