| From 83c627e21ea3180a6b6556dae19b71a8cee6a666 Mon Sep 17 00:00:00 2001 |
| From: Takashi Iwai <tiwai@suse.de> |
| Date: Fri, 3 Apr 2020 09:25:15 +0200 |
| Subject: [PATCH] ALSA: pcm: oss: Fix regression by buffer overflow fix |
| |
| commit ae769d3556644888c964635179ef192995f40793 upstream. |
| |
| The recent fix for the OOB access in PCM OSS plugins (commit |
| f2ecf903ef06: "ALSA: pcm: oss: Avoid plugin buffer overflow") caused a |
| regression on OSS applications. The patch introduced the size check |
| in client and slave size calculations to limit to each plugin's buffer |
| size, but I overlooked that some code paths call those without |
| allocating the buffer but just for estimation. |
| |
| This patch fixes the bug by skipping the size check for those code |
| paths while keeping checking in the actual transfer calls. |
| |
| Fixes: f2ecf903ef06 ("ALSA: pcm: oss: Avoid plugin buffer overflow") |
| Tested-and-reported-by: Jari Ruusu <jari.ruusu@gmail.com> |
| Cc: <stable@vger.kernel.org> |
| Link: https://lore.kernel.org/r/20200403072515.25539-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 732bbede7ebf..8539047145de 100644 |
| --- a/sound/core/oss/pcm_plugin.c |
| +++ b/sound/core/oss/pcm_plugin.c |
| @@ -196,7 +196,9 @@ int snd_pcm_plugin_free(struct snd_pcm_plugin *plugin) |
| return 0; |
| } |
| |
| -snd_pcm_sframes_t snd_pcm_plug_client_size(struct snd_pcm_substream *plug, snd_pcm_uframes_t drv_frames) |
| +static snd_pcm_sframes_t plug_client_size(struct snd_pcm_substream *plug, |
| + snd_pcm_uframes_t drv_frames, |
| + bool check_size) |
| { |
| struct snd_pcm_plugin *plugin, *plugin_prev, *plugin_next; |
| int stream; |
| @@ -209,7 +211,7 @@ 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) |
| + if (check_size && drv_frames > plugin->buf_frames) |
| drv_frames = plugin->buf_frames; |
| plugin_prev = plugin->prev; |
| if (plugin->src_frames) |
| @@ -222,7 +224,7 @@ 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) |
| + if (check_size && drv_frames > plugin->buf_frames) |
| drv_frames = plugin->buf_frames; |
| plugin = plugin_next; |
| } |
| @@ -231,7 +233,9 @@ snd_pcm_sframes_t snd_pcm_plug_client_size(struct snd_pcm_substream *plug, snd_p |
| return drv_frames; |
| } |
| |
| -snd_pcm_sframes_t snd_pcm_plug_slave_size(struct snd_pcm_substream *plug, snd_pcm_uframes_t clt_frames) |
| +static snd_pcm_sframes_t plug_slave_size(struct snd_pcm_substream *plug, |
| + snd_pcm_uframes_t clt_frames, |
| + bool check_size) |
| { |
| struct snd_pcm_plugin *plugin, *plugin_prev, *plugin_next; |
| snd_pcm_sframes_t frames; |
| @@ -252,14 +256,14 @@ 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) |
| + if (check_size && 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) |
| + if (check_size && frames > plugin->buf_frames) |
| frames = plugin->buf_frames; |
| plugin_prev = plugin->prev; |
| if (plugin->src_frames) { |
| @@ -274,6 +278,18 @@ snd_pcm_sframes_t snd_pcm_plug_slave_size(struct snd_pcm_substream *plug, snd_pc |
| return frames; |
| } |
| |
| +snd_pcm_sframes_t snd_pcm_plug_client_size(struct snd_pcm_substream *plug, |
| + snd_pcm_uframes_t drv_frames) |
| +{ |
| + return plug_client_size(plug, drv_frames, false); |
| +} |
| + |
| +snd_pcm_sframes_t snd_pcm_plug_slave_size(struct snd_pcm_substream *plug, |
| + snd_pcm_uframes_t clt_frames) |
| +{ |
| + return plug_slave_size(plug, clt_frames, false); |
| +} |
| + |
| static int snd_pcm_plug_formats(const struct snd_mask *mask, |
| snd_pcm_format_t format) |
| { |
| @@ -630,7 +646,7 @@ snd_pcm_sframes_t snd_pcm_plug_write_transfer(struct snd_pcm_substream *plug, st |
| src_channels = dst_channels; |
| plugin = next; |
| } |
| - return snd_pcm_plug_client_size(plug, frames); |
| + return plug_client_size(plug, frames, true); |
| } |
| |
| snd_pcm_sframes_t snd_pcm_plug_read_transfer(struct snd_pcm_substream *plug, struct snd_pcm_plugin_channel *dst_channels_final, snd_pcm_uframes_t size) |
| @@ -640,7 +656,7 @@ snd_pcm_sframes_t snd_pcm_plug_read_transfer(struct snd_pcm_substream *plug, str |
| snd_pcm_sframes_t frames = size; |
| int err; |
| |
| - frames = snd_pcm_plug_slave_size(plug, frames); |
| + frames = plug_slave_size(plug, frames, true); |
| if (frames < 0) |
| return frames; |
| |
| -- |
| 2.7.4 |
| |