]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
ALSA: pcm: oss: Avoid plugin buffer overflow
authorTakashi Iwai <tiwai@suse.de>
Mon, 9 Mar 2020 08:21:48 +0000 (09:21 +0100)
committerTakashi Iwai <tiwai@suse.de>
Mon, 9 Mar 2020 08:22:22 +0000 (09:22 +0100)
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
Link: https://lore.kernel.org/r/20200309082148.19855-1-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
sound/core/oss/pcm_plugin.c

index 240e4702c09881409cd3de59306bae2409d5258f..c9401832967c3c5e0382bc7c472f8be772064830 100644 (file)
@@ -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);