[alsa-devel] [PATCH] ALSA: pcm: Fix possible inconsistent appl_ptr update via mmap

Takashi Sakamoto o-takashi at sakamocchi.jp
Sun Jun 18 12:49:24 CEST 2017


Hi,

On Jun 17 2017 05:40, Takashi Iwai wrote:
> The ALSA PCM core refers to the appl_ptr value stored on the mmapped
> page that is shared between kernel and user-space.  Although the
> reference is performed in the PCM stream lock, it doesn't guarantee
> the atomic access when the value gets updated concurrently from the
> user-space on another CPU.
> 
> In most of codes, this is no big problem, but still there are a few
> places that may result in slight inconsistencies because they access
> runtime->control->appl_ptr multiple times; that is, the second read
> might be a different value from the first value.  It can be even
> backward or jumping, as we have no control for it.  Hence, the
> calculation may give an unexpected value.  Luckily, there is no
> security vulnerability by that, as far as I've checked.  But still we
> should address it.
> 
> This patch tries to reduce such possible cases.  The fix is simple --
> we just read once, store it to a local variable and use it for the
> rest calculations.
> 
> Signed-off-by: Takashi Iwai <tiwai at suse.de>
> ---
>   sound/core/pcm_lib.c | 13 +++++++------
>   1 file changed, 7 insertions(+), 6 deletions(-)

This looks good to me by itself.

Reviewed-by: Takashi Sakamoto <o-takashi at sakamocchi.jp>

This function, 'snd_pcm_playback_silence()' can be called without 
acquiring stream lock by 'snd_pcm_reset()' when runtime of PCM substream 
is configured to have a larger value than zero to its 'silence_size' 
member. When a task or any IRQ handler operates the runtime and another 
task operates the reset in the same time, both of them got expected result.

I'll post a patch to take 'snd_pcm_reset()' to use 
'snd_pcm_action_lock_irq()' instead of 'snd_pcm_action_nonatomic()'. How 
do you think about it?

> diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
> index 631cd598ba6c..cda258d91490 100644
> --- a/sound/core/pcm_lib.c
> +++ b/sound/core/pcm_lib.c
> @@ -65,15 +65,16 @@ void snd_pcm_playback_silence(struct snd_pcm_substream *substream, snd_pcm_ufram
>   
>   	if (runtime->silence_size < runtime->boundary) {
>   		snd_pcm_sframes_t noise_dist, n;
> -		if (runtime->silence_start != runtime->control->appl_ptr) {
> -			n = runtime->control->appl_ptr - runtime->silence_start;
> +		snd_pcm_uframes_t appl_ptr = runtime->control->appl_ptr;
> +		if (runtime->silence_start != appl_ptr) {
> +			n = appl_ptr - runtime->silence_start;
>   			if (n < 0)
>   				n += runtime->boundary;
>   			if ((snd_pcm_uframes_t)n < runtime->silence_filled)
>   				runtime->silence_filled -= n;
>   			else
>   				runtime->silence_filled = 0;
> -			runtime->silence_start = runtime->control->appl_ptr;
> +			runtime->silence_start = appl_ptr;
>   		}
>   		if (runtime->silence_filled >= runtime->buffer_size)
>   			return;
> @@ -2224,7 +2225,9 @@ snd_pcm_sframes_t __snd_pcm_lib_xfer(struct snd_pcm_substream *substream,
>   				continue; /* draining */
>   		}
>   		frames = size > avail ? avail : size;
> -		cont = runtime->buffer_size - runtime->control->appl_ptr % runtime->buffer_size;
> +		appl_ptr = runtime->control->appl_ptr;
> +		appl_ofs = appl_ptr % runtime->buffer_size;
> +		cont = runtime->buffer_size - appl_ofs;
>   		if (frames > cont)
>   			frames = cont;
>   		if (snd_BUG_ON(!frames)) {
> @@ -2232,8 +2235,6 @@ snd_pcm_sframes_t __snd_pcm_lib_xfer(struct snd_pcm_substream *substream,
>   			snd_pcm_stream_unlock_irq(substream);
>   			return -EINVAL;
>   		}
> -		appl_ptr = runtime->control->appl_ptr;
> -		appl_ofs = appl_ptr % runtime->buffer_size;
>   		snd_pcm_stream_unlock_irq(substream);
>   		err = writer(substream, appl_ofs, data, offset, frames,
>   			     transfer);

Regards

Takashi Sakamoto


More information about the Alsa-devel mailing list