summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2025-05-16 10:08:16 +0200
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2025-06-04 14:37:07 +0200
commit8170d8ec4efd0be352c14cb61f374e30fb0c2a25 (patch)
treee0f6b87c02c76b00d02e71e4de560d49d1610401
parent659701c0b954ccdb4a916a4ad59bbc16e726d42c (diff)
downloadlinux-8170d8ec4efd0be352c14cb61f374e30fb0c2a25.tar.gz
linux-8170d8ec4efd0be352c14cb61f374e30fb0c2a25.tar.bz2
linux-8170d8ec4efd0be352c14cb61f374e30fb0c2a25.zip
ALSA: pcm: Fix race of buffer access at PCM OSS layer
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>
-rw-r--r--include/sound/pcm.h2
-rw-r--r--sound/core/oss/pcm_oss.c3
-rw-r--r--sound/core/pcm_native.c11
3 files changed, 14 insertions, 2 deletions
diff --git a/include/sound/pcm.h b/include/sound/pcm.h
index 6554a9f71c62..c573c6a7da12 100644
--- a/include/sound/pcm.h
+++ b/include/sound/pcm.h
@@ -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
diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c
index de6f94bee50b..8eb5fef41dbe 100644
--- a/sound/core/oss/pcm_oss.c
+++ b/sound/core/oss/pcm_oss.c
@@ -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);
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 9425fcd30c4c..98bd6fe850d3 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -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