ALSA: pcm: oss: Avoid potential buffer overflows
authorTakashi Iwai <tiwai@suse.de>
Wed, 4 Dec 2019 14:48:24 +0000 (15:48 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 13 Dec 2019 07:52:37 +0000 (08:52 +0100)
commit 4cc8d6505ab82db3357613d36e6c58a297f57f7c upstream.

syzkaller reported an invalid access in PCM OSS read, and this seems
to be an overflow of the internal buffer allocated for a plugin.
Since the rate plugin adjusts its transfer size dynamically, the
calculation for the chained plugin might be bigger than the given
buffer size in some extreme cases, which lead to such an buffer
overflow as caught by KASAN.

Fix it by limiting the max transfer size properly by checking against
the destination size in each plugin transfer callback.

Reported-by: syzbot+f153bde47a62e0b05f83@syzkaller.appspotmail.com
Cc: <stable@vger.kernel.org>
Link: https://lore.kernel.org/r/20191204144824.17801-1-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
sound/core/oss/linear.c
sound/core/oss/mulaw.c
sound/core/oss/route.c

index 2045697..797d838 100644 (file)
@@ -107,6 +107,8 @@ static snd_pcm_sframes_t linear_transfer(struct snd_pcm_plugin *plugin,
                }
        }
 #endif
+       if (frames > dst_channels[0].frames)
+               frames = dst_channels[0].frames;
        convert(plugin, src_channels, dst_channels, frames);
        return frames;
 }
index 7915564..3788906 100644 (file)
@@ -269,6 +269,8 @@ static snd_pcm_sframes_t mulaw_transfer(struct snd_pcm_plugin *plugin,
                }
        }
 #endif
+       if (frames > dst_channels[0].frames)
+               frames = dst_channels[0].frames;
        data = (struct mulaw_priv *)plugin->extra_data;
        data->func(plugin, src_channels, dst_channels, frames);
        return frames;
index c8171f5..72dea04 100644 (file)
@@ -57,6 +57,8 @@ static snd_pcm_sframes_t route_transfer(struct snd_pcm_plugin *plugin,
                return -ENXIO;
        if (frames == 0)
                return 0;
+       if (frames > dst_channels[0].frames)
+               frames = dst_channels[0].frames;
 
        nsrcs = plugin->src_format.channels;
        ndsts = plugin->dst_format.channels;