| From 69534c48ba8ce552ce383b3dfdb271ffe51820c3 Mon Sep 17 00:00:00 2001 |
| From: Takashi Iwai <tiwai@suse.de> |
| Date: Tue, 22 Mar 2022 18:07:20 +0100 |
| Subject: ALSA: pcm: Fix races among concurrent prealloc proc writes |
| |
| From: Takashi Iwai <tiwai@suse.de> |
| |
| commit 69534c48ba8ce552ce383b3dfdb271ffe51820c3 upstream. |
| |
| We have no protection against concurrent PCM buffer preallocation |
| changes via proc files, and it may potentially lead to UAF or some |
| weird problem. This patch applies the PCM open_mutex to the proc |
| write operation for avoiding the racy proc writes and the PCM stream |
| open (and further operations). |
| |
| Cc: <stable@vger.kernel.org> |
| Reviewed-by: Jaroslav Kysela <perex@perex.cz> |
| Link: https://lore.kernel.org/r/20220322170720.3529-5-tiwai@suse.de |
| Signed-off-by: Takashi Iwai <tiwai@suse.de> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| sound/core/pcm_memory.c | 11 +++++++---- |
| 1 file changed, 7 insertions(+), 4 deletions(-) |
| |
| --- a/sound/core/pcm_memory.c |
| +++ b/sound/core/pcm_memory.c |
| @@ -163,19 +163,20 @@ static void snd_pcm_lib_preallocate_proc |
| size_t size; |
| struct snd_dma_buffer new_dmab; |
| |
| + mutex_lock(&substream->pcm->open_mutex); |
| if (substream->runtime) { |
| buffer->error = -EBUSY; |
| - return; |
| + goto unlock; |
| } |
| if (!snd_info_get_line(buffer, line, sizeof(line))) { |
| snd_info_get_str(str, line, sizeof(str)); |
| size = simple_strtoul(str, NULL, 10) * 1024; |
| if ((size != 0 && size < 8192) || size > substream->dma_max) { |
| buffer->error = -EINVAL; |
| - return; |
| + goto unlock; |
| } |
| if (substream->dma_buffer.bytes == size) |
| - return; |
| + goto unlock; |
| memset(&new_dmab, 0, sizeof(new_dmab)); |
| new_dmab.dev = substream->dma_buffer.dev; |
| if (size > 0) { |
| @@ -189,7 +190,7 @@ static void snd_pcm_lib_preallocate_proc |
| substream->pcm->card->number, substream->pcm->device, |
| substream->stream ? 'c' : 'p', substream->number, |
| substream->pcm->name, size); |
| - return; |
| + goto unlock; |
| } |
| substream->buffer_bytes_max = size; |
| } else { |
| @@ -201,6 +202,8 @@ static void snd_pcm_lib_preallocate_proc |
| } else { |
| buffer->error = -EINVAL; |
| } |
| + unlock: |
| + mutex_unlock(&substream->pcm->open_mutex); |
| } |
| |
| static inline void preallocate_info_init(struct snd_pcm_substream *substream) |