USB: gadget: f_audio_source: Fix use after free in audio_unbind
authorMike Lockwood <lockwood@google.com>
Thu, 16 Aug 2012 02:58:28 +0000 (19:58 -0700)
committerandroid code review <noreply-gerritcodereview@google.com>
Thu, 16 Aug 2012 19:52:33 +0000 (12:52 -0700)
When USB was disconnected, we were freeing our audio_dev struct in audio_unbind
before the audio system had cleaned up, resulting in a hang in audio_pcm_close.
We now statically allocate the audio_dev struct to avoid this problem.

Change-Id: I58ad21eaa20dcf4aa74ee614ef3b6ed2c91d52a1
Signed-off-by: Mike Lockwood <lockwood@google.com>
drivers/usb/gadget/f_audio_source.c

index ba8e007c7969ca8f0228358c474564f4392ff7a4..fe221c51cbfb5d699893e853ccb98e36938c47aa 100644 (file)
@@ -243,7 +243,6 @@ struct audio_dev {
 
        struct list_head                idle_reqs;
        struct usb_ep                   *in_ep;
-       struct usb_endpoint_descriptor  *in_desc;
 
        spinlock_t                      lock;
 
@@ -620,7 +619,10 @@ audio_unbind(struct usb_configuration *c, struct usb_function *f)
                audio_request_free(req, audio->in_ep);
 
        snd_card_free_when_closed(audio->card);
-       kfree(audio);
+       audio->card = NULL;
+       audio->pcm = NULL;
+       audio->substream = NULL;
+       audio->in_ep = NULL;
 }
 
 static void audio_pcm_playback_start(struct audio_dev *audio)
@@ -736,6 +738,19 @@ static int audio_pcm_playback_trigger(struct snd_pcm_substream *substream,
        return ret;
 }
 
+static struct audio_dev _audio_dev = {
+       .func = {
+               .name = "audio_source",
+               .bind = audio_bind,
+               .unbind = audio_unbind,
+               .set_alt = audio_set_alt,
+               .setup = audio_setup,
+               .disable = audio_disable,
+       },
+       .lock = __SPIN_LOCK_UNLOCKED(_audio_dev.lock),
+       .idle_reqs = LIST_HEAD_INIT(_audio_dev.idle_reqs),
+};
+
 static struct snd_pcm_ops audio_playback_ops = {
        .open           = audio_pcm_open,
        .close          = audio_pcm_close,
@@ -758,27 +773,12 @@ int audio_source_bind_config(struct usb_configuration *c,
        config->card = -1;
        config->device = -1;
 
-       audio = kzalloc(sizeof *audio, GFP_KERNEL);
-       if (!audio)
-               return -ENOMEM;
-
-       audio->func.name = "audio_source";
-
-       spin_lock_init(&audio->lock);
-
-       audio->func.bind = audio_bind;
-       audio->func.unbind = audio_unbind;
-       audio->func.set_alt = audio_set_alt;
-       audio->func.setup = audio_setup;
-       audio->func.disable = audio_disable;
-       audio->in_desc = &fs_as_in_ep_desc;
-
-       INIT_LIST_HEAD(&audio->idle_reqs);
+       audio = &_audio_dev;
 
        err = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
                        THIS_MODULE, 0, &card);
        if (err)
-               goto snd_card_fail;
+               return err;
 
        snd_card_set_dev(card, &c->cdev->gadget->dev);
 
@@ -817,7 +817,5 @@ add_fail:
 register_fail:
 pcm_fail:
        snd_card_free(audio->card);
-snd_card_fail:
-       kfree(audio);
        return err;
 }