summaryrefslogtreecommitdiff
path: root/sound/core
diff options
context:
space:
mode:
authorWang Wensheng <wangwensheng4@huawei.com>2021-11-03 06:35:17 +0300
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2021-11-18 16:03:40 +0300
commitb980ce4ebb8b8d79b71b63f374607fa434a1d9dd (patch)
treea10205531162470476464106f28a319ab29add85 /sound/core
parent7c6fd525044c20082233f15312f62a9aee18ec38 (diff)
downloadlinux-b980ce4ebb8b8d79b71b63f374607fa434a1d9dd.tar.xz
ALSA: timer: Fix use-after-free problem
commit c0317c0e87094f5b5782b6fdef5ae0a4b150496c upstream. When the timer instance was add into ack_list but was not currently in process, the user could stop it via snd_timer_stop1() without delete it from the ack_list. Then the user could free the timer instance and when it was actually processed UAF occurred. This issue could be reproduced via testcase snd_timer01 in ltp - running several instances of that testcase at the same time. What I actually met was that the ack_list of the timer broken and the kernel went into deadloop with irqoff. That could be detected by hardlockup detector on board or when we run it on qemu, we could use gdb to dump the ack_list when the console has no response. To fix this issue, we delete the timer instance from ack_list and active_list unconditionally in snd_timer_stop1(). Signed-off-by: Wang Wensheng <wangwensheng4@huawei.com> Suggested-by: Takashi Iwai <tiwai@suse.de> Cc: <stable@vger.kernel.org> Link: https://lore.kernel.org/r/20211103033517.80531-1-wangwensheng4@huawei.com Signed-off-by: Takashi Iwai <tiwai@suse.de> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'sound/core')
-rw-r--r--sound/core/timer.c4
1 files changed, 2 insertions, 2 deletions
diff --git a/sound/core/timer.c b/sound/core/timer.c
index c15c8314671b..963ddd9e7715 100644
--- a/sound/core/timer.c
+++ b/sound/core/timer.c
@@ -624,13 +624,13 @@ static int snd_timer_stop1(struct snd_timer_instance *timeri, bool stop)
if (!timer)
return -EINVAL;
spin_lock_irqsave(&timer->lock, flags);
+ list_del_init(&timeri->ack_list);
+ list_del_init(&timeri->active_list);
if (!(timeri->flags & (SNDRV_TIMER_IFLG_RUNNING |
SNDRV_TIMER_IFLG_START))) {
result = -EBUSY;
goto unlock;
}
- list_del_init(&timeri->ack_list);
- list_del_init(&timeri->active_list);
if (timer->card && timer->card->shutdown)
goto unlock;
if (stop) {