]> git.ipfire.org Git - thirdparty/kernel/stable.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)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 4 Jun 2025 12:37:07 +0000 (14:37 +0200)
commit 93a81ca0657758b607c3f4ba889ae806be9beb73 upstream.

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>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
include/sound/pcm.h
sound/core/oss/pcm_oss.c
sound/core/pcm_native.c

index 6554a9f71c62ef08efebc8debf9a4adf4cf2d111..c573c6a7da1297eac5c7680ca5339dc8a908915c 100644 (file)
@@ -1334,6 +1334,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 de6f94bee50b9ac03f22398ffcb91e09574ab92d..8eb5fef41dbee7f77a0bdf40cb4dc543bd2786a4 100644 (file)
@@ -1078,8 +1078,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 9425fcd30c4c78df584d36554d3e4cba930d82e5..98bd6fe850d30d9cb953c56e0a00c11f12a01cd9 100644 (file)
@@ -685,6 +685,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