aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
authorVladis Dronov <vdronov@redhat.com>2016-03-31 12:05:43 -0400
committerTakashi Iwai <tiwai@suse.de>2016-03-31 12:07:31 -0400
commit836b34a935abc91e13e63053d0a83b24dfb5ea78 (patch)
treeb2aaeb09188148c679f23eda13f7db4b933a65e9 /sound
parent8eb22214b7cb0c0a28be6caf3b81201629d8ea7c (diff)
ALSA: usb-audio: Fix double-free in error paths after snd_usb_add_audio_stream() call
create_fixed_stream_quirk(), snd_usb_parse_audio_interface() and create_uaxx_quirk() functions allocate the audioformat object by themselves and free it upon error before returning. However, once the object is linked to a stream, it's freed again in snd_usb_audio_pcm_free(), thus it'll be double-freed, eventually resulting in a memory corruption. This patch fixes these failures in the error paths by unlinking the audioformat object before freeing it. Based on a patch by Takashi Iwai <tiwai@suse.de> [Note for stable backports: this patch requires the commit 902eb7fd1e4a ('ALSA: usb-audio: Minor code cleanup in create_fixed_stream_quirk()')] Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1283358 Reported-by: Ralf Spenneberg <ralf@spenneberg.net> Cc: <stable@vger.kernel.org> # see the note above Signed-off-by: Vladis Dronov <vdronov@redhat.com> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound')
-rw-r--r--sound/usb/quirks.c4
-rw-r--r--sound/usb/stream.c6
2 files changed, 9 insertions, 1 deletions
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
index fb62bce2435c..6178bb5d0731 100644
--- a/sound/usb/quirks.c
+++ b/sound/usb/quirks.c
@@ -150,6 +150,7 @@ static int create_fixed_stream_quirk(struct snd_usb_audio *chip,
150 usb_audio_err(chip, "cannot memdup\n"); 150 usb_audio_err(chip, "cannot memdup\n");
151 return -ENOMEM; 151 return -ENOMEM;
152 } 152 }
153 INIT_LIST_HEAD(&fp->list);
153 if (fp->nr_rates > MAX_NR_RATES) { 154 if (fp->nr_rates > MAX_NR_RATES) {
154 kfree(fp); 155 kfree(fp);
155 return -EINVAL; 156 return -EINVAL;
@@ -193,6 +194,7 @@ static int create_fixed_stream_quirk(struct snd_usb_audio *chip,
193 return 0; 194 return 0;
194 195
195 error: 196 error:
197 list_del(&fp->list); /* unlink for avoiding double-free */
196 kfree(fp); 198 kfree(fp);
197 kfree(rate_table); 199 kfree(rate_table);
198 return err; 200 return err;
@@ -469,6 +471,7 @@ static int create_uaxx_quirk(struct snd_usb_audio *chip,
469 fp->ep_attr = get_endpoint(alts, 0)->bmAttributes; 471 fp->ep_attr = get_endpoint(alts, 0)->bmAttributes;
470 fp->datainterval = 0; 472 fp->datainterval = 0;
471 fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize); 473 fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize);
474 INIT_LIST_HEAD(&fp->list);
472 475
473 switch (fp->maxpacksize) { 476 switch (fp->maxpacksize) {
474 case 0x120: 477 case 0x120:
@@ -492,6 +495,7 @@ static int create_uaxx_quirk(struct snd_usb_audio *chip,
492 ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK; 495 ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK;
493 err = snd_usb_add_audio_stream(chip, stream, fp); 496 err = snd_usb_add_audio_stream(chip, stream, fp);
494 if (err < 0) { 497 if (err < 0) {
498 list_del(&fp->list); /* unlink for avoiding double-free */
495 kfree(fp); 499 kfree(fp);
496 return err; 500 return err;
497 } 501 }
diff --git a/sound/usb/stream.c b/sound/usb/stream.c
index c4dc577ab1bd..8e9548bc1f1a 100644
--- a/sound/usb/stream.c
+++ b/sound/usb/stream.c
@@ -314,7 +314,9 @@ static struct snd_pcm_chmap_elem *convert_chmap(int channels, unsigned int bits,
314/* 314/*
315 * add this endpoint to the chip instance. 315 * add this endpoint to the chip instance.
316 * if a stream with the same endpoint already exists, append to it. 316 * if a stream with the same endpoint already exists, append to it.
317 * if not, create a new pcm stream. 317 * if not, create a new pcm stream. note, fp is added to the substream
318 * fmt_list and will be freed on the chip instance release. do not free
319 * fp or do remove it from the substream fmt_list to avoid double-free.
318 */ 320 */
319int snd_usb_add_audio_stream(struct snd_usb_audio *chip, 321int snd_usb_add_audio_stream(struct snd_usb_audio *chip,
320 int stream, 322 int stream,
@@ -675,6 +677,7 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no)
675 * (fp->maxpacksize & 0x7ff); 677 * (fp->maxpacksize & 0x7ff);
676 fp->attributes = parse_uac_endpoint_attributes(chip, alts, protocol, iface_no); 678 fp->attributes = parse_uac_endpoint_attributes(chip, alts, protocol, iface_no);
677 fp->clock = clock; 679 fp->clock = clock;
680 INIT_LIST_HEAD(&fp->list);
678 681
679 /* some quirks for attributes here */ 682 /* some quirks for attributes here */
680 683
@@ -723,6 +726,7 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no)
723 dev_dbg(&dev->dev, "%u:%d: add audio endpoint %#x\n", iface_no, altno, fp->endpoint); 726 dev_dbg(&dev->dev, "%u:%d: add audio endpoint %#x\n", iface_no, altno, fp->endpoint);
724 err = snd_usb_add_audio_stream(chip, stream, fp); 727 err = snd_usb_add_audio_stream(chip, stream, fp);
725 if (err < 0) { 728 if (err < 0) {
729 list_del(&fp->list); /* unlink for avoiding double-free */
726 kfree(fp->rate_table); 730 kfree(fp->rate_table);
727 kfree(fp->chmap); 731 kfree(fp->chmap);
728 kfree(fp); 732 kfree(fp);