From 482c8b19a85cf0282158e98ec060f803f08e498e Mon Sep 17 00:00:00 2001 From: Laxminath Kasam Date: Mon, 11 Jul 2016 12:18:10 +0530 Subject: [PATCH] ASoC: Fix freed memory access of pcm stream kctl Consider sound card instantiate fails due to audrx init failure. In such case, all dais/ctls are de-registered and freed. But as part of it, access to unregistered ctls for pcm_chmap and similar controls result in crash. Ctls are freed at disconnection but the disconnect is called only when it was registered. CRs-Fixed: 1038054 Change-Id: Ief8817b4ec000c058d46aa021977b7c6003c0011 Signed-off-by: Laxminath Kasam --- sound/core/control.c | 2 ++ sound/core/pcm.c | 30 ++++++++++++++++++------------ 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/sound/core/control.c b/sound/core/control.c index a85d45595d02..b4fe9b002512 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -160,6 +160,8 @@ void snd_ctl_notify(struct snd_card *card, unsigned int mask, if (snd_BUG_ON(!card || !id)) return; + if (card->shutdown) + return; read_lock(&card->ctl_files_rwlock); #if IS_ENABLED(CONFIG_SND_MIXER_OSS) card->mixer_oss_change_count++; diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 019751a83e25..9e4743e833be 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -849,6 +849,22 @@ int snd_pcm_new_internal(struct snd_card *card, const char *id, int device, } EXPORT_SYMBOL(snd_pcm_new_internal); +static void free_pcm_kctl(struct snd_pcm_str *pstr) +{ + if (pstr->chmap_kctl) { + snd_ctl_remove(pstr->pcm->card, pstr->chmap_kctl); + pstr->chmap_kctl = NULL; + } + if (pstr->vol_kctl) { + snd_ctl_remove(pstr->pcm->card, pstr->vol_kctl); + pstr->vol_kctl = NULL; + } + if (pstr->usr_kctl) { + snd_ctl_remove(pstr->pcm->card, pstr->usr_kctl); + pstr->usr_kctl = NULL; + } +} + static void snd_pcm_free_stream(struct snd_pcm_str * pstr) { struct snd_pcm_substream *substream, *substream_next; @@ -871,6 +887,7 @@ static void snd_pcm_free_stream(struct snd_pcm_str * pstr) kfree(setup); } #endif + free_pcm_kctl(pstr); if (pstr->substream_count) put_device(&pstr->dev); } @@ -1135,18 +1152,7 @@ static int snd_pcm_dev_disconnect(struct snd_device *device) for (cidx = 0; cidx < 2; cidx++) { if (!pcm->internal) snd_unregister_device(&pcm->streams[cidx].dev); - if (pcm->streams[cidx].chmap_kctl) { - snd_ctl_remove(pcm->card, pcm->streams[cidx].chmap_kctl); - pcm->streams[cidx].chmap_kctl = NULL; - } - if (pcm->streams[cidx].vol_kctl) { - snd_ctl_remove(pcm->card, pcm->streams[cidx].vol_kctl); - pcm->streams[cidx].vol_kctl = NULL; - } - if (pcm->streams[cidx].usr_kctl) { - snd_ctl_remove(pcm->card, pcm->streams[cidx].usr_kctl); - pcm->streams[cidx].usr_kctl = NULL; - } + free_pcm_kctl(&pcm->streams[cidx]); } mutex_unlock(&pcm->open_mutex); mutex_unlock(®ister_mutex);