hw_params() can be called again without hw_free() in between.
fsl_easrc_hw_params() then requests a second context while the stream
still owns the first one, which is never released. After close, that
easrc->pair[] entry points to freed memory and is dereferenced by
fsl_easrc_runtime_resume() on the next open.
The EASRC slots depend on the number of channels, so release the owned
context before requesting a new one, and make
fsl_easrc_release_context() ignore a context it does not own.
Fixes: 955ac624058f ("ASoC: fsl_easrc: Add EASRC ASoC CPU DAI drivers")
Signed-off-by: Stefan Ghetu <[email protected]>
---
sound/soc/fsl/fsl_easrc.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/sound/soc/fsl/fsl_easrc.c b/sound/soc/fsl/fsl_easrc.c
index 5d715bc07357..ae0fbf6c316b 100644
--- a/sound/soc/fsl/fsl_easrc.c
+++ b/sound/soc/fsl/fsl_easrc.c
@@ -1347,6 +1347,10 @@ static void fsl_easrc_release_context(struct
fsl_asrc_pair *ctx)
guard(spinlock_irqsave)(&easrc->lock);
+ /* Nothing to release if the context is not owned by @ctx */
+ if (easrc->pair[ctx->index] != ctx)
+ return;
+
fsl_easrc_release_slot(easrc, ctx->index);
easrc->channel_avail += ctx->channels;
@@ -1500,6 +1504,12 @@ static int fsl_easrc_hw_params(struct snd_pcm_substream
*substream,
snd_pcm_format_t format = params_format(params);
int ret;
+ /* hw_params() may be called again without hw_free() in between */
+ if (ctx_priv->ctx_streams & BIT(substream->stream)) {
+ ctx_priv->ctx_streams &= ~BIT(substream->stream);
+ fsl_easrc_release_context(ctx);
+ }
+
ret = fsl_easrc_request_context(channels, ctx);
if (ret) {
dev_err(dev, "failed to request context\n");
--
2.53.0