diff options
author | Peter Zijlstra <peterz@infradead.org> | 2017-03-04 04:27:18 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2017-03-22 07:43:40 -0400 |
commit | 6244ffc5a1221e593a937c7ad3c03a9ce691a8df (patch) | |
tree | 893fe75ffd8e1952ad1285da878e25250e16b8ca | |
parent | 9f9115b67aa5821e1d5490d94c1ad87d0396f7b6 (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.c | 20 |
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 |