Revert "ASoC: dpcm: prevent snd_soc_dpcm use after free"
This reverts commit71dc356a36which is commit a9764869779081e8bf24da07ac040e8f3efcf13a upstream. It is needed for Android but in this format, it breaks the ABI. An ABI-stable version will be added back to the tree in a later change. Fixes:71dc356a36("ASoC: dpcm: prevent snd_soc_dpcm use after free") Cc: Will McVicker <willmcvicker@google.com> Signed-off-by: Greg Kroah-Hartman <gregkh@google.com> Change-Id: I11e394d57418cd35de0801e34ba479ffce3eb81d
This commit is contained in:
@@ -1161,8 +1161,6 @@ struct snd_soc_card {
|
||||
u32 pop_time;
|
||||
|
||||
void *drvdata;
|
||||
|
||||
spinlock_t dpcm_lock;
|
||||
};
|
||||
|
||||
/* SoC machine DAI configuration, glues a codec and cpu DAI together */
|
||||
|
||||
@@ -2786,7 +2786,6 @@ int snd_soc_register_card(struct snd_soc_card *card)
|
||||
mutex_init(&card->mutex);
|
||||
mutex_init(&card->dapm_mutex);
|
||||
mutex_init(&card->dapm_power_mutex);
|
||||
spin_lock_init(&card->dpcm_lock);
|
||||
|
||||
ret = snd_soc_instantiate_card(card);
|
||||
if (ret != 0)
|
||||
|
||||
@@ -1282,7 +1282,6 @@ static int dpcm_be_connect(struct snd_soc_pcm_runtime *fe,
|
||||
struct snd_soc_pcm_runtime *be, int stream)
|
||||
{
|
||||
struct snd_soc_dpcm *dpcm;
|
||||
unsigned long flags;
|
||||
|
||||
/* only add new dpcms */
|
||||
list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
|
||||
@@ -1298,10 +1297,8 @@ static int dpcm_be_connect(struct snd_soc_pcm_runtime *fe,
|
||||
dpcm->fe = fe;
|
||||
be->dpcm[stream].runtime = fe->dpcm[stream].runtime;
|
||||
dpcm->state = SND_SOC_DPCM_LINK_STATE_NEW;
|
||||
spin_lock_irqsave(&fe->card->dpcm_lock, flags);
|
||||
list_add(&dpcm->list_be, &fe->dpcm[stream].be_clients);
|
||||
list_add(&dpcm->list_fe, &be->dpcm[stream].fe_clients);
|
||||
spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
|
||||
|
||||
dev_dbg(fe->dev, "connected new DPCM %s path %s %s %s\n",
|
||||
stream ? "capture" : "playback", fe->dai_link->name,
|
||||
@@ -1347,7 +1344,6 @@ static void dpcm_be_reparent(struct snd_soc_pcm_runtime *fe,
|
||||
void dpcm_be_disconnect(struct snd_soc_pcm_runtime *fe, int stream)
|
||||
{
|
||||
struct snd_soc_dpcm *dpcm, *d;
|
||||
unsigned long flags;
|
||||
|
||||
list_for_each_entry_safe(dpcm, d, &fe->dpcm[stream].be_clients, list_be) {
|
||||
dev_dbg(fe->dev, "ASoC: BE %s disconnect check for %s\n",
|
||||
@@ -1367,10 +1363,8 @@ void dpcm_be_disconnect(struct snd_soc_pcm_runtime *fe, int stream)
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
debugfs_remove(dpcm->debugfs_state);
|
||||
#endif
|
||||
spin_lock_irqsave(&fe->card->dpcm_lock, flags);
|
||||
list_del(&dpcm->list_be);
|
||||
list_del(&dpcm->list_fe);
|
||||
spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
|
||||
kfree(dpcm);
|
||||
}
|
||||
}
|
||||
@@ -1624,13 +1618,10 @@ int dpcm_process_paths(struct snd_soc_pcm_runtime *fe,
|
||||
void dpcm_clear_pending_state(struct snd_soc_pcm_runtime *fe, int stream)
|
||||
{
|
||||
struct snd_soc_dpcm *dpcm;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&fe->card->dpcm_lock, flags);
|
||||
list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be)
|
||||
dpcm->be->dpcm[stream].runtime_update =
|
||||
SND_SOC_DPCM_UPDATE_NO;
|
||||
spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
|
||||
}
|
||||
|
||||
static void dpcm_be_dai_startup_unwind(struct snd_soc_pcm_runtime *fe,
|
||||
@@ -2696,7 +2687,6 @@ static int dpcm_run_update_startup(struct snd_soc_pcm_runtime *fe, int stream)
|
||||
struct snd_soc_dpcm *dpcm;
|
||||
enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream];
|
||||
int ret;
|
||||
unsigned long flags;
|
||||
|
||||
dev_dbg(fe->dev, "ASoC: runtime %s open on FE %s\n",
|
||||
stream ? "capture" : "playback", fe->dai_link->name);
|
||||
@@ -2766,13 +2756,11 @@ static int dpcm_run_update_startup(struct snd_soc_pcm_runtime *fe, int stream)
|
||||
dpcm_be_dai_shutdown(fe, stream);
|
||||
disconnect:
|
||||
/* disconnect any non started BEs */
|
||||
spin_lock_irqsave(&fe->card->dpcm_lock, flags);
|
||||
list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
|
||||
struct snd_soc_pcm_runtime *be = dpcm->be;
|
||||
if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START)
|
||||
dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
|
||||
}
|
||||
spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -3368,10 +3356,7 @@ int snd_soc_dpcm_can_be_free_stop(struct snd_soc_pcm_runtime *fe,
|
||||
{
|
||||
struct snd_soc_dpcm *dpcm;
|
||||
int state;
|
||||
int ret = 1;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&fe->card->dpcm_lock, flags);
|
||||
list_for_each_entry(dpcm, &be->dpcm[stream].fe_clients, list_fe) {
|
||||
|
||||
if (dpcm->fe == fe)
|
||||
@@ -3380,15 +3365,12 @@ int snd_soc_dpcm_can_be_free_stop(struct snd_soc_pcm_runtime *fe,
|
||||
state = dpcm->fe->dpcm[stream].state;
|
||||
if (state == SND_SOC_DPCM_STATE_START ||
|
||||
state == SND_SOC_DPCM_STATE_PAUSED ||
|
||||
state == SND_SOC_DPCM_STATE_SUSPEND) {
|
||||
ret = 0;
|
||||
break;
|
||||
state == SND_SOC_DPCM_STATE_SUSPEND)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
|
||||
|
||||
/* it's safe to free/stop this BE DAI */
|
||||
return ret;
|
||||
return 1;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_soc_dpcm_can_be_free_stop);
|
||||
|
||||
@@ -3401,10 +3383,7 @@ int snd_soc_dpcm_can_be_params(struct snd_soc_pcm_runtime *fe,
|
||||
{
|
||||
struct snd_soc_dpcm *dpcm;
|
||||
int state;
|
||||
int ret = 1;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&fe->card->dpcm_lock, flags);
|
||||
list_for_each_entry(dpcm, &be->dpcm[stream].fe_clients, list_fe) {
|
||||
|
||||
if (dpcm->fe == fe)
|
||||
@@ -3414,15 +3393,12 @@ int snd_soc_dpcm_can_be_params(struct snd_soc_pcm_runtime *fe,
|
||||
if (state == SND_SOC_DPCM_STATE_START ||
|
||||
state == SND_SOC_DPCM_STATE_PAUSED ||
|
||||
state == SND_SOC_DPCM_STATE_SUSPEND ||
|
||||
state == SND_SOC_DPCM_STATE_PREPARE) {
|
||||
ret = 0;
|
||||
break;
|
||||
state == SND_SOC_DPCM_STATE_PREPARE)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
|
||||
|
||||
/* it's safe to change hw_params */
|
||||
return ret;
|
||||
return 1;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_soc_dpcm_can_be_params);
|
||||
|
||||
@@ -3461,7 +3437,6 @@ static ssize_t dpcm_show_state(struct snd_soc_pcm_runtime *fe,
|
||||
struct snd_pcm_hw_params *params = &fe->dpcm[stream].hw_params;
|
||||
struct snd_soc_dpcm *dpcm;
|
||||
ssize_t offset = 0;
|
||||
unsigned long flags;
|
||||
|
||||
/* FE state */
|
||||
offset += scnprintf(buf + offset, size - offset,
|
||||
@@ -3489,7 +3464,6 @@ static ssize_t dpcm_show_state(struct snd_soc_pcm_runtime *fe,
|
||||
goto out;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&fe->card->dpcm_lock, flags);
|
||||
list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
|
||||
struct snd_soc_pcm_runtime *be = dpcm->be;
|
||||
params = &dpcm->hw_params;
|
||||
@@ -3510,7 +3484,7 @@ static ssize_t dpcm_show_state(struct snd_soc_pcm_runtime *fe,
|
||||
params_channels(params),
|
||||
params_rate(params));
|
||||
}
|
||||
spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
|
||||
|
||||
out:
|
||||
return offset;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user