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


Reply via email to