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

Commit f68bed12 authored by Amadeusz Sławiński's avatar Amadeusz Sławiński Committed by Greg Kroah-Hartman
Browse files

ALSA: jack: Access input_dev under mutex



[ Upstream commit 1b6a6fc5280e97559287b61eade2d4b363e836f2 ]

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: default avatarAmadeusz Sławiński <amadeuszx.slawinski@linux.intel.com>
Reviewed-by: default avatarCezary Rojewski <cezary.rojewski@intel.com>
Link: https://lore.kernel.org/r/20220412091628.3056922-1-amadeuszx.slawinski@linux.intel.com


Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent aea74850
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -62,6 +62,7 @@ struct snd_jack {
	const char *id;
#ifdef CONFIG_SND_JACK_INPUT_DEV
	struct input_dev *input_dev;
	struct mutex input_dev_lock;
	int registered;
	int type;
	char name[100];
+27 −7
Original line number Diff line number Diff line
@@ -34,8 +34,11 @@ static int snd_jack_dev_disconnect(struct snd_device *device)
#ifdef CONFIG_SND_JACK_INPUT_DEV
	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;
	}

	/* If the input device is registered with the input subsystem
	 * then we need to use a different deallocator. */
@@ -44,6 +47,7 @@ static int snd_jack_dev_disconnect(struct snd_device *device)
	else
		input_free_device(jack->input_dev);
	jack->input_dev = NULL;
	mutex_unlock(&jack->input_dev_lock);
#endif /* CONFIG_SND_JACK_INPUT_DEV */
	return 0;
}
@@ -82,8 +86,11 @@ static int snd_jack_dev_register(struct snd_device *device)
	snprintf(jack->name, sizeof(jack->name), "%s %s",
		 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;
	}

	jack->input_dev->name = jack->name;

@@ -108,6 +115,7 @@ static int snd_jack_dev_register(struct snd_device *device)
	if (err == 0)
		jack->registered = 1;

	mutex_unlock(&jack->input_dev_lock);
	return err;
}
#endif /* CONFIG_SND_JACK_INPUT_DEV */
@@ -228,9 +236,11 @@ int snd_jack_new(struct snd_card *card, const char *id, int type,
		return -ENOMEM;
	}

	/* don't creat input device for phantom jack */
	if (!phantom_jack) {
#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;

		jack->input_dev = input_allocate_device();
@@ -248,8 +258,8 @@ int snd_jack_new(struct snd_card *card, const char *id, int type,
				input_set_capability(jack->input_dev, EV_SW,
						     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);
	if (err < 0)
@@ -289,10 +299,14 @@ EXPORT_SYMBOL(snd_jack_new);
void snd_jack_set_parent(struct snd_jack *jack, struct device *parent)
{
	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;
	}

	jack->input_dev->dev.parent = parent;
	mutex_unlock(&jack->input_dev_lock);
}
EXPORT_SYMBOL(snd_jack_set_parent);

@@ -340,6 +354,8 @@ EXPORT_SYMBOL(snd_jack_set_key);

/**
 * 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
 * @status: The current status of the jack
@@ -359,8 +375,11 @@ void snd_jack_report(struct snd_jack *jack, int status)
					    status & jack_kctl->mask_bits);

#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;
	}

	for (i = 0; i < ARRAY_SIZE(jack->key); i++) {
		int testbit = SND_JACK_BTN_0 >> i;
@@ -379,6 +398,7 @@ void snd_jack_report(struct snd_jack *jack, int status)
	}

	input_sync(jack->input_dev);
	mutex_unlock(&jack->input_dev_lock);
#endif /* CONFIG_SND_JACK_INPUT_DEV */
}
EXPORT_SYMBOL(snd_jack_report);