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;
|
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 */
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user