Commit ff7e06a5 authored by Takashi Iwai's avatar Takashi Iwai

ALSA: pcm: oss: Fix regression by buffer overflow fix (again)

[ This is essentially the same fix as commit ae769d35, but it's
  adapted to the latest code for 5.7; hence it contains no Fixes or
  other tags for avoid backport confusion -- tiwai ]

The recent fix for the OOB access in PCM OSS plugins (commit
f2ecf903: "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.

Link: https://lore.kernel.org/r/20200403073818.27943-1-tiwai@suse.deSigned-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent dbdd24ea
...@@ -197,7 +197,8 @@ int snd_pcm_plugin_free(struct snd_pcm_plugin *plugin) ...@@ -197,7 +197,8 @@ int snd_pcm_plugin_free(struct snd_pcm_plugin *plugin)
} }
static snd_pcm_sframes_t calc_dst_frames(struct snd_pcm_substream *plug, static snd_pcm_sframes_t calc_dst_frames(struct snd_pcm_substream *plug,
snd_pcm_sframes_t frames) snd_pcm_sframes_t frames,
bool check_size)
{ {
struct snd_pcm_plugin *plugin, *plugin_next; struct snd_pcm_plugin *plugin, *plugin_next;
...@@ -209,7 +210,7 @@ static snd_pcm_sframes_t calc_dst_frames(struct snd_pcm_substream *plug, ...@@ -209,7 +210,7 @@ static snd_pcm_sframes_t calc_dst_frames(struct snd_pcm_substream *plug,
if (frames < 0) if (frames < 0)
return frames; return frames;
} }
if (frames > plugin->buf_frames) if (check_size && frames > plugin->buf_frames)
frames = plugin->buf_frames; frames = plugin->buf_frames;
plugin = plugin_next; plugin = plugin_next;
} }
...@@ -217,13 +218,14 @@ static snd_pcm_sframes_t calc_dst_frames(struct snd_pcm_substream *plug, ...@@ -217,13 +218,14 @@ static snd_pcm_sframes_t calc_dst_frames(struct snd_pcm_substream *plug,
} }
static snd_pcm_sframes_t calc_src_frames(struct snd_pcm_substream *plug, static snd_pcm_sframes_t calc_src_frames(struct snd_pcm_substream *plug,
snd_pcm_sframes_t frames) snd_pcm_sframes_t frames,
bool check_size)
{ {
struct snd_pcm_plugin *plugin, *plugin_prev; struct snd_pcm_plugin *plugin, *plugin_prev;
plugin = snd_pcm_plug_last(plug); plugin = snd_pcm_plug_last(plug);
while (plugin && frames > 0) { while (plugin && frames > 0) {
if (frames > plugin->buf_frames) if (check_size && frames > plugin->buf_frames)
frames = plugin->buf_frames; frames = plugin->buf_frames;
plugin_prev = plugin->prev; plugin_prev = plugin->prev;
if (plugin->src_frames) { if (plugin->src_frames) {
...@@ -242,9 +244,9 @@ snd_pcm_sframes_t snd_pcm_plug_client_size(struct snd_pcm_substream *plug, snd_p ...@@ -242,9 +244,9 @@ snd_pcm_sframes_t snd_pcm_plug_client_size(struct snd_pcm_substream *plug, snd_p
return -ENXIO; return -ENXIO;
switch (snd_pcm_plug_stream(plug)) { switch (snd_pcm_plug_stream(plug)) {
case SNDRV_PCM_STREAM_PLAYBACK: case SNDRV_PCM_STREAM_PLAYBACK:
return calc_src_frames(plug, drv_frames); return calc_src_frames(plug, drv_frames, false);
case SNDRV_PCM_STREAM_CAPTURE: case SNDRV_PCM_STREAM_CAPTURE:
return calc_dst_frames(plug, drv_frames); return calc_dst_frames(plug, drv_frames, false);
default: default:
snd_BUG(); snd_BUG();
return -EINVAL; return -EINVAL;
...@@ -257,9 +259,9 @@ snd_pcm_sframes_t snd_pcm_plug_slave_size(struct snd_pcm_substream *plug, snd_pc ...@@ -257,9 +259,9 @@ snd_pcm_sframes_t snd_pcm_plug_slave_size(struct snd_pcm_substream *plug, snd_pc
return -ENXIO; return -ENXIO;
switch (snd_pcm_plug_stream(plug)) { switch (snd_pcm_plug_stream(plug)) {
case SNDRV_PCM_STREAM_PLAYBACK: case SNDRV_PCM_STREAM_PLAYBACK:
return calc_dst_frames(plug, clt_frames); return calc_dst_frames(plug, clt_frames, false);
case SNDRV_PCM_STREAM_CAPTURE: case SNDRV_PCM_STREAM_CAPTURE:
return calc_src_frames(plug, clt_frames); return calc_src_frames(plug, clt_frames, false);
default: default:
snd_BUG(); snd_BUG();
return -EINVAL; return -EINVAL;
...@@ -622,7 +624,7 @@ snd_pcm_sframes_t snd_pcm_plug_write_transfer(struct snd_pcm_substream *plug, st ...@@ -622,7 +624,7 @@ snd_pcm_sframes_t snd_pcm_plug_write_transfer(struct snd_pcm_substream *plug, st
src_channels = dst_channels; src_channels = dst_channels;
plugin = next; plugin = next;
} }
return snd_pcm_plug_client_size(plug, frames); return calc_src_frames(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) 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)
...@@ -632,7 +634,7 @@ snd_pcm_sframes_t snd_pcm_plug_read_transfer(struct snd_pcm_substream *plug, str ...@@ -632,7 +634,7 @@ snd_pcm_sframes_t snd_pcm_plug_read_transfer(struct snd_pcm_substream *plug, str
snd_pcm_sframes_t frames = size; snd_pcm_sframes_t frames = size;
int err; int err;
frames = snd_pcm_plug_slave_size(plug, frames); frames = calc_src_frames(plug, frames, true);
if (frames < 0) if (frames < 0)
return frames; return frames;
......
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