[alsa-devel] [PATCH] ASoC: STI: Fix null ptr deference in IRQ handler
Takashi Iwai
tiwai at suse.de
Mon Mar 20 18:42:58 CET 2017
On Mon, 20 Mar 2017 18:09:15 +0100,
Arnaud Pouliquen wrote:
>
> With RTlinux a race condition has been found that leads to NULL ptr crash:
> - On CPU 0: uni_player_irq_handler is called to treat XRUN
> "(player->state == UNIPERIF_STATE_STOPPED)" is FALSE so status is checked,
> dev_err(player->dev, "FIFO underflow error detected") is printed
> and then snd_pcm_stream_lock should be called to lock stream for stopping.
> - On CPU 1: application stop and close the stream.
> Issue is that the stop and shutdown functions are executed while
> "FIFO underflow error detected" is printed.
> So when CPU 0 call snd_pcm_stream_lock is player->substream is already null.
Hrm, how the first call of snd_pcm_stream_lock() with
player->substream to be guaranteed to be non-NULL?
Takashi
>
> Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen at st.com>
> ---
> sound/soc/sti/uniperif_player.c | 9 +++------
> sound/soc/sti/uniperif_reader.c | 8 +++++---
> 2 files changed, 8 insertions(+), 9 deletions(-)
>
> diff --git a/sound/soc/sti/uniperif_player.c b/sound/soc/sti/uniperif_player.c
> index 60ae31a..6fa9eee 100644
> --- a/sound/soc/sti/uniperif_player.c
> +++ b/sound/soc/sti/uniperif_player.c
> @@ -65,8 +65,10 @@ static irqreturn_t uni_player_irq_handler(int irq, void *dev_id)
> unsigned int status;
> unsigned int tmp;
>
> + snd_pcm_stream_lock(player->substream);
> if (player->state == UNIPERIF_STATE_STOPPED) {
> /* Unexpected IRQ: do nothing */
> + snd_pcm_stream_unlock(player->substream);
> return IRQ_NONE;
> }
>
> @@ -88,9 +90,7 @@ static irqreturn_t uni_player_irq_handler(int irq, void *dev_id)
> SET_UNIPERIF_ITM_BCLR_FIFO_ERROR(player);
>
> /* Stop the player */
> - snd_pcm_stream_lock(player->substream);
> snd_pcm_stop(player->substream, SNDRV_PCM_STATE_XRUN);
> - snd_pcm_stream_unlock(player->substream);
> }
>
> ret = IRQ_HANDLED;
> @@ -104,9 +104,7 @@ static irqreturn_t uni_player_irq_handler(int irq, void *dev_id)
> SET_UNIPERIF_ITM_BCLR_DMA_ERROR(player);
>
> /* Stop the player */
> - snd_pcm_stream_lock(player->substream);
> snd_pcm_stop(player->substream, SNDRV_PCM_STATE_XRUN);
> - snd_pcm_stream_unlock(player->substream);
>
> ret = IRQ_HANDLED;
> }
> @@ -138,13 +136,12 @@ static irqreturn_t uni_player_irq_handler(int irq, void *dev_id)
> dev_err(player->dev, "Underflow recovery failed\n");
>
> /* Stop the player */
> - snd_pcm_stream_lock(player->substream);
> snd_pcm_stop(player->substream, SNDRV_PCM_STATE_XRUN);
> - snd_pcm_stream_unlock(player->substream);
>
> ret = IRQ_HANDLED;
> }
>
> + snd_pcm_stream_unlock(player->substream);
> return ret;
> }
>
> diff --git a/sound/soc/sti/uniperif_reader.c b/sound/soc/sti/uniperif_reader.c
> index 5992c6a..9273f59 100644
> --- a/sound/soc/sti/uniperif_reader.c
> +++ b/sound/soc/sti/uniperif_reader.c
> @@ -46,9 +46,11 @@ static irqreturn_t uni_reader_irq_handler(int irq, void *dev_id)
> struct uniperif *reader = dev_id;
> unsigned int status;
>
> + snd_pcm_stream_lock(reader->substream);
> if (reader->state == UNIPERIF_STATE_STOPPED) {
> /* Unexpected IRQ: do nothing */
> dev_warn(reader->dev, "unexpected IRQ\n");
> + snd_pcm_stream_unlock(reader->substream);
> return IRQ_HANDLED;
> }
>
> @@ -60,13 +62,13 @@ static irqreturn_t uni_reader_irq_handler(int irq, void *dev_id)
> if (unlikely(status & UNIPERIF_ITS_FIFO_ERROR_MASK(reader))) {
> dev_err(reader->dev, "FIFO error detected\n");
>
> - snd_pcm_stream_lock(reader->substream);
> snd_pcm_stop(reader->substream, SNDRV_PCM_STATE_XRUN);
> - snd_pcm_stream_unlock(reader->substream);
>
> - return IRQ_HANDLED;
> + ret = IRQ_HANDLED;
> }
>
> + snd_pcm_stream_unlock(reader->substream);
> +
> return ret;
> }
>
> --
> 1.9.1
>
More information about the Alsa-devel
mailing list