| From: Takashi Iwai <tiwai@suse.de> |
| Date: Fri, 2 Jun 2017 15:03:38 +0200 |
| Subject: ALSA: timer: Fix race between read and ioctl |
| |
| commit d11662f4f798b50d8c8743f433842c3e40fe3378 upstream. |
| |
| The read from ALSA timer device, the function snd_timer_user_tread(), |
| may access to an uninitialized struct snd_timer_user fields when the |
| read is concurrently performed while the ioctl like |
| snd_timer_user_tselect() is invoked. We have already fixed the races |
| among ioctls via a mutex, but we seem to have forgotten the race |
| between read vs ioctl. |
| |
| This patch simply applies (more exactly extends the already applied |
| range of) tu->ioctl_lock in snd_timer_user_tread() for closing the |
| race window. |
| |
| 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 | 6 ++++-- |
| 1 file changed, 4 insertions(+), 2 deletions(-) |
| |
| --- a/sound/core/timer.c |
| +++ b/sound/core/timer.c |
| @@ -1976,6 +1976,7 @@ static ssize_t snd_timer_user_read(struc |
| |
| tu = file->private_data; |
| unit = tu->tread ? sizeof(struct snd_timer_tread) : sizeof(struct snd_timer_read); |
| + mutex_lock(&tu->ioctl_lock); |
| spin_lock_irq(&tu->qlock); |
| while ((long)count - result >= unit) { |
| while (!tu->qused) { |
| @@ -1991,7 +1992,9 @@ static ssize_t snd_timer_user_read(struc |
| add_wait_queue(&tu->qchange_sleep, &wait); |
| |
| spin_unlock_irq(&tu->qlock); |
| + mutex_unlock(&tu->ioctl_lock); |
| schedule(); |
| + mutex_lock(&tu->ioctl_lock); |
| spin_lock_irq(&tu->qlock); |
| |
| remove_wait_queue(&tu->qchange_sleep, &wait); |
| @@ -2011,7 +2014,6 @@ static ssize_t snd_timer_user_read(struc |
| tu->qused--; |
| spin_unlock_irq(&tu->qlock); |
| |
| - mutex_lock(&tu->ioctl_lock); |
| if (tu->tread) { |
| if (copy_to_user(buffer, &tu->tqueue[qhead], |
| sizeof(struct snd_timer_tread))) |
| @@ -2021,7 +2023,6 @@ static ssize_t snd_timer_user_read(struc |
| sizeof(struct snd_timer_read))) |
| err = -EFAULT; |
| } |
| - mutex_unlock(&tu->ioctl_lock); |
| |
| spin_lock_irq(&tu->qlock); |
| if (err < 0) |
| @@ -2031,6 +2032,7 @@ static ssize_t snd_timer_user_read(struc |
| } |
| _error: |
| spin_unlock_irq(&tu->qlock); |
| + mutex_unlock(&tu->ioctl_lock); |
| return result > 0 ? result : err; |
| } |
| |