aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Zijlstra <peterz@infradead.org>2017-03-04 04:27:18 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2017-03-22 07:43:40 -0400
commit6244ffc5a1221e593a937c7ad3c03a9ce691a8df (patch)
tree893fe75ffd8e1952ad1285da878e25250e16b8ca
parent9f9115b67aa5821e1d5490d94c1ad87d0396f7b6 (diff)
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 Link: http://lkml.kernel.org/r/20170304093558.801744246@infradead.org Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--kernel/futex.c20
1 files changed, 11 insertions, 9 deletions
diff --git a/kernel/futex.c b/kernel/futex.c
index 38b68c2735c5..aa45c4e13880 100644
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -2813,7 +2813,6 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags,
2813{ 2813{
2814 struct hrtimer_sleeper timeout, *to = NULL; 2814 struct hrtimer_sleeper timeout, *to = NULL;
2815 struct rt_mutex_waiter rt_waiter; 2815 struct rt_mutex_waiter rt_waiter;
2816 struct rt_mutex *pi_mutex = NULL;
2817 struct futex_hash_bucket *hb; 2816 struct futex_hash_bucket *hb;
2818 union futex_key key2 = FUTEX_KEY_INIT; 2817 union futex_key key2 = FUTEX_KEY_INIT;
2819 struct futex_q q = futex_q_init; 2818 struct futex_q q = futex_q_init;
@@ -2905,6 +2904,8 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags,
2905 spin_unlock(q.lock_ptr); 2904 spin_unlock(q.lock_ptr);
2906 } 2905 }
2907 } else { 2906 } else {
2907 struct rt_mutex *pi_mutex;
2908
2908 /* 2909 /*
2909 * We have been woken up by futex_unlock_pi(), a timeout, or a 2910 * We have been woken up by futex_unlock_pi(), a timeout, or a
2910 * signal. futex_unlock_pi() will not destroy the lock_ptr nor 2911 * signal. futex_unlock_pi() will not destroy the lock_ptr nor
@@ -2928,18 +2929,19 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags,
2928 if (res) 2929 if (res)
2929 ret = (res < 0) ? res : 0; 2930 ret = (res < 0) ? res : 0;
2930 2931
2932 /*
2933 * If fixup_pi_state_owner() faulted and was unable to handle
2934 * the fault, unlock the rt_mutex and return the fault to
2935 * userspace.
2936 */
2937 if (ret && rt_mutex_owner(pi_mutex) == current)
2938 rt_mutex_unlock(pi_mutex);
2939
2931 /* Unqueue and drop the lock. */ 2940 /* Unqueue and drop the lock. */
2932 unqueue_me_pi(&q); 2941 unqueue_me_pi(&q);
2933 } 2942 }
2934 2943
2935 /* 2944 if (ret == -EINTR) {
2936 * If fixup_pi_state_owner() faulted and was unable to handle the
2937 * fault, unlock the rt_mutex and return the fault to userspace.
2938 */
2939 if (ret == -EFAULT) {
2940 if (pi_mutex && rt_mutex_owner(pi_mutex) == current)
2941 rt_mutex_unlock(pi_mutex);
2942 } else if (ret == -EINTR) {
2943 /* 2945 /*
2944 * We've already been requeued, but cannot restart by calling 2946 * We've already been requeued, but cannot restart by calling
2945 * futex_lock_pi() directly. We could restart this syscall, but 2947 * futex_lock_pi() directly. We could restart this syscall, but