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 <lkasam@codeaurora.org>
This commit is contained in:
Laxminath Kasam 2016-07-11 12:18:10 +05:30
parent 293a2b36f2
commit 482c8b19a8
2 changed files with 20 additions and 12 deletions

View file

@ -160,6 +160,8 @@ void snd_ctl_notify(struct snd_card *card, unsigned int mask,
if (snd_BUG_ON(!card || !id)) if (snd_BUG_ON(!card || !id))
return; return;
if (card->shutdown)
return;
read_lock(&card->ctl_files_rwlock); read_lock(&card->ctl_files_rwlock);
#if IS_ENABLED(CONFIG_SND_MIXER_OSS) #if IS_ENABLED(CONFIG_SND_MIXER_OSS)
card->mixer_oss_change_count++; card->mixer_oss_change_count++;

View file

@ -849,6 +849,22 @@ int snd_pcm_new_internal(struct snd_card *card, const char *id, int device,
} }
EXPORT_SYMBOL(snd_pcm_new_internal); 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) static void snd_pcm_free_stream(struct snd_pcm_str * pstr)
{ {
struct snd_pcm_substream *substream, *substream_next; struct snd_pcm_substream *substream, *substream_next;
@ -871,6 +887,7 @@ static void snd_pcm_free_stream(struct snd_pcm_str * pstr)
kfree(setup); kfree(setup);
} }
#endif #endif
free_pcm_kctl(pstr);
if (pstr->substream_count) if (pstr->substream_count)
put_device(&pstr->dev); put_device(&pstr->dev);
} }
@ -1135,18 +1152,7 @@ static int snd_pcm_dev_disconnect(struct snd_device *device)
for (cidx = 0; cidx < 2; cidx++) { for (cidx = 0; cidx < 2; cidx++) {
if (!pcm->internal) if (!pcm->internal)
snd_unregister_device(&pcm->streams[cidx].dev); snd_unregister_device(&pcm->streams[cidx].dev);
if (pcm->streams[cidx].chmap_kctl) { free_pcm_kctl(&pcm->streams[cidx]);
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;
}
} }
mutex_unlock(&pcm->open_mutex); mutex_unlock(&pcm->open_mutex);
mutex_unlock(&register_mutex); mutex_unlock(&register_mutex);