| From 49e31dcd319be0dd78c86f8aa2d62fe155c48b08 Mon Sep 17 00:00:00 2001 |
| From: Peter Zijlstra <peterz@infradead.org> |
| Date: Sat, 4 Mar 2017 10:27:18 +0100 |
| Subject: [PATCH] futex: Fix potential use-after-free in FUTEX_REQUEUE_PI |
| |
| commit c236c8e95a3d395b0494e7108f0d41cf36ec107c upstream. |
| |
| While working on the futex code, I stumbled over this potential |
| use-after-free scenario. Dmitry triggered it later with syzkaller. |
| |
| pi_mutex is a pointer into pi_state, which we drop the reference on in |
| unqueue_me_pi(). So any access to that pointer after that is bad. |
| |
| Since other sites already do rt_mutex_unlock() with hb->lock held, see |
| for example futex_lock_pi(), simply move the unlock before |
| unqueue_me_pi(). |
| |
| Reported-by: Dmitry Vyukov <dvyukov@google.com> |
| Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> |
| Reviewed-by: Darren Hart <dvhart@linux.intel.com> |
| Cc: juri.lelli@arm.com |
| Cc: bigeasy@linutronix.de |
| Cc: xlpang@redhat.com |
| Cc: rostedt@goodmis.org |
| Cc: mathieu.desnoyers@efficios.com |
| Cc: jdesfossez@efficios.com |
| Cc: dvhart@infradead.org |
| Cc: bristot@redhat.com |
| Cc: stable@vger.kernel.org |
| Link: http://lkml.kernel.org/r/20170304093558.801744246@infradead.org |
| Signed-off-by: Thomas Gleixner <tglx@linutronix.de> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/kernel/futex.c b/kernel/futex.c |
| index e3b9561e9f8e..ec5edbf6539e 100644 |
| --- a/kernel/futex.c |
| +++ b/kernel/futex.c |
| @@ -2804,7 +2804,6 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags, |
| { |
| struct hrtimer_sleeper timeout, *to = NULL; |
| struct rt_mutex_waiter rt_waiter; |
| - struct rt_mutex *pi_mutex = NULL; |
| struct futex_hash_bucket *hb; |
| union futex_key key2 = FUTEX_KEY_INIT; |
| struct futex_q q = futex_q_init; |
| @@ -2896,6 +2895,8 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags, |
| spin_unlock(q.lock_ptr); |
| } |
| } else { |
| + struct rt_mutex *pi_mutex; |
| + |
| /* |
| * We have been woken up by futex_unlock_pi(), a timeout, or a |
| * signal. futex_unlock_pi() will not destroy the lock_ptr nor |
| @@ -2919,18 +2920,19 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags, |
| if (res) |
| ret = (res < 0) ? res : 0; |
| |
| + /* |
| + * If fixup_pi_state_owner() faulted and was unable to handle |
| + * the fault, unlock the rt_mutex and return the fault to |
| + * userspace. |
| + */ |
| + if (ret && rt_mutex_owner(pi_mutex) == current) |
| + rt_mutex_unlock(pi_mutex); |
| + |
| /* Unqueue and drop the lock. */ |
| unqueue_me_pi(&q); |
| } |
| |
| - /* |
| - * If fixup_pi_state_owner() faulted and was unable to handle the |
| - * fault, unlock the rt_mutex and return the fault to userspace. |
| - */ |
| - if (ret == -EFAULT) { |
| - if (pi_mutex && rt_mutex_owner(pi_mutex) == current) |
| - rt_mutex_unlock(pi_mutex); |
| - } else if (ret == -EINTR) { |
| + if (ret == -EINTR) { |
| /* |
| * We've already been requeued, but cannot restart by calling |
| * futex_lock_pi() directly. We could restart this syscall, but |
| -- |
| 2.12.0 |
| |