| From 1c2b9519159b470ef24b2638f4794e86e2952ab7 Mon Sep 17 00:00:00 2001 |
| From: Takashi Iwai <tiwai@suse.de> |
| Date: Fri, 16 Jul 2021 15:27:23 +0200 |
| Subject: ALSA: sb: Fix potential ABBA deadlock in CSP driver |
| |
| From: Takashi Iwai <tiwai@suse.de> |
| |
| commit 1c2b9519159b470ef24b2638f4794e86e2952ab7 upstream. |
| |
| SB16 CSP driver may hit potentially a typical ABBA deadlock in two |
| code paths: |
| |
| In snd_sb_csp_stop(): |
| spin_lock_irqsave(&p->chip->mixer_lock, flags); |
| spin_lock(&p->chip->reg_lock); |
| |
| In snd_sb_csp_load(): |
| spin_lock_irqsave(&p->chip->reg_lock, flags); |
| spin_lock(&p->chip->mixer_lock); |
| |
| Also the similar pattern is seen in snd_sb_csp_start(). |
| |
| Although the practical impact is very small (those states aren't |
| triggered in the same running state and this happens only on a real |
| hardware, decades old ISA sound boards -- which must be very difficult |
| to find nowadays), it's a real scenario and has to be fixed. |
| |
| This patch addresses those deadlocks by splitting the locks in |
| snd_sb_csp_start() and snd_sb_csp_stop() for avoiding the nested |
| locks. |
| |
| Reported-by: Jia-Ju Bai <baijiaju1990@gmail.com> |
| Cc: <stable@vger.kernel.org> |
| Link: https://lore.kernel.org/r/7b0fcdaf-cd4f-4728-2eae-48c151a92e10@gmail.com |
| Link: https://lore.kernel.org/r/20210716132723.13216-1-tiwai@suse.de |
| Signed-off-by: Takashi Iwai <tiwai@suse.de> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| sound/isa/sb/sb16_csp.c | 4 ++++ |
| 1 file changed, 4 insertions(+) |
| |
| --- a/sound/isa/sb/sb16_csp.c |
| +++ b/sound/isa/sb/sb16_csp.c |
| @@ -814,6 +814,7 @@ static int snd_sb_csp_start(struct snd_s |
| mixR = snd_sbmixer_read(p->chip, SB_DSP4_PCM_DEV + 1); |
| snd_sbmixer_write(p->chip, SB_DSP4_PCM_DEV, mixL & 0x7); |
| snd_sbmixer_write(p->chip, SB_DSP4_PCM_DEV + 1, mixR & 0x7); |
| + spin_unlock_irqrestore(&p->chip->mixer_lock, flags); |
| |
| spin_lock(&p->chip->reg_lock); |
| set_mode_register(p->chip, 0xc0); /* c0 = STOP */ |
| @@ -853,6 +854,7 @@ static int snd_sb_csp_start(struct snd_s |
| spin_unlock(&p->chip->reg_lock); |
| |
| /* restore PCM volume */ |
| + spin_lock_irqsave(&p->chip->mixer_lock, flags); |
| snd_sbmixer_write(p->chip, SB_DSP4_PCM_DEV, mixL); |
| snd_sbmixer_write(p->chip, SB_DSP4_PCM_DEV + 1, mixR); |
| spin_unlock_irqrestore(&p->chip->mixer_lock, flags); |
| @@ -878,6 +880,7 @@ static int snd_sb_csp_stop(struct snd_sb |
| mixR = snd_sbmixer_read(p->chip, SB_DSP4_PCM_DEV + 1); |
| snd_sbmixer_write(p->chip, SB_DSP4_PCM_DEV, mixL & 0x7); |
| snd_sbmixer_write(p->chip, SB_DSP4_PCM_DEV + 1, mixR & 0x7); |
| + spin_unlock_irqrestore(&p->chip->mixer_lock, flags); |
| |
| spin_lock(&p->chip->reg_lock); |
| if (p->running & SNDRV_SB_CSP_ST_QSOUND) { |
| @@ -892,6 +895,7 @@ static int snd_sb_csp_stop(struct snd_sb |
| spin_unlock(&p->chip->reg_lock); |
| |
| /* restore PCM volume */ |
| + spin_lock_irqsave(&p->chip->mixer_lock, flags); |
| snd_sbmixer_write(p->chip, SB_DSP4_PCM_DEV, mixL); |
| snd_sbmixer_write(p->chip, SB_DSP4_PCM_DEV + 1, mixR); |
| spin_unlock_irqrestore(&p->chip->mixer_lock, flags); |