diff options
author | Takashi Iwai <tiwai@suse.de> | 2017-05-24 04:19:45 -0400 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2017-05-24 13:11:08 -0400 |
commit | 4efda5f2130da033aeedc5b3205569893b910de2 (patch) | |
tree | 9a55c0a2d19260fe65c2fb6c2a401bc6a951abca | |
parent | 2ea659a9ef488125eb46da6eb571de5eae5c43f6 (diff) |
ASoC: Fix use-after-free at card unregistration
soc_cleanup_card_resources() call snd_card_free() at the last of its
procedure. This turned out to lead to a use-after-free.
PCM runtimes have been already removed via soc_remove_pcm_runtimes(),
while it's dereferenced later in soc_pcm_free() called via
snd_card_free().
The fix is simple: just move the snd_card_free() call to the beginning
of the whole procedure. This also gives another benefit: it
guarantees that all operations have been shut down before actually
releasing the resources, which was racy until now.
Reported-and-tested-by: Robert Jarzmik <robert.jarzmik@free.fr>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Mark Brown <broonie@kernel.org>
Cc: <stable@vger.kernel.org>
-rw-r--r-- | sound/soc/soc-core.c | 5 |
1 files changed, 3 insertions, 2 deletions
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index aae099c0e502..754e3ef8d7ae 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c | |||
@@ -2286,6 +2286,9 @@ static int soc_cleanup_card_resources(struct snd_soc_card *card) | |||
2286 | list_for_each_entry(rtd, &card->rtd_list, list) | 2286 | list_for_each_entry(rtd, &card->rtd_list, list) |
2287 | flush_delayed_work(&rtd->delayed_work); | 2287 | flush_delayed_work(&rtd->delayed_work); |
2288 | 2288 | ||
2289 | /* free the ALSA card at first; this syncs with pending operations */ | ||
2290 | snd_card_free(card->snd_card); | ||
2291 | |||
2289 | /* remove and free each DAI */ | 2292 | /* remove and free each DAI */ |
2290 | soc_remove_dai_links(card); | 2293 | soc_remove_dai_links(card); |
2291 | soc_remove_pcm_runtimes(card); | 2294 | soc_remove_pcm_runtimes(card); |
@@ -2300,9 +2303,7 @@ static int soc_cleanup_card_resources(struct snd_soc_card *card) | |||
2300 | if (card->remove) | 2303 | if (card->remove) |
2301 | card->remove(card); | 2304 | card->remove(card); |
2302 | 2305 | ||
2303 | snd_card_free(card->snd_card); | ||
2304 | return 0; | 2306 | return 0; |
2305 | |||
2306 | } | 2307 | } |
2307 | 2308 | ||
2308 | /* removes a socdev */ | 2309 | /* removes a socdev */ |