Revert "ASoC: dpcm: prevent snd_soc_dpcm use after free"

This reverts commit 71dc356a36 which 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:
Greg Kroah-Hartman
2022-01-31 13:09:21 +01:00
parent 464464ac47
commit ee259c6c2f
3 changed files with 7 additions and 36 deletions

View File

@@ -1161,8 +1161,6 @@ struct snd_soc_card {
u32 pop_time; u32 pop_time;
void *drvdata; void *drvdata;
spinlock_t dpcm_lock;
}; };
/* SoC machine DAI configuration, glues a codec and cpu DAI together */ /* SoC machine DAI configuration, glues a codec and cpu DAI together */

View File

@@ -2786,7 +2786,6 @@ int snd_soc_register_card(struct snd_soc_card *card)
mutex_init(&card->mutex); mutex_init(&card->mutex);
mutex_init(&card->dapm_mutex); mutex_init(&card->dapm_mutex);
mutex_init(&card->dapm_power_mutex); mutex_init(&card->dapm_power_mutex);
spin_lock_init(&card->dpcm_lock);
ret = snd_soc_instantiate_card(card); ret = snd_soc_instantiate_card(card);
if (ret != 0) if (ret != 0)

View File

@@ -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_pcm_runtime *be, int stream)
{ {
struct snd_soc_dpcm *dpcm; struct snd_soc_dpcm *dpcm;
unsigned long flags;
/* only add new dpcms */ /* only add new dpcms */
list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { 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; dpcm->fe = fe;
be->dpcm[stream].runtime = fe->dpcm[stream].runtime; be->dpcm[stream].runtime = fe->dpcm[stream].runtime;
dpcm->state = SND_SOC_DPCM_LINK_STATE_NEW; 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_be, &fe->dpcm[stream].be_clients);
list_add(&dpcm->list_fe, &be->dpcm[stream].fe_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", dev_dbg(fe->dev, "connected new DPCM %s path %s %s %s\n",
stream ? "capture" : "playback", fe->dai_link->name, 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) void dpcm_be_disconnect(struct snd_soc_pcm_runtime *fe, int stream)
{ {
struct snd_soc_dpcm *dpcm, *d; struct snd_soc_dpcm *dpcm, *d;
unsigned long flags;
list_for_each_entry_safe(dpcm, d, &fe->dpcm[stream].be_clients, list_be) { 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", 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 #ifdef CONFIG_DEBUG_FS
debugfs_remove(dpcm->debugfs_state); debugfs_remove(dpcm->debugfs_state);
#endif #endif
spin_lock_irqsave(&fe->card->dpcm_lock, flags);
list_del(&dpcm->list_be); list_del(&dpcm->list_be);
list_del(&dpcm->list_fe); list_del(&dpcm->list_fe);
spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
kfree(dpcm); 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) void dpcm_clear_pending_state(struct snd_soc_pcm_runtime *fe, int stream)
{ {
struct snd_soc_dpcm *dpcm; 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) list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be)
dpcm->be->dpcm[stream].runtime_update = dpcm->be->dpcm[stream].runtime_update =
SND_SOC_DPCM_UPDATE_NO; 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, 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; struct snd_soc_dpcm *dpcm;
enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream]; enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream];
int ret; int ret;
unsigned long flags;
dev_dbg(fe->dev, "ASoC: runtime %s open on FE %s\n", dev_dbg(fe->dev, "ASoC: runtime %s open on FE %s\n",
stream ? "capture" : "playback", fe->dai_link->name); 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); dpcm_be_dai_shutdown(fe, stream);
disconnect: disconnect:
/* disconnect any non started BEs */ /* 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) { list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
struct snd_soc_pcm_runtime *be = dpcm->be; struct snd_soc_pcm_runtime *be = dpcm->be;
if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START) if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START)
dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE; dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
} }
spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
return ret; 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; struct snd_soc_dpcm *dpcm;
int state; 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) { list_for_each_entry(dpcm, &be->dpcm[stream].fe_clients, list_fe) {
if (dpcm->fe == 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; state = dpcm->fe->dpcm[stream].state;
if (state == SND_SOC_DPCM_STATE_START || if (state == SND_SOC_DPCM_STATE_START ||
state == SND_SOC_DPCM_STATE_PAUSED || state == SND_SOC_DPCM_STATE_PAUSED ||
state == SND_SOC_DPCM_STATE_SUSPEND) { state == SND_SOC_DPCM_STATE_SUSPEND)
ret = 0; return 0;
break;
} }
}
spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
/* it's safe to free/stop this BE DAI */ /* it's safe to free/stop this BE DAI */
return ret; return 1;
} }
EXPORT_SYMBOL_GPL(snd_soc_dpcm_can_be_free_stop); 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; struct snd_soc_dpcm *dpcm;
int state; 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) { list_for_each_entry(dpcm, &be->dpcm[stream].fe_clients, list_fe) {
if (dpcm->fe == 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 || if (state == SND_SOC_DPCM_STATE_START ||
state == SND_SOC_DPCM_STATE_PAUSED || state == SND_SOC_DPCM_STATE_PAUSED ||
state == SND_SOC_DPCM_STATE_SUSPEND || state == SND_SOC_DPCM_STATE_SUSPEND ||
state == SND_SOC_DPCM_STATE_PREPARE) { state == SND_SOC_DPCM_STATE_PREPARE)
ret = 0; return 0;
break;
} }
}
spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
/* it's safe to change hw_params */ /* it's safe to change hw_params */
return ret; return 1;
} }
EXPORT_SYMBOL_GPL(snd_soc_dpcm_can_be_params); 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_pcm_hw_params *params = &fe->dpcm[stream].hw_params;
struct snd_soc_dpcm *dpcm; struct snd_soc_dpcm *dpcm;
ssize_t offset = 0; ssize_t offset = 0;
unsigned long flags;
/* FE state */ /* FE state */
offset += scnprintf(buf + offset, size - offset, offset += scnprintf(buf + offset, size - offset,
@@ -3489,7 +3464,6 @@ static ssize_t dpcm_show_state(struct snd_soc_pcm_runtime *fe,
goto out; goto out;
} }
spin_lock_irqsave(&fe->card->dpcm_lock, flags);
list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
struct snd_soc_pcm_runtime *be = dpcm->be; struct snd_soc_pcm_runtime *be = dpcm->be;
params = &dpcm->hw_params; params = &dpcm->hw_params;
@@ -3510,7 +3484,7 @@ static ssize_t dpcm_show_state(struct snd_soc_pcm_runtime *fe,
params_channels(params), params_channels(params),
params_rate(params)); params_rate(params));
} }
spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
out: out:
return offset; return offset;
} }