| From c0317c0e87094f5b5782b6fdef5ae0a4b150496c Mon Sep 17 00:00:00 2001 |
| From: Wang Wensheng <wangwensheng4@huawei.com> |
| Date: Wed, 3 Nov 2021 03:35:17 +0000 |
| Subject: ALSA: timer: Fix use-after-free problem |
| |
| From: Wang Wensheng <wangwensheng4@huawei.com> |
| |
| 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> |
| --- |
| sound/core/timer.c | 4 ++-- |
| 1 file changed, 2 insertions(+), 2 deletions(-) |
| |
| --- a/sound/core/timer.c |
| +++ b/sound/core/timer.c |
| @@ -595,13 +595,13 @@ static int snd_timer_stop1(struct snd_ti |
| 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) { |