]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
ALSA: aloop: Add missing cable lock to ctl API callbacks
authorTakashi Iwai <tiwai@suse.de>
Mon, 30 Apr 2018 08:06:48 +0000 (10:06 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 16 May 2018 08:05:15 +0000 (10:05 +0200)
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

index 23a2ac84eb51cef49cac6d52b72010aa8777c85c..835f3093a48d3d5c56f9e97da15b1a077a6d4533 100644 (file)
@@ -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;
 }