ASoC: dapm: Move dai_link widgets to runtime to fix use after free

The newly added CODEC to CODEC DAI link widget pointers in
snd_soc_dai_link are better placed in snd_soc_pcm_runtime.
snd_soc_dai_link is really intended for static configuration of
the DAI, and the runtime for dynamic data.  The snd_soc_dai_link
structures are not destroyed if the card is unbound. The widgets
are cleared up on unbind, however if the card is rebound as the
snd_soc_dai_link structures are reused these pointers will be left at
their old values, causing access to freed memory.

Fixes: 595571cca4 ("ASoC: dapm: Fix regression introducing multiple copies of DAI widgets")
Signed-off-by: Charles Keepax <ckeepax@opensource.cirrus.com>
Link: https://lore.kernel.org/r/20200526161930.30759-1-ckeepax@opensource.cirrus.com
Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
Charles Keepax 2020-05-26 17:19:30 +01:00 committed by Mark Brown
parent 53a58bf96b
commit f4aa5e214e
No known key found for this signature in database
GPG Key ID: 24D68B725D5487D0
2 changed files with 9 additions and 9 deletions

View File

@ -790,9 +790,6 @@ struct snd_soc_dai_link {
const struct snd_soc_pcm_stream *params; const struct snd_soc_pcm_stream *params;
unsigned int num_params; unsigned int num_params;
struct snd_soc_dapm_widget *playback_widget;
struct snd_soc_dapm_widget *capture_widget;
unsigned int dai_fmt; /* format to set on init */ unsigned int dai_fmt; /* format to set on init */
enum snd_soc_dpcm_trigger trigger[2]; /* trigger type for DPCM */ enum snd_soc_dpcm_trigger trigger[2]; /* trigger type for DPCM */
@ -1156,6 +1153,9 @@ struct snd_soc_pcm_runtime {
struct snd_soc_dai **cpu_dais; struct snd_soc_dai **cpu_dais;
unsigned int num_cpus; unsigned int num_cpus;
struct snd_soc_dapm_widget *playback_widget;
struct snd_soc_dapm_widget *capture_widget;
struct delayed_work delayed_work; struct delayed_work delayed_work;
void (*close_delayed_work_func)(struct snd_soc_pcm_runtime *rtd); void (*close_delayed_work_func)(struct snd_soc_pcm_runtime *rtd);
#ifdef CONFIG_DEBUG_FS #ifdef CONFIG_DEBUG_FS

View File

@ -4340,16 +4340,16 @@ static void dapm_connect_dai_pair(struct snd_soc_card *card,
codec = codec_dai->playback_widget; codec = codec_dai->playback_widget;
if (playback_cpu && codec) { if (playback_cpu && codec) {
if (dai_link->params && !dai_link->playback_widget) { if (dai_link->params && !rtd->playback_widget) {
substream = streams[SNDRV_PCM_STREAM_PLAYBACK].substream; substream = streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
dai = snd_soc_dapm_new_dai(card, substream, "playback"); dai = snd_soc_dapm_new_dai(card, substream, "playback");
if (IS_ERR(dai)) if (IS_ERR(dai))
goto capture; goto capture;
dai_link->playback_widget = dai; rtd->playback_widget = dai;
} }
dapm_connect_dai_routes(&card->dapm, cpu_dai, playback_cpu, dapm_connect_dai_routes(&card->dapm, cpu_dai, playback_cpu,
dai_link->playback_widget, rtd->playback_widget,
codec_dai, codec); codec_dai, codec);
} }
@ -4358,16 +4358,16 @@ static void dapm_connect_dai_pair(struct snd_soc_card *card,
codec = codec_dai->capture_widget; codec = codec_dai->capture_widget;
if (codec && capture_cpu) { if (codec && capture_cpu) {
if (dai_link->params && !dai_link->capture_widget) { if (dai_link->params && !rtd->capture_widget) {
substream = streams[SNDRV_PCM_STREAM_CAPTURE].substream; substream = streams[SNDRV_PCM_STREAM_CAPTURE].substream;
dai = snd_soc_dapm_new_dai(card, substream, "capture"); dai = snd_soc_dapm_new_dai(card, substream, "capture");
if (IS_ERR(dai)) if (IS_ERR(dai))
return; return;
dai_link->capture_widget = dai; rtd->capture_widget = dai;
} }
dapm_connect_dai_routes(&card->dapm, codec_dai, codec, dapm_connect_dai_routes(&card->dapm, codec_dai, codec,
dai_link->capture_widget, rtd->capture_widget,
cpu_dai, capture_cpu); cpu_dai, capture_cpu);
} }
} }