Commit 4cc8d650 authored by Takashi Iwai's avatar Takashi Iwai

ALSA: pcm: oss: Avoid potential buffer overflows

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.deSigned-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 643a2cc9
...@@ -107,6 +107,8 @@ static snd_pcm_sframes_t linear_transfer(struct snd_pcm_plugin *plugin, ...@@ -107,6 +107,8 @@ static snd_pcm_sframes_t linear_transfer(struct snd_pcm_plugin *plugin,
} }
} }
#endif #endif
if (frames > dst_channels[0].frames)
frames = dst_channels[0].frames;
convert(plugin, src_channels, dst_channels, frames); convert(plugin, src_channels, dst_channels, frames);
return frames; return frames;
} }
......
...@@ -269,6 +269,8 @@ static snd_pcm_sframes_t mulaw_transfer(struct snd_pcm_plugin *plugin, ...@@ -269,6 +269,8 @@ static snd_pcm_sframes_t mulaw_transfer(struct snd_pcm_plugin *plugin,
} }
} }
#endif #endif
if (frames > dst_channels[0].frames)
frames = dst_channels[0].frames;
data = (struct mulaw_priv *)plugin->extra_data; data = (struct mulaw_priv *)plugin->extra_data;
data->func(plugin, src_channels, dst_channels, frames); data->func(plugin, src_channels, dst_channels, frames);
return frames; return frames;
......
...@@ -57,6 +57,8 @@ static snd_pcm_sframes_t route_transfer(struct snd_pcm_plugin *plugin, ...@@ -57,6 +57,8 @@ static snd_pcm_sframes_t route_transfer(struct snd_pcm_plugin *plugin,
return -ENXIO; return -ENXIO;
if (frames == 0) if (frames == 0)
return 0; return 0;
if (frames > dst_channels[0].frames)
frames = dst_channels[0].frames;
nsrcs = plugin->src_format.channels; nsrcs = plugin->src_format.channels;
ndsts = plugin->dst_format.channels; ndsts = plugin->dst_format.channels;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment