| From: Takashi Iwai <tiwai@suse.de> |
| Date: Fri, 2 Jun 2017 17:26:56 +0200 |
| Subject: ALSA: timer: Fix missing queue indices reset at |
| SNDRV_TIMER_IOCTL_SELECT |
| |
| commit ba3021b2c79b2fa9114f92790a99deb27a65b728 upstream. |
| |
| snd_timer_user_tselect() reallocates the queue buffer dynamically, but |
| it forgot to reset its indices. Since the read may happen |
| concurrently with ioctl and snd_timer_user_tselect() allocates the |
| buffer via kmalloc(), this may lead to the leak of uninitialized |
| kernel-space data, as spotted via KMSAN: |
| |
| BUG: KMSAN: use of unitialized memory in snd_timer_user_read+0x6c4/0xa10 |
| CPU: 0 PID: 1037 Comm: probe Not tainted 4.11.0-rc5+ #2739 |
| Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Bochs 01/01/2011 |
| Call Trace: |
| __dump_stack lib/dump_stack.c:16 |
| dump_stack+0x143/0x1b0 lib/dump_stack.c:52 |
| kmsan_report+0x12a/0x180 mm/kmsan/kmsan.c:1007 |
| kmsan_check_memory+0xc2/0x140 mm/kmsan/kmsan.c:1086 |
| copy_to_user ./arch/x86/include/asm/uaccess.h:725 |
| snd_timer_user_read+0x6c4/0xa10 sound/core/timer.c:2004 |
| do_loop_readv_writev fs/read_write.c:716 |
| __do_readv_writev+0x94c/0x1380 fs/read_write.c:864 |
| do_readv_writev fs/read_write.c:894 |
| vfs_readv fs/read_write.c:908 |
| do_readv+0x52a/0x5d0 fs/read_write.c:934 |
| SYSC_readv+0xb6/0xd0 fs/read_write.c:1021 |
| SyS_readv+0x87/0xb0 fs/read_write.c:1018 |
| |
| This patch adds the missing reset of queue indices. Together with the |
| previous fix for the ioctl/read race, we cover the whole problem. |
| |
| Reported-by: Alexander Potapenko <glider@google.com> |
| Tested-by: Alexander Potapenko <glider@google.com> |
| Signed-off-by: Takashi Iwai <tiwai@suse.de> |
| Signed-off-by: Ben Hutchings <ben@decadent.org.uk> |
| --- |
| sound/core/timer.c | 1 + |
| 1 file changed, 1 insertion(+) |
| |
| --- a/sound/core/timer.c |
| +++ b/sound/core/timer.c |
| @@ -1590,6 +1590,7 @@ static int snd_timer_user_tselect(struct |
| if (err < 0) |
| goto __err; |
| |
| + tu->qhead = tu->qtail = tu->qused = 0; |
| kfree(tu->queue); |
| tu->queue = NULL; |
| kfree(tu->tqueue); |