| From 73cc075b3dc145684abc22bcf30e3d4ecef230b0 Mon Sep 17 00:00:00 2001 |
| From: Takashi Iwai <tiwai@suse.de> |
| Date: Mon, 9 Mar 2020 09:21:48 +0100 |
| Subject: [PATCH] ALSA: pcm: oss: Avoid plugin buffer overflow |
| |
| commit f2ecf903ef06eb1bbbfa969db9889643d487e73a upstream. |
| |
| 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> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/sound/core/oss/pcm_plugin.c b/sound/core/oss/pcm_plugin.c |
| index 31cb2acf8afc..9b588c6a6f09 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); |
| -- |
| 2.7.4 |
| |