ALSA: seq: Fix data-race at module auto-loading
authorTakashi Iwai <tiwai@suse.de>
Tue, 23 Aug 2022 07:27:17 +0000 (09:27 +0200)
committerTakashi Iwai <tiwai@suse.de>
Wed, 24 Aug 2022 05:59:06 +0000 (07:59 +0200)
It's been reported that there is a possible data-race accessing to the
global card_requested[] array at ALSA sequencer core, which is used
for determining whether to call request_module() for the card or not.
This data race itself is almost harmless, as it might end up with one
extra request_module() call for the already loaded module at most.
But it's still better to fix.

This patch addresses the possible data race of card_requested[] and
client_requested[] arrays by replacing them with bitmask.
It's an atomic operation and can work without locks.

Reported-by: Abhishek Shah <abhishek.shah@columbia.edu>
Cc: <stable@vger.kernel.org>
Link: https://lore.kernel.org/r/CAEHB24_ay6YzARpA1zgCsE7=H9CSJJzux618E=Ka4h0YdKn=qA@mail.gmail.com
Link: https://lore.kernel.org/r/20220823072717.1706-2-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
sound/core/seq/seq_clientmgr.c

index 2e9d695d336c9faac010c6bfdddc08445a96a8aa..2d707afa1ef1cd3a0e367df865f142f10f344387 100644 (file)
@@ -121,13 +121,13 @@ struct snd_seq_client *snd_seq_client_use_ptr(int clientid)
        spin_unlock_irqrestore(&clients_lock, flags);
 #ifdef CONFIG_MODULES
        if (!in_interrupt()) {
-               static char client_requested[SNDRV_SEQ_GLOBAL_CLIENTS];
-               static char card_requested[SNDRV_CARDS];
+               static DECLARE_BITMAP(client_requested, SNDRV_SEQ_GLOBAL_CLIENTS);
+               static DECLARE_BITMAP(card_requested, SNDRV_CARDS);
+
                if (clientid < SNDRV_SEQ_GLOBAL_CLIENTS) {
                        int idx;
                        
-                       if (!client_requested[clientid]) {
-                               client_requested[clientid] = 1;
+                       if (!test_and_set_bit(clientid, client_requested)) {
                                for (idx = 0; idx < 15; idx++) {
                                        if (seq_client_load[idx] < 0)
                                                break;
@@ -142,10 +142,8 @@ struct snd_seq_client *snd_seq_client_use_ptr(int clientid)
                        int card = (clientid - SNDRV_SEQ_GLOBAL_CLIENTS) /
                                SNDRV_SEQ_CLIENTS_PER_CARD;
                        if (card < snd_ecards_limit) {
-                               if (! card_requested[card]) {
-                                       card_requested[card] = 1;
+                               if (!test_and_set_bit(card, card_requested))
                                        snd_request_card(card);
-                               }
                                snd_seq_device_load_drivers();
                        }
                }