Skip to content

Commit 1b6a6fc

Browse files
Amadeusz Sławińskitiwai
authored andcommitted
ALSA: jack: Access input_dev under mutex
It is possible when using ASoC that input_dev is unregistered while calling snd_jack_report, which causes NULL pointer dereference. In order to prevent this serialize access to input_dev using mutex lock. Signed-off-by: Amadeusz Sławiński <amadeuszx.slawinski@linux.intel.com> Reviewed-by: Cezary Rojewski <cezary.rojewski@intel.com> Link: https://lore.kernel.org/r/20220412091628.3056922-1-amadeuszx.slawinski@linux.intel.com Signed-off-by: Takashi Iwai <tiwai@suse.de>
1 parent 8f06bd1 commit 1b6a6fc

2 files changed

Lines changed: 28 additions & 7 deletions

File tree

include/sound/jack.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ struct snd_jack {
6262
const char *id;
6363
#ifdef CONFIG_SND_JACK_INPUT_DEV
6464
struct input_dev *input_dev;
65+
struct mutex input_dev_lock;
6566
int registered;
6667
int type;
6768
char name[100];

sound/core/jack.c

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,11 @@ static int snd_jack_dev_disconnect(struct snd_device *device)
4242
#ifdef CONFIG_SND_JACK_INPUT_DEV
4343
struct snd_jack *jack = device->device_data;
4444

45-
if (!jack->input_dev)
45+
mutex_lock(&jack->input_dev_lock);
46+
if (!jack->input_dev) {
47+
mutex_unlock(&jack->input_dev_lock);
4648
return 0;
49+
}
4750

4851
/* If the input device is registered with the input subsystem
4952
* then we need to use a different deallocator. */
@@ -52,6 +55,7 @@ static int snd_jack_dev_disconnect(struct snd_device *device)
5255
else
5356
input_free_device(jack->input_dev);
5457
jack->input_dev = NULL;
58+
mutex_unlock(&jack->input_dev_lock);
5559
#endif /* CONFIG_SND_JACK_INPUT_DEV */
5660
return 0;
5761
}
@@ -90,8 +94,11 @@ static int snd_jack_dev_register(struct snd_device *device)
9094
snprintf(jack->name, sizeof(jack->name), "%s %s",
9195
card->shortname, jack->id);
9296

93-
if (!jack->input_dev)
97+
mutex_lock(&jack->input_dev_lock);
98+
if (!jack->input_dev) {
99+
mutex_unlock(&jack->input_dev_lock);
94100
return 0;
101+
}
95102

96103
jack->input_dev->name = jack->name;
97104

@@ -116,6 +123,7 @@ static int snd_jack_dev_register(struct snd_device *device)
116123
if (err == 0)
117124
jack->registered = 1;
118125

126+
mutex_unlock(&jack->input_dev_lock);
119127
return err;
120128
}
121129
#endif /* CONFIG_SND_JACK_INPUT_DEV */
@@ -517,9 +525,11 @@ int snd_jack_new(struct snd_card *card, const char *id, int type,
517525
return -ENOMEM;
518526
}
519527

520-
/* don't creat input device for phantom jack */
521-
if (!phantom_jack) {
522528
#ifdef CONFIG_SND_JACK_INPUT_DEV
529+
mutex_init(&jack->input_dev_lock);
530+
531+
/* don't create input device for phantom jack */
532+
if (!phantom_jack) {
523533
int i;
524534

525535
jack->input_dev = input_allocate_device();
@@ -537,8 +547,8 @@ int snd_jack_new(struct snd_card *card, const char *id, int type,
537547
input_set_capability(jack->input_dev, EV_SW,
538548
jack_switch_types[i]);
539549

540-
#endif /* CONFIG_SND_JACK_INPUT_DEV */
541550
}
551+
#endif /* CONFIG_SND_JACK_INPUT_DEV */
542552

543553
err = snd_device_new(card, SNDRV_DEV_JACK, jack, &ops);
544554
if (err < 0)
@@ -578,10 +588,14 @@ EXPORT_SYMBOL(snd_jack_new);
578588
void snd_jack_set_parent(struct snd_jack *jack, struct device *parent)
579589
{
580590
WARN_ON(jack->registered);
581-
if (!jack->input_dev)
591+
mutex_lock(&jack->input_dev_lock);
592+
if (!jack->input_dev) {
593+
mutex_unlock(&jack->input_dev_lock);
582594
return;
595+
}
583596

584597
jack->input_dev->dev.parent = parent;
598+
mutex_unlock(&jack->input_dev_lock);
585599
}
586600
EXPORT_SYMBOL(snd_jack_set_parent);
587601

@@ -629,6 +643,8 @@ EXPORT_SYMBOL(snd_jack_set_key);
629643

630644
/**
631645
* snd_jack_report - Report the current status of a jack
646+
* Note: This function uses mutexes and should be called from a
647+
* context which can sleep (such as a workqueue).
632648
*
633649
* @jack: The jack to report status for
634650
* @status: The current status of the jack
@@ -654,8 +670,11 @@ void snd_jack_report(struct snd_jack *jack, int status)
654670
status & jack_kctl->mask_bits);
655671

656672
#ifdef CONFIG_SND_JACK_INPUT_DEV
657-
if (!jack->input_dev)
673+
mutex_lock(&jack->input_dev_lock);
674+
if (!jack->input_dev) {
675+
mutex_unlock(&jack->input_dev_lock);
658676
return;
677+
}
659678

660679
for (i = 0; i < ARRAY_SIZE(jack->key); i++) {
661680
int testbit = ((SND_JACK_BTN_0 >> i) & ~mask_bits);
@@ -675,6 +694,7 @@ void snd_jack_report(struct snd_jack *jack, int status)
675694
}
676695

677696
input_sync(jack->input_dev);
697+
mutex_unlock(&jack->input_dev_lock);
678698
#endif /* CONFIG_SND_JACK_INPUT_DEV */
679699
}
680700
EXPORT_SYMBOL(snd_jack_report);

0 commit comments

Comments
 (0)