Commit 39675f7a authored by Takashi Iwai's avatar Takashi Iwai

ALSA: rawmidi: Change resized buffers atomically

The SNDRV_RAWMIDI_IOCTL_PARAMS ioctl may resize the buffers and the
current code is racy.  For example, the sequencer client may write to
buffer while it being resized.

As a simple workaround, let's switch to the resized buffer inside the
stream runtime lock.

Reported-by: syzbot+52f83f0ea8df16932f7f@syzkaller.appspotmail.com
Cc: <stable@vger.kernel.org>
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 0fca97a2
...@@ -635,7 +635,7 @@ static int snd_rawmidi_info_select_user(struct snd_card *card, ...@@ -635,7 +635,7 @@ static int snd_rawmidi_info_select_user(struct snd_card *card,
int snd_rawmidi_output_params(struct snd_rawmidi_substream *substream, int snd_rawmidi_output_params(struct snd_rawmidi_substream *substream,
struct snd_rawmidi_params * params) struct snd_rawmidi_params * params)
{ {
char *newbuf; char *newbuf, *oldbuf;
struct snd_rawmidi_runtime *runtime = substream->runtime; struct snd_rawmidi_runtime *runtime = substream->runtime;
if (substream->append && substream->use_count > 1) if (substream->append && substream->use_count > 1)
...@@ -648,13 +648,17 @@ int snd_rawmidi_output_params(struct snd_rawmidi_substream *substream, ...@@ -648,13 +648,17 @@ int snd_rawmidi_output_params(struct snd_rawmidi_substream *substream,
return -EINVAL; return -EINVAL;
} }
if (params->buffer_size != runtime->buffer_size) { if (params->buffer_size != runtime->buffer_size) {
newbuf = krealloc(runtime->buffer, params->buffer_size, newbuf = kmalloc(params->buffer_size, GFP_KERNEL);
GFP_KERNEL);
if (!newbuf) if (!newbuf)
return -ENOMEM; return -ENOMEM;
spin_lock_irq(&runtime->lock);
oldbuf = runtime->buffer;
runtime->buffer = newbuf; runtime->buffer = newbuf;
runtime->buffer_size = params->buffer_size; runtime->buffer_size = params->buffer_size;
runtime->avail = runtime->buffer_size; runtime->avail = runtime->buffer_size;
runtime->appl_ptr = runtime->hw_ptr = 0;
spin_unlock_irq(&runtime->lock);
kfree(oldbuf);
} }
runtime->avail_min = params->avail_min; runtime->avail_min = params->avail_min;
substream->active_sensing = !params->no_active_sensing; substream->active_sensing = !params->no_active_sensing;
...@@ -665,7 +669,7 @@ EXPORT_SYMBOL(snd_rawmidi_output_params); ...@@ -665,7 +669,7 @@ EXPORT_SYMBOL(snd_rawmidi_output_params);
int snd_rawmidi_input_params(struct snd_rawmidi_substream *substream, int snd_rawmidi_input_params(struct snd_rawmidi_substream *substream,
struct snd_rawmidi_params * params) struct snd_rawmidi_params * params)
{ {
char *newbuf; char *newbuf, *oldbuf;
struct snd_rawmidi_runtime *runtime = substream->runtime; struct snd_rawmidi_runtime *runtime = substream->runtime;
snd_rawmidi_drain_input(substream); snd_rawmidi_drain_input(substream);
...@@ -676,12 +680,16 @@ int snd_rawmidi_input_params(struct snd_rawmidi_substream *substream, ...@@ -676,12 +680,16 @@ int snd_rawmidi_input_params(struct snd_rawmidi_substream *substream,
return -EINVAL; return -EINVAL;
} }
if (params->buffer_size != runtime->buffer_size) { if (params->buffer_size != runtime->buffer_size) {
newbuf = krealloc(runtime->buffer, params->buffer_size, newbuf = kmalloc(params->buffer_size, GFP_KERNEL);
GFP_KERNEL);
if (!newbuf) if (!newbuf)
return -ENOMEM; return -ENOMEM;
spin_lock_irq(&runtime->lock);
oldbuf = runtime->buffer;
runtime->buffer = newbuf; runtime->buffer = newbuf;
runtime->buffer_size = params->buffer_size; runtime->buffer_size = params->buffer_size;
runtime->appl_ptr = runtime->hw_ptr = 0;
spin_unlock_irq(&runtime->lock);
kfree(oldbuf);
} }
runtime->avail_min = params->avail_min; runtime->avail_min = params->avail_min;
return 0; return 0;
......
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