| From 2a3f7221acddfe1caa9ff09b3a8158c39b2fdeac Mon Sep 17 00:00:00 2001 |
| From: Takashi Iwai <tiwai@suse.de> |
| Date: Tue, 16 Apr 2019 17:06:33 +0200 |
| Subject: ALSA: core: Fix card races between register and disconnect |
| |
| From: Takashi Iwai <tiwai@suse.de> |
| |
| commit 2a3f7221acddfe1caa9ff09b3a8158c39b2fdeac upstream. |
| |
| There is a small race window in the card disconnection code that |
| allows the registration of another card with the very same card id. |
| This leads to a warning in procfs creation as caught by syzkaller. |
| |
| The problem is that we delete snd_cards and snd_cards_lock entries at |
| the very beginning of the disconnection procedure. This makes the |
| slot available to be assigned for another card object while the |
| disconnection procedure is being processed. Then it becomes possible |
| to issue a procfs registration with the existing file name although we |
| check the conflict beforehand. |
| |
| The fix is simply to move the snd_cards and snd_cards_lock clearances |
| at the end of the disconnection procedure. The references to these |
| entries are merely either from the global proc files like |
| /proc/asound/cards or from the card registration / disconnection, so |
| it should be fine to shift at the very end. |
| |
| Reported-by: syzbot+48df349490c36f9f54ab@syzkaller.appspotmail.com |
| Cc: <stable@vger.kernel.org> |
| Signed-off-by: Takashi Iwai <tiwai@suse.de> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| sound/core/init.c | 18 +++++++++--------- |
| 1 file changed, 9 insertions(+), 9 deletions(-) |
| |
| --- a/sound/core/init.c |
| +++ b/sound/core/init.c |
| @@ -408,14 +408,7 @@ int snd_card_disconnect(struct snd_card |
| card->shutdown = 1; |
| spin_unlock(&card->files_lock); |
| |
| - /* phase 1: disable fops (user space) operations for ALSA API */ |
| - mutex_lock(&snd_card_mutex); |
| - snd_cards[card->number] = NULL; |
| - clear_bit(card->number, snd_cards_lock); |
| - mutex_unlock(&snd_card_mutex); |
| - |
| - /* phase 2: replace file->f_op with special dummy operations */ |
| - |
| + /* replace file->f_op with special dummy operations */ |
| spin_lock(&card->files_lock); |
| list_for_each_entry(mfile, &card->files_list, list) { |
| /* it's critical part, use endless loop */ |
| @@ -431,7 +424,7 @@ int snd_card_disconnect(struct snd_card |
| } |
| spin_unlock(&card->files_lock); |
| |
| - /* phase 3: notify all connected devices about disconnection */ |
| + /* notify all connected devices about disconnection */ |
| /* at this point, they cannot respond to any calls except release() */ |
| |
| #if IS_ENABLED(CONFIG_SND_MIXER_OSS) |
| @@ -447,6 +440,13 @@ int snd_card_disconnect(struct snd_card |
| device_del(&card->card_dev); |
| card->registered = false; |
| } |
| + |
| + /* disable fops (user space) operations for ALSA API */ |
| + mutex_lock(&snd_card_mutex); |
| + snd_cards[card->number] = NULL; |
| + clear_bit(card->number, snd_cards_lock); |
| + mutex_unlock(&snd_card_mutex); |
| + |
| #ifdef CONFIG_PM |
| wake_up(&card->power_sleep); |
| #endif |