aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/futex.c
diff options
context:
space:
mode:
authorPeter Zijlstra <peterz@infradead.org>2017-03-04 04:27:18 -0500
committerThomas Gleixner <tglx@linutronix.de>2017-03-14 16:45:36 -0400
commitc236c8e95a3d395b0494e7108f0d41cf36ec107c (patch)
tree25c0e83f3b4458fb2982a8470876f99adce29cfe /kernel/futex.c
parent4495c08e84729385774601b5146d51d9e5849f81 (diff)
futex: Fix potential use-after-free in FUTEX_REQUEUE_PI
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>
Diffstat (limited to 'kernel/futex.c')
-rw-r--r--kernel/futex.c20
1 files changed, 11 insertions, 9 deletions
diff --git a/kernel/futex.c b/kernel/futex.c
index 229a744b1781..3a4775fd7468 100644
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -2815,7 +2815,6 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags,
2815{ 2815{
2816 struct hrtimer_sleeper timeout, *to = NULL; 2816 struct hrtimer_sleeper timeout, *to = NULL;
2817 struct rt_mutex_waiter rt_waiter; 2817 struct rt_mutex_waiter rt_waiter;
2818 struct rt_mutex *pi_mutex = NULL;
2819 struct futex_hash_bucket *hb; 2818 struct futex_hash_bucket *hb;
2820 union futex_key key2 = FUTEX_KEY_INIT; 2819 union futex_key key2 = FUTEX_KEY_INIT;
2821 struct futex_q q = futex_q_init; 2820 struct futex_q q = futex_q_init;
@@ -2907,6 +2906,8 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags,
2907 spin_unlock(q.lock_ptr); 2906 spin_unlock(q.lock_ptr);
2908 } 2907 }
2909 } else { 2908 } else {
2909 struct rt_mutex *pi_mutex;
2910
2910 /* 2911 /*
2911 * We have been woken up by futex_unlock_pi(), a timeout, or a 2912 * We have been woken up by futex_unlock_pi(), a timeout, or a
2912 * signal. futex_unlock_pi() will not destroy the lock_ptr nor 2913 * signal. futex_unlock_pi() will not destroy the lock_ptr nor
@@ -2930,18 +2931,19 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags,
2930 if (res) 2931 if (res)
2931 ret = (res < 0) ? res : 0; 2932 ret = (res < 0) ? res : 0;
2932 2933
2934 /*
2935 * If fixup_pi_state_owner() faulted and was unable to handle
2936 * the fault, unlock the rt_mutex and return the fault to
2937 * userspace.
2938 */
2939 if (ret && rt_mutex_owner(pi_mutex) == current)
2940 rt_mutex_unlock(pi_mutex);
2941
2933 /* Unqueue and drop the lock. */ 2942 /* Unqueue and drop the lock. */
2934 unqueue_me_pi(&q); 2943 unqueue_me_pi(&q);
2935 } 2944 }
2936 2945
2937 /* 2946 if (ret == -EINTR) {
2938 * If fixup_pi_state_owner() faulted and was unable to handle the
2939 * fault, unlock the rt_mutex and return the fault to userspace.
2940 */
2941 if (ret == -EFAULT) {
2942 if (pi_mutex && rt_mutex_owner(pi_mutex) == current)
2943 rt_mutex_unlock(pi_mutex);
2944 } else if (ret == -EINTR) {
2945 /* 2947 /*
2946 * We've already been requeued, but cannot restart by calling 2948 * We've already been requeued, but cannot restart by calling
2947 * futex_lock_pi() directly. We could restart this syscall, but 2949 * futex_lock_pi() directly. We could restart this syscall, but