OSDN Git Service

ALSA: pcm: Fix races among concurrent prealloc proc writes
authorTakashi Iwai <tiwai@suse.de>
Tue, 22 Mar 2022 17:07:20 +0000 (18:07 +0100)
committerTakashi Iwai <tiwai@suse.de>
Tue, 22 Mar 2022 19:56:58 +0000 (20:56 +0100)
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>
sound/core/pcm_memory.c

index b70ce3b..8848d2f 100644 (file)
@@ -163,19 +163,20 @@ static void snd_pcm_lib_preallocate_proc_write(struct snd_info_entry *entry,
        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_write(struct snd_info_entry *entry,
                                         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_write(struct snd_info_entry *entry,
        } else {
                buffer->error = -EINVAL;
        }
+ unlock:
+       mutex_unlock(&substream->pcm->open_mutex);
 }
 
 static inline void preallocate_info_init(struct snd_pcm_substream *substream)