Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3af1316d authored by Takashi Iwai's avatar Takashi Iwai Committed by Greg Kroah-Hartman
Browse files

ALSA: seq: Fix data-race at module auto-loading



commit 3e7e04b747adea36f349715d9f0998eeebf15d72 upstream.

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: default avatarAbhishek 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: default avatarTakashi Iwai <tiwai@suse.de>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 4fa63d52
Loading
Loading
Loading
Loading
+5 −7
Original line number Original line Diff line number Diff line
@@ -121,13 +121,13 @@ struct snd_seq_client *snd_seq_client_use_ptr(int clientid)
	spin_unlock_irqrestore(&clients_lock, flags);
	spin_unlock_irqrestore(&clients_lock, flags);
#ifdef CONFIG_MODULES
#ifdef CONFIG_MODULES
	if (!in_interrupt()) {
	if (!in_interrupt()) {
		static char client_requested[SNDRV_SEQ_GLOBAL_CLIENTS];
		static DECLARE_BITMAP(client_requested, SNDRV_SEQ_GLOBAL_CLIENTS);
		static char card_requested[SNDRV_CARDS];
		static DECLARE_BITMAP(card_requested, SNDRV_CARDS);

		if (clientid < SNDRV_SEQ_GLOBAL_CLIENTS) {
		if (clientid < SNDRV_SEQ_GLOBAL_CLIENTS) {
			int idx;
			int idx;
			
			
			if (!client_requested[clientid]) {
			if (!test_and_set_bit(clientid, client_requested)) {
				client_requested[clientid] = 1;
				for (idx = 0; idx < 15; idx++) {
				for (idx = 0; idx < 15; idx++) {
					if (seq_client_load[idx] < 0)
					if (seq_client_load[idx] < 0)
						break;
						break;
@@ -142,10 +142,8 @@ struct snd_seq_client *snd_seq_client_use_ptr(int clientid)
			int card = (clientid - SNDRV_SEQ_GLOBAL_CLIENTS) /
			int card = (clientid - SNDRV_SEQ_GLOBAL_CLIENTS) /
				SNDRV_SEQ_CLIENTS_PER_CARD;
				SNDRV_SEQ_CLIENTS_PER_CARD;
			if (card < snd_ecards_limit) {
			if (card < snd_ecards_limit) {
				if (! card_requested[card]) {
				if (!test_and_set_bit(card, card_requested))
					card_requested[card] = 1;
					snd_request_card(card);
					snd_request_card(card);
				}
				snd_seq_device_load_drivers();
				snd_seq_device_load_drivers();
			}
			}
		}
		}