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>
This commit is contained in:
parent
8f06bd1f89
commit
1b6a6fc528
|
@ -62,6 +62,7 @@ struct snd_jack {
|
||||||
const char *id;
|
const char *id;
|
||||||
#ifdef CONFIG_SND_JACK_INPUT_DEV
|
#ifdef CONFIG_SND_JACK_INPUT_DEV
|
||||||
struct input_dev *input_dev;
|
struct input_dev *input_dev;
|
||||||
|
struct mutex input_dev_lock;
|
||||||
int registered;
|
int registered;
|
||||||
int type;
|
int type;
|
||||||
char name[100];
|
char name[100];
|
||||||
|
|
|
@ -42,8 +42,11 @@ static int snd_jack_dev_disconnect(struct snd_device *device)
|
||||||
#ifdef CONFIG_SND_JACK_INPUT_DEV
|
#ifdef CONFIG_SND_JACK_INPUT_DEV
|
||||||
struct snd_jack *jack = device->device_data;
|
struct snd_jack *jack = device->device_data;
|
||||||
|
|
||||||
if (!jack->input_dev)
|
mutex_lock(&jack->input_dev_lock);
|
||||||
|
if (!jack->input_dev) {
|
||||||
|
mutex_unlock(&jack->input_dev_lock);
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* If the input device is registered with the input subsystem
|
/* If the input device is registered with the input subsystem
|
||||||
* then we need to use a different deallocator. */
|
* then we need to use a different deallocator. */
|
||||||
|
@ -52,6 +55,7 @@ static int snd_jack_dev_disconnect(struct snd_device *device)
|
||||||
else
|
else
|
||||||
input_free_device(jack->input_dev);
|
input_free_device(jack->input_dev);
|
||||||
jack->input_dev = NULL;
|
jack->input_dev = NULL;
|
||||||
|
mutex_unlock(&jack->input_dev_lock);
|
||||||
#endif /* CONFIG_SND_JACK_INPUT_DEV */
|
#endif /* CONFIG_SND_JACK_INPUT_DEV */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -90,8 +94,11 @@ static int snd_jack_dev_register(struct snd_device *device)
|
||||||
snprintf(jack->name, sizeof(jack->name), "%s %s",
|
snprintf(jack->name, sizeof(jack->name), "%s %s",
|
||||||
card->shortname, jack->id);
|
card->shortname, jack->id);
|
||||||
|
|
||||||
if (!jack->input_dev)
|
mutex_lock(&jack->input_dev_lock);
|
||||||
|
if (!jack->input_dev) {
|
||||||
|
mutex_unlock(&jack->input_dev_lock);
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
jack->input_dev->name = jack->name;
|
jack->input_dev->name = jack->name;
|
||||||
|
|
||||||
|
@ -116,6 +123,7 @@ static int snd_jack_dev_register(struct snd_device *device)
|
||||||
if (err == 0)
|
if (err == 0)
|
||||||
jack->registered = 1;
|
jack->registered = 1;
|
||||||
|
|
||||||
|
mutex_unlock(&jack->input_dev_lock);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_SND_JACK_INPUT_DEV */
|
#endif /* CONFIG_SND_JACK_INPUT_DEV */
|
||||||
|
@ -517,9 +525,11 @@ int snd_jack_new(struct snd_card *card, const char *id, int type,
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* don't creat input device for phantom jack */
|
|
||||||
if (!phantom_jack) {
|
|
||||||
#ifdef CONFIG_SND_JACK_INPUT_DEV
|
#ifdef CONFIG_SND_JACK_INPUT_DEV
|
||||||
|
mutex_init(&jack->input_dev_lock);
|
||||||
|
|
||||||
|
/* don't create input device for phantom jack */
|
||||||
|
if (!phantom_jack) {
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
jack->input_dev = input_allocate_device();
|
jack->input_dev = input_allocate_device();
|
||||||
|
@ -537,8 +547,8 @@ int snd_jack_new(struct snd_card *card, const char *id, int type,
|
||||||
input_set_capability(jack->input_dev, EV_SW,
|
input_set_capability(jack->input_dev, EV_SW,
|
||||||
jack_switch_types[i]);
|
jack_switch_types[i]);
|
||||||
|
|
||||||
#endif /* CONFIG_SND_JACK_INPUT_DEV */
|
|
||||||
}
|
}
|
||||||
|
#endif /* CONFIG_SND_JACK_INPUT_DEV */
|
||||||
|
|
||||||
err = snd_device_new(card, SNDRV_DEV_JACK, jack, &ops);
|
err = snd_device_new(card, SNDRV_DEV_JACK, jack, &ops);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
|
@ -578,10 +588,14 @@ EXPORT_SYMBOL(snd_jack_new);
|
||||||
void snd_jack_set_parent(struct snd_jack *jack, struct device *parent)
|
void snd_jack_set_parent(struct snd_jack *jack, struct device *parent)
|
||||||
{
|
{
|
||||||
WARN_ON(jack->registered);
|
WARN_ON(jack->registered);
|
||||||
if (!jack->input_dev)
|
mutex_lock(&jack->input_dev_lock);
|
||||||
|
if (!jack->input_dev) {
|
||||||
|
mutex_unlock(&jack->input_dev_lock);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
jack->input_dev->dev.parent = parent;
|
jack->input_dev->dev.parent = parent;
|
||||||
|
mutex_unlock(&jack->input_dev_lock);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(snd_jack_set_parent);
|
EXPORT_SYMBOL(snd_jack_set_parent);
|
||||||
|
|
||||||
|
@ -629,6 +643,8 @@ EXPORT_SYMBOL(snd_jack_set_key);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* snd_jack_report - Report the current status of a jack
|
* snd_jack_report - Report the current status of a jack
|
||||||
|
* Note: This function uses mutexes and should be called from a
|
||||||
|
* context which can sleep (such as a workqueue).
|
||||||
*
|
*
|
||||||
* @jack: The jack to report status for
|
* @jack: The jack to report status for
|
||||||
* @status: The current status of the jack
|
* @status: The current status of the jack
|
||||||
|
@ -654,8 +670,11 @@ void snd_jack_report(struct snd_jack *jack, int status)
|
||||||
status & jack_kctl->mask_bits);
|
status & jack_kctl->mask_bits);
|
||||||
|
|
||||||
#ifdef CONFIG_SND_JACK_INPUT_DEV
|
#ifdef CONFIG_SND_JACK_INPUT_DEV
|
||||||
if (!jack->input_dev)
|
mutex_lock(&jack->input_dev_lock);
|
||||||
|
if (!jack->input_dev) {
|
||||||
|
mutex_unlock(&jack->input_dev_lock);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(jack->key); i++) {
|
for (i = 0; i < ARRAY_SIZE(jack->key); i++) {
|
||||||
int testbit = ((SND_JACK_BTN_0 >> i) & ~mask_bits);
|
int testbit = ((SND_JACK_BTN_0 >> i) & ~mask_bits);
|
||||||
|
@ -675,6 +694,7 @@ void snd_jack_report(struct snd_jack *jack, int status)
|
||||||
}
|
}
|
||||||
|
|
||||||
input_sync(jack->input_dev);
|
input_sync(jack->input_dev);
|
||||||
|
mutex_unlock(&jack->input_dev_lock);
|
||||||
#endif /* CONFIG_SND_JACK_INPUT_DEV */
|
#endif /* CONFIG_SND_JACK_INPUT_DEV */
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(snd_jack_report);
|
EXPORT_SYMBOL(snd_jack_report);
|
||||||
|
|
Loading…
Reference in New Issue