diff options
author | Takashi Iwai <tiwai@suse.de> | 2018-04-30 04:06:48 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2018-04-30 04:06:48 -0400 |
commit | 76b3421b39bd610546931fc923edcf90c18fa395 (patch) | |
tree | f27e1ca71c7053ccd68c6ec44163410a6b8ed6a9 /sound | |
parent | 52759c0963510a2843774aac9b65ccaed3308dc0 (diff) |
ALSA: aloop: Add missing cable lock to ctl API callbacks
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>
Diffstat (limited to 'sound')
-rw-r--r-- | sound/drivers/aloop.c | 17 |
1 files changed, 15 insertions, 2 deletions
diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c index 58e349fc893f..eab7f594ebe7 100644 --- a/sound/drivers/aloop.c +++ b/sound/drivers/aloop.c | |||
@@ -831,9 +831,11 @@ static int loopback_rate_shift_get(struct snd_kcontrol *kcontrol, | |||
831 | { | 831 | { |
832 | struct loopback *loopback = snd_kcontrol_chip(kcontrol); | 832 | struct loopback *loopback = snd_kcontrol_chip(kcontrol); |
833 | 833 | ||
834 | mutex_lock(&loopback->cable_lock); | ||
834 | ucontrol->value.integer.value[0] = | 835 | ucontrol->value.integer.value[0] = |
835 | loopback->setup[kcontrol->id.subdevice] | 836 | loopback->setup[kcontrol->id.subdevice] |
836 | [kcontrol->id.device].rate_shift; | 837 | [kcontrol->id.device].rate_shift; |
838 | mutex_unlock(&loopback->cable_lock); | ||
837 | return 0; | 839 | return 0; |
838 | } | 840 | } |
839 | 841 | ||
@@ -865,9 +867,11 @@ static int loopback_notify_get(struct snd_kcontrol *kcontrol, | |||
865 | { | 867 | { |
866 | struct loopback *loopback = snd_kcontrol_chip(kcontrol); | 868 | struct loopback *loopback = snd_kcontrol_chip(kcontrol); |
867 | 869 | ||
870 | mutex_lock(&loopback->cable_lock); | ||
868 | ucontrol->value.integer.value[0] = | 871 | ucontrol->value.integer.value[0] = |
869 | loopback->setup[kcontrol->id.subdevice] | 872 | loopback->setup[kcontrol->id.subdevice] |
870 | [kcontrol->id.device].notify; | 873 | [kcontrol->id.device].notify; |
874 | mutex_unlock(&loopback->cable_lock); | ||
871 | return 0; | 875 | return 0; |
872 | } | 876 | } |
873 | 877 | ||
@@ -879,12 +883,14 @@ static int loopback_notify_put(struct snd_kcontrol *kcontrol, | |||
879 | int change = 0; | 883 | int change = 0; |
880 | 884 | ||
881 | val = ucontrol->value.integer.value[0] ? 1 : 0; | 885 | val = ucontrol->value.integer.value[0] ? 1 : 0; |
886 | mutex_lock(&loopback->cable_lock); | ||
882 | if (val != loopback->setup[kcontrol->id.subdevice] | 887 | if (val != loopback->setup[kcontrol->id.subdevice] |
883 | [kcontrol->id.device].notify) { | 888 | [kcontrol->id.device].notify) { |
884 | loopback->setup[kcontrol->id.subdevice] | 889 | loopback->setup[kcontrol->id.subdevice] |
885 | [kcontrol->id.device].notify = val; | 890 | [kcontrol->id.device].notify = val; |
886 | change = 1; | 891 | change = 1; |
887 | } | 892 | } |
893 | mutex_unlock(&loopback->cable_lock); | ||
888 | return change; | 894 | return change; |
889 | } | 895 | } |
890 | 896 | ||
@@ -892,15 +898,18 @@ static int loopback_active_get(struct snd_kcontrol *kcontrol, | |||
892 | struct snd_ctl_elem_value *ucontrol) | 898 | struct snd_ctl_elem_value *ucontrol) |
893 | { | 899 | { |
894 | struct loopback *loopback = snd_kcontrol_chip(kcontrol); | 900 | struct loopback *loopback = snd_kcontrol_chip(kcontrol); |
895 | struct loopback_cable *cable = loopback->cables | 901 | struct loopback_cable *cable; |
896 | [kcontrol->id.subdevice][kcontrol->id.device ^ 1]; | 902 | |
897 | unsigned int val = 0; | 903 | unsigned int val = 0; |
898 | 904 | ||
905 | mutex_lock(&loopback->cable_lock); | ||
906 | cable = loopback->cables[kcontrol->id.subdevice][kcontrol->id.device ^ 1]; | ||
899 | if (cable != NULL) { | 907 | if (cable != NULL) { |
900 | unsigned int running = cable->running ^ cable->pause; | 908 | unsigned int running = cable->running ^ cable->pause; |
901 | 909 | ||
902 | val = (running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) ? 1 : 0; | 910 | val = (running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) ? 1 : 0; |
903 | } | 911 | } |
912 | mutex_unlock(&loopback->cable_lock); | ||
904 | ucontrol->value.integer.value[0] = val; | 913 | ucontrol->value.integer.value[0] = val; |
905 | return 0; | 914 | return 0; |
906 | } | 915 | } |
@@ -943,9 +952,11 @@ static int loopback_rate_get(struct snd_kcontrol *kcontrol, | |||
943 | { | 952 | { |
944 | struct loopback *loopback = snd_kcontrol_chip(kcontrol); | 953 | struct loopback *loopback = snd_kcontrol_chip(kcontrol); |
945 | 954 | ||
955 | mutex_lock(&loopback->cable_lock); | ||
946 | ucontrol->value.integer.value[0] = | 956 | ucontrol->value.integer.value[0] = |
947 | loopback->setup[kcontrol->id.subdevice] | 957 | loopback->setup[kcontrol->id.subdevice] |
948 | [kcontrol->id.device].rate; | 958 | [kcontrol->id.device].rate; |
959 | mutex_unlock(&loopback->cable_lock); | ||
949 | return 0; | 960 | return 0; |
950 | } | 961 | } |
951 | 962 | ||
@@ -965,9 +976,11 @@ static int loopback_channels_get(struct snd_kcontrol *kcontrol, | |||
965 | { | 976 | { |
966 | struct loopback *loopback = snd_kcontrol_chip(kcontrol); | 977 | struct loopback *loopback = snd_kcontrol_chip(kcontrol); |
967 | 978 | ||
979 | mutex_lock(&loopback->cable_lock); | ||
968 | ucontrol->value.integer.value[0] = | 980 | ucontrol->value.integer.value[0] = |
969 | loopback->setup[kcontrol->id.subdevice] | 981 | loopback->setup[kcontrol->id.subdevice] |
970 | [kcontrol->id.device].channels; | 982 | [kcontrol->id.device].channels; |
983 | mutex_unlock(&loopback->cable_lock); | ||
971 | return 0; | 984 | return 0; |
972 | } | 985 | } |
973 | 986 | ||