[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