ALSA: pcm: oss: Avoid potential buffer overflows
authorTakashi Iwai <tiwai@suse.de>
Wed, 4 Dec 2019 14:48:24 +0000 (15:48 +0100)
committerTakashi Iwai <tiwai@suse.de>
Wed, 4 Dec 2019 14:51:30 +0000 (15:51 +0100)
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>
sound/core/oss/linear.c
sound/core/oss/mulaw.c
sound/core/oss/route.c

index 2045697f449d3f5ebe347572dc2dfba66b64568a..797d838a2f9eb4ef7c3ebb7d6e56858d8ac077a5 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 7915564bd39445fd45e8cff34330ea269c6e9476..3788906421a73d2b34979fbf4fbfbd33fc8010e8 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 c8171f5783c873c49eaa86d61420b99e30adfac8..72dea04197ef2ffd820cb8f36de4c25d09587f67 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;