[PATCH] ALSA: pcm: oss: Avoid plugin buffer overflow

Each OSS PCM plugins allocate its internal buffer per pre-calculation of the max buffer size through the chain of plugins (calling src_frames and dst_frames callbacks). This works for most plugins, but the rate plugin might behave incorrectly. The calculation in the rate plugin involves with the fractional position, i.e. it may vary depending on the input position. Since the buffer size pre-calculation is always done with the offset zero, it may return a shorter size than it might be; this may result in the out-of-bound access as spotted by fuzzer.
This patch addresses those possible buffer overflow accesses by simply setting the upper limit per the given buffer size for each plugin before src_frames() and after dst_frames() calls.
Reported-by: syzbot+e1fe9f44fb8ecf4fb5dd@syzkaller.appspotmail.com Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/000000000000b25ea005a02bcf21@google.com Signed-off-by: Takashi Iwai tiwai@suse.de --- sound/core/oss/pcm_plugin.c | 8 ++++++++ 1 file changed, 8 insertions(+)
diff --git a/sound/core/oss/pcm_plugin.c b/sound/core/oss/pcm_plugin.c index 240e4702c098..c9401832967c 100644 --- a/sound/core/oss/pcm_plugin.c +++ b/sound/core/oss/pcm_plugin.c @@ -209,6 +209,8 @@ snd_pcm_sframes_t snd_pcm_plug_client_size(struct snd_pcm_substream *plug, snd_p if (stream == SNDRV_PCM_STREAM_PLAYBACK) { plugin = snd_pcm_plug_last(plug); while (plugin && drv_frames > 0) { + if (drv_frames > plugin->buf_frames) + drv_frames = plugin->buf_frames; plugin_prev = plugin->prev; if (plugin->src_frames) drv_frames = plugin->src_frames(plugin, drv_frames); @@ -220,6 +222,8 @@ snd_pcm_sframes_t snd_pcm_plug_client_size(struct snd_pcm_substream *plug, snd_p plugin_next = plugin->next; if (plugin->dst_frames) drv_frames = plugin->dst_frames(plugin, drv_frames); + if (drv_frames > plugin->buf_frames) + drv_frames = plugin->buf_frames; plugin = plugin_next; } } else @@ -248,11 +252,15 @@ snd_pcm_sframes_t snd_pcm_plug_slave_size(struct snd_pcm_substream *plug, snd_pc if (frames < 0) return frames; } + if (frames > plugin->buf_frames) + frames = plugin->buf_frames; plugin = plugin_next; } } else if (stream == SNDRV_PCM_STREAM_CAPTURE) { plugin = snd_pcm_plug_last(plug); while (plugin) { + if (frames > plugin->buf_frames) + frames = plugin->buf_frames; plugin_prev = plugin->prev; if (plugin->src_frames) { frames = plugin->src_frames(plugin, frames);

...
This patch addresses those possible buffer overflow accesses by simply setting the upper limit per the given buffer size for each plugin before src_frames() and after dst_frames() calls.
Hi!
This patch breaks any output via oss interface, as evident by "mpv --ao=oss somefile.mp3" or "mpg123 -o oss somefile.mp3" or just "cat /dev/urandom > /dev/dsp", which worked previously in kernel version 5.5 but not any longer starting with 5.6.
It appears here that plugin->buf_frames is zero which results in ENXIO returned to userspace.
... --- a/sound/core/oss/pcm_plugin.c +++ b/sound/core/oss/pcm_plugin.c @@ -209,6 +209,8 @@ snd_pcm_sframes_t snd_pcm_plug_client_size(struct snd_pcm_substream *plug, snd_p if (stream == SNDRV_PCM_STREAM_PLAYBACK) { plugin = snd_pcm_plug_last(plug); while (plugin && drv_frames > 0) {
if (drv_frames > plugin->buf_frames)
drv_frames = plugin->buf_frames; plugin_prev = plugin->prev; if (plugin->src_frames) drv_frames = plugin->src_frames(plugin, drv_frames);
...

On Thu, 30 Apr 2020 18:34:02 +0200, Serge Belyshev wrote:
...
This patch addresses those possible buffer overflow accesses by simply setting the upper limit per the given buffer size for each plugin before src_frames() and after dst_frames() calls.
Hi!
This patch breaks any output via oss interface, as evident by "mpv --ao=oss somefile.mp3" or "mpg123 -o oss somefile.mp3" or just "cat /dev/urandom > /dev/dsp", which worked previously in kernel version 5.5 but not any longer starting with 5.6.
It appears here that plugin->buf_frames is zero which results in ENXIO returned to userspace.
The fix is already in sound git tree, and will be in the next pull request to 5.7-rc4.
thanks,
Takashi
participants (2)
-
Serge Belyshev
-
Takashi Iwai