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

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

ALSA: aloop: Add missing cable lock to ctl API callbacks



commit 76b3421b39bd610546931fc923edcf90c18fa395 upstream.

Some control API callbacks in aloop driver are too lazy to take the
loopback->cable_lock and it results in possible races of cable access
while it's being freed.  It eventually lead to a UAF, as reported by
fuzzer recently.

This patch covers such control API callbacks and add the proper mutex
locks.

Reported-by: default avatarDaeRyong Jeong <threeearcat@gmail.com>
Cc: <stable@vger.kernel.org>
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent a69e6088
Loading
Loading
Loading
Loading
+15 −2
Original line number Diff line number Diff line
@@ -833,9 +833,11 @@ static int loopback_rate_shift_get(struct snd_kcontrol *kcontrol,
{
	struct loopback *loopback = snd_kcontrol_chip(kcontrol);
	
	mutex_lock(&loopback->cable_lock);
	ucontrol->value.integer.value[0] =
		loopback->setup[kcontrol->id.subdevice]
			       [kcontrol->id.device].rate_shift;
	mutex_unlock(&loopback->cable_lock);
	return 0;
}

@@ -867,9 +869,11 @@ static int loopback_notify_get(struct snd_kcontrol *kcontrol,
{
	struct loopback *loopback = snd_kcontrol_chip(kcontrol);
	
	mutex_lock(&loopback->cable_lock);
	ucontrol->value.integer.value[0] =
		loopback->setup[kcontrol->id.subdevice]
			       [kcontrol->id.device].notify;
	mutex_unlock(&loopback->cable_lock);
	return 0;
}

@@ -881,12 +885,14 @@ static int loopback_notify_put(struct snd_kcontrol *kcontrol,
	int change = 0;

	val = ucontrol->value.integer.value[0] ? 1 : 0;
	mutex_lock(&loopback->cable_lock);
	if (val != loopback->setup[kcontrol->id.subdevice]
				[kcontrol->id.device].notify) {
		loopback->setup[kcontrol->id.subdevice]
			[kcontrol->id.device].notify = val;
		change = 1;
	}
	mutex_unlock(&loopback->cable_lock);
	return change;
}

@@ -894,15 +900,18 @@ static int loopback_active_get(struct snd_kcontrol *kcontrol,
			       struct snd_ctl_elem_value *ucontrol)
{
	struct loopback *loopback = snd_kcontrol_chip(kcontrol);
	struct loopback_cable *cable = loopback->cables
			[kcontrol->id.subdevice][kcontrol->id.device ^ 1];
	struct loopback_cable *cable;

	unsigned int val = 0;

	mutex_lock(&loopback->cable_lock);
	cable = loopback->cables[kcontrol->id.subdevice][kcontrol->id.device ^ 1];
	if (cable != NULL) {
		unsigned int running = cable->running ^ cable->pause;

		val = (running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) ? 1 : 0;
	}
	mutex_unlock(&loopback->cable_lock);
	ucontrol->value.integer.value[0] = val;
	return 0;
}
@@ -945,9 +954,11 @@ static int loopback_rate_get(struct snd_kcontrol *kcontrol,
{
	struct loopback *loopback = snd_kcontrol_chip(kcontrol);
	
	mutex_lock(&loopback->cable_lock);
	ucontrol->value.integer.value[0] =
		loopback->setup[kcontrol->id.subdevice]
			       [kcontrol->id.device].rate;
	mutex_unlock(&loopback->cable_lock);
	return 0;
}

@@ -967,9 +978,11 @@ static int loopback_channels_get(struct snd_kcontrol *kcontrol,
{
	struct loopback *loopback = snd_kcontrol_chip(kcontrol);
	
	mutex_lock(&loopback->cable_lock);
	ucontrol->value.integer.value[0] =
		loopback->setup[kcontrol->id.subdevice]
			       [kcontrol->id.device].channels;
	mutex_unlock(&loopback->cable_lock);
	return 0;
}