ALSA: virmidi: Fix too long output trigger loop
The virmidi output trigger tries to parse the all available bytes and process sequencer events as much as possible. In a normal situation, this is supposed to be relatively short, but a program may give a huge buffer and it'll take a long time in a single spin lock, which may eventually lead to a soft lockup. This patch simply adds a workaround, a cond_resched() call in the loop if applicable. A better solution would be to move the event processor into a work, but let's put a duct-tape quickly at first. Reported-and-tested-by: Dae R. Jeong <threeearcat@gmail.com> Reported-by: syzbot+619d9f40141d826b097e@syzkaller.appspotmail.com Cc: <stable@vger.kernel.org> Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
Родитель
69756930f2
Коммит
50e9ffb199
|
@ -163,6 +163,7 @@ static void snd_virmidi_output_trigger(struct snd_rawmidi_substream *substream,
|
|||
int count, res;
|
||||
unsigned char buf[32], *pbuf;
|
||||
unsigned long flags;
|
||||
bool check_resched = !in_atomic();
|
||||
|
||||
if (up) {
|
||||
vmidi->trigger = 1;
|
||||
|
@ -200,6 +201,15 @@ static void snd_virmidi_output_trigger(struct snd_rawmidi_substream *substream,
|
|||
vmidi->event.type = SNDRV_SEQ_EVENT_NONE;
|
||||
}
|
||||
}
|
||||
if (!check_resched)
|
||||
continue;
|
||||
/* do temporary unlock & cond_resched() for avoiding
|
||||
* CPU soft lockup, which may happen via a write from
|
||||
* a huge rawmidi buffer
|
||||
*/
|
||||
spin_unlock_irqrestore(&substream->runtime->lock, flags);
|
||||
cond_resched();
|
||||
spin_lock_irqsave(&substream->runtime->lock, flags);
|
||||
}
|
||||
out:
|
||||
spin_unlock_irqrestore(&substream->runtime->lock, flags);
|
||||
|
|
Загрузка…
Ссылка в новой задаче