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: Takashi Iwai <tiwai@suse.de>hifive-unleashed-5.1
parent
0fca97a29b
commit
39675f7a7c
|
@ -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,
|
||||||
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);
|
||||||
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,
|
||||||
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;
|
||||||
|
|
Loading…
Reference in New Issue