]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
ALSA: pcm: Fix race of buffer access at PCM OSS layer
authorTakashi Iwai <tiwai@suse.de>
Fri, 16 May 2025 08:08:16 +0000 (10:08 +0200)
committerTakashi Iwai <tiwai@suse.de>
Fri, 16 May 2025 08:09:02 +0000 (10:09 +0200)
The PCM OSS layer tries to clear the buffer with the silence data at
initialization (or reconfiguration) of a stream with the explicit call
of snd_pcm_format_set_silence() with runtime->dma_area.  But this may
lead to a UAF because the accessed runtime->dma_area might be freed
concurrently, as it's performed outside the PCM ops.

For avoiding it, move the code into the PCM core and perform it inside
the buffer access lock, so that it won't be changed during the
operation.

Reported-by: syzbot+32d4647f551007595173@syzkaller.appspotmail.com
Closes: https://lore.kernel.org/68164d8e.050a0220.11da1b.0019.GAE@google.com
Cc: <stable@vger.kernel.org>
Link: https://patch.msgid.link/20250516080817.20068-1-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
include/sound/pcm.h
sound/core/oss/pcm_oss.c
sound/core/pcm_native.c

index 8becb450488736763c5662e0dd64d84ae90da84b..8582d22f3818476e84caab9f768f4a3b771d67b3 100644 (file)
@@ -1404,6 +1404,8 @@ int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream, struct vm_area_s
 #define snd_pcm_lib_mmap_iomem NULL
 #endif
 
+void snd_pcm_runtime_buffer_set_silence(struct snd_pcm_runtime *runtime);
+
 /**
  * snd_pcm_limit_isa_dma_size - Get the max size fitting with ISA DMA transfer
  * @dma: DMA number
index 4683b9139c566a0134e59e5adc99df7f5de509f6..4ecb17bd5436e7829d607e0be03c794768eb4632 100644 (file)
@@ -1074,8 +1074,7 @@ static int snd_pcm_oss_change_params_locked(struct snd_pcm_substream *substream)
        runtime->oss.params = 0;
        runtime->oss.prepare = 1;
        runtime->oss.buffer_used = 0;
-       if (runtime->dma_area)
-               snd_pcm_format_set_silence(runtime->format, runtime->dma_area, bytes_to_samples(runtime, runtime->dma_bytes));
+       snd_pcm_runtime_buffer_set_silence(runtime);
 
        runtime->oss.period_frames = snd_pcm_alsa_frames(substream, oss_period_size);
 
index 6c2b6a62d9d2f8011e44cf0432daeaa553011d6d..853ac5bb33ff2a8718bd22217edaab5437cd4316 100644 (file)
@@ -723,6 +723,17 @@ static void snd_pcm_buffer_access_unlock(struct snd_pcm_runtime *runtime)
        atomic_inc(&runtime->buffer_accessing);
 }
 
+/* fill the PCM buffer with the current silence format; called from pcm_oss.c */
+void snd_pcm_runtime_buffer_set_silence(struct snd_pcm_runtime *runtime)
+{
+       snd_pcm_buffer_access_lock(runtime);
+       if (runtime->dma_area)
+               snd_pcm_format_set_silence(runtime->format, runtime->dma_area,
+                                          bytes_to_samples(runtime, runtime->dma_bytes));
+       snd_pcm_buffer_access_unlock(runtime);
+}
+EXPORT_SYMBOL_GPL(snd_pcm_runtime_buffer_set_silence);
+
 #if IS_ENABLED(CONFIG_SND_PCM_OSS)
 #define is_oss_stream(substream)       ((substream)->oss.oss)
 #else