| From 76b3421b39bd610546931fc923edcf90c18fa395 Mon Sep 17 00:00:00 2001 |
| From: Takashi Iwai <tiwai@suse.de> |
| Date: Mon, 30 Apr 2018 10:06:48 +0200 |
| Subject: ALSA: aloop: Add missing cable lock to ctl API callbacks |
| |
| From: Takashi Iwai <tiwai@suse.de> |
| |
| 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: DaeRyong Jeong <threeearcat@gmail.com> |
| Cc: <stable@vger.kernel.org> |
| Signed-off-by: Takashi Iwai <tiwai@suse.de> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| sound/drivers/aloop.c | 17 +++++++++++++++-- |
| 1 file changed, 15 insertions(+), 2 deletions(-) |
| |
| --- a/sound/drivers/aloop.c |
| +++ b/sound/drivers/aloop.c |
| @@ -832,9 +832,11 @@ static int loopback_rate_shift_get(struc |
| { |
| 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; |
| } |
| |
| @@ -866,9 +868,11 @@ static int loopback_notify_get(struct sn |
| { |
| 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; |
| } |
| |
| @@ -880,12 +884,14 @@ static int loopback_notify_put(struct sn |
| 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; |
| } |
| |
| @@ -893,15 +899,18 @@ static int loopback_active_get(struct sn |
| 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; |
| } |
| @@ -944,9 +953,11 @@ static int loopback_rate_get(struct snd_ |
| { |
| 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; |
| } |
| |
| @@ -966,9 +977,11 @@ static int loopback_channels_get(struct |
| { |
| 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; |
| } |
| |