Blame SOURCES/CVE-2021-3347.patch

d57b6a
From 517d5c245c9805b56f73c7fa0e23e8853fe22da6 Mon Sep 17 00:00:00 2001
d57b6a
From: Artem Savkov <asavkov@redhat.com>
d57b6a
Date: Fri, 21 May 2021 14:20:32 +0200
d57b6a
Subject: [RHEL7.9 KPATCH] CVE-2021-3347 Use after free via PI futex state
d57b6a
d57b6a
Kernels:
d57b6a
3.10.0-1160.el7
d57b6a
3.10.0-1160.2.1.el7
d57b6a
3.10.0-1160.2.2.el7
d57b6a
3.10.0-1160.6.1.el7
d57b6a
3.10.0-1160.11.1.el7
d57b6a
3.10.0-1160.15.2.el7
d57b6a
3.10.0-1160.21.1.el7
d57b6a
3.10.0-1160.24.1.el7
d57b6a
3.10.0-1160.25.1.el7
d57b6a
d57b6a
Changes since last build:
d57b6a
[x86_64]:
d57b6a
futex.o: changed function: do_futex
d57b6a
futex.o: changed function: fixup_owner
d57b6a
futex.o: changed function: fixup_pi_state_owner.isra.16
d57b6a
futex.o: changed function: free_pi_state
d57b6a
futex.o: changed function: futex_lock_pi.isra.20
d57b6a
futex.o: changed function: futex_wait_requeue_pi.constprop.22
d57b6a
futex.o: new function: pi_state_update_owner
d57b6a
d57b6a
[ppc64le]:
d57b6a
futex.o: changed function: do_futex
d57b6a
futex.o: changed function: fixup_owner
d57b6a
futex.o: changed function: fixup_pi_state_owner.isra.9
d57b6a
futex.o: changed function: free_pi_state
d57b6a
futex.o: changed function: futex_lock_pi.isra.16
d57b6a
futex.o: changed function: futex_wait_requeue_pi.constprop.17
d57b6a
futex.o: changed function: unqueue_me_pi
d57b6a
futex.o: new function: pi_state_update_owner
d57b6a
d57b6a
---------------------------
d57b6a
d57b6a
Modifications: added -fno-optimize-sibling-calls to fixup_owner()
d57b6a
d57b6a
commit d2fb2a9cf682bdba4b66103fb079c13a04039430
d57b6a
Author: Donghai Qiao <dqiao@redhat.com>
d57b6a
Date:   Thu May 20 16:35:49 2021 -0400
d57b6a
d57b6a
    futex: Handle faults correctly for PI futexes
d57b6a
d57b6a
    Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1935108
d57b6a
    Upstream status: 34b1a1ce1458f50ef27c54e28eb9b1947012907a
d57b6a
    CVE: CVE-2021-3347
d57b6a
d57b6a
    Conflicts:
d57b6a
    The original patch is intent to make the state of rtmutex and pi_state consistent
d57b6a
    if the kernel is unable to update the user space futex word, rather than unlocking
d57b6a
    the rtmutex and leaving pi_state out of synched. As a result, this original fix
d57b6a
    removed part of the code which was introduced by 16ffa12d7 ("futex: Pull
d57b6a
    rt_mutex_futex_unlock() out from under hb->lock") to the functions futex_lock_pi()
d57b6a
    and futex_wait_requeue_pi() to avoid the inconsistency. So the conflicts are related
d57b6a
    to the following two commits, though git blame displayed a much longer list which
d57b6a
    shows the chain of dependency in the history.
d57b6a
d57b6a
    16ffa12d7425 ("futex: Pull rt_mutex_futex_unlock() out from under hb->lock")
d57b6a
    c236c8e95a3d ("futex: Fix potential use-after-free in FUTEX_REQUEUE_PI")
d57b6a
d57b6a
    commit 34b1a1ce1458f50ef27c54e28eb9b1947012907a
d57b6a
    Author: Thomas Gleixner <tglx@linutronix.de>
d57b6a
    Date:   Mon, 18 Jan 2021 19:01:21 +0100
d57b6a
d57b6a
        futex: Handle faults correctly for PI futexes
d57b6a
d57b6a
        fixup_pi_state_owner() tries to ensure that the state of the rtmutex,
d57b6a
        pi_state and the user space value related to the PI futex are consistent
d57b6a
        before returning to user space. In case that the user space value update
d57b6a
        faults and the fault cannot be resolved by faulting the page in via
d57b6a
        fault_in_user_writeable() the function returns with -EFAULT and leaves
d57b6a
        the rtmutex and pi_state owner state inconsistent.
d57b6a
d57b6a
        A subsequent futex_unlock_pi() operates on the inconsistent pi_state and
d57b6a
        releases the rtmutex despite not owning it which can corrupt the RB tree of
d57b6a
        the rtmutex and cause a subsequent kernel stack use after free.
d57b6a
d57b6a
        It was suggested to loop forever in fixup_pi_state_owner() if the fault
d57b6a
        cannot be resolved, but that results in runaway tasks which is especially
d57b6a
        undesired when the problem happens due to a programming error and not due
d57b6a
        to malice.
d57b6a
d57b6a
        As the user space value cannot be fixed up, the proper solution is to make
d57b6a
        the rtmutex and the pi_state consistent so both have the same owner. This
d57b6a
        leaves the user space value out of sync. Any subsequent operation on the
d57b6a
        futex will fail because the 10th rule of PI futexes (pi_state owner and
d57b6a
        user space value are consistent) has been violated.
d57b6a
d57b6a
        As a consequence this removes the inept attempts of 'fixing' the situation
d57b6a
        in case that the current task owns the rtmutex when returning with an
d57b6a
        unresolvable fault by unlocking the rtmutex which left pi_state::owner and
d57b6a
        rtmutex::owner out of sync in a different and only slightly less dangerous
d57b6a
        way.
d57b6a
d57b6a
        Fixes: 1b7558e457ed ("futexes: fix fault handling in futex_lock_pi")
d57b6a
        Reported-by: gzobqq@gmail.com
d57b6a
        Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
d57b6a
        Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
d57b6a
        Cc: stable@vger.kernel.org
d57b6a
d57b6a
    Signed-off-by: Donghai Qiao <dqiao@redhat.com>
d57b6a
d57b6a
commit 25077b49b47c1cdf224b54c837172ff820e8be88
d57b6a
Author: Donghai Qiao <dqiao@redhat.com>
d57b6a
Date:   Thu May 20 16:30:16 2021 -0400
d57b6a
d57b6a
    futex: Provide and use pi_state_update_owner()
d57b6a
d57b6a
    Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1935108
d57b6a
    Upstream status: c5cade200ab9a2a3be9e7f32a752c8d86b502ec7
d57b6a
    CVE: CVE-2021-3347
d57b6a
d57b6a
    Conflicts:
d57b6a
    Updating the owner of pi_state requires that we remove the pi_state structure from
d57b6a
    the old owner's pi_state_list then add it to the new owner's pi_state_list. Because
d57b6a
    this action takes place in multiple occassions in the current upstream futex.c, so
d57b6a
    the similar code is duplicated in all these places. The purpose of this patch is to
d57b6a
    eliminate these code duplications with a new routine pi_state_update_owner().
d57b6a
d57b6a
    The conflicts in 7.9.z are caused by the differences in places where updating owner
d57b6a
    takes place. After sorting out the details, the relevant commit IDs as below :
d57b6a
d57b6a
    734009e96d19 ("futex: Change locking rules")
d57b6a
    b4abf91047cf ("rtmutex: Make wait_lock irq safe")
d57b6a
d57b6a
    commit c5cade200ab9a2a3be9e7f32a752c8d86b502ec7
d57b6a
    Author: Thomas Gleixner <tglx@linutronix.de>
d57b6a
    Date:   Tue, 19 Jan 2021 15:21:35 +0100
d57b6a
d57b6a
        futex: Provide and use pi_state_update_owner()
d57b6a
d57b6a
        Updating pi_state::owner is done at several places with the same
d57b6a
        code. Provide a function for it and use that at the obvious places.
d57b6a
d57b6a
        This is also a preparation for a bug fix to avoid yet another copy of the
d57b6a
        same code or alternatively introducing a completely unpenetratable mess of
d57b6a
        gotos.
d57b6a
d57b6a
        Originally-by: Peter Zijlstra <peterz@infradead.org>
d57b6a
        Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
d57b6a
        Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
d57b6a
        Cc: stable@vger.kernel.org
d57b6a
d57b6a
    Signed-off-by: Donghai Qiao <dqiao@redhat.com>
d57b6a
d57b6a
commit 69414a50f8bad2063b89981110fb374733209d9d
d57b6a
Author: Donghai Qiao <dqiao@redhat.com>
d57b6a
Date:   Wed May 19 14:24:04 2021 -0400
d57b6a
d57b6a
    futex: Replace pointless printk in fixup_owner()
d57b6a
d57b6a
    Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1935108
d57b6a
    Upstream status: 04b79c55201f02ffd675e1231d731365e335c307
d57b6a
    CVE: CVE-2021-3347
d57b6a
d57b6a
    commit 04b79c55201f02ffd675e1231d731365e335c307
d57b6a
    Author: Thomas Gleixner <tglx@linutronix.de>
d57b6a
    Date:   Tue, 19 Jan 2021 16:06:10 +0100
d57b6a
d57b6a
        futex: Replace pointless printk in fixup_owner()
d57b6a
d57b6a
        If that unexpected case of inconsistent arguments ever happens then the
d57b6a
        futex state is left completely inconsistent and the printk is not really
d57b6a
        helpful. Replace it with a warning and make the state consistent.
d57b6a
d57b6a
        Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
d57b6a
        Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
d57b6a
        Cc: stable@vger.kernel.org
d57b6a
d57b6a
    Signed-off-by: Donghai Qiao <dqiao@redhat.com>
d57b6a
d57b6a
commit 7e96fb06469c95628039ead2591f82e88af5da10
d57b6a
Author: Donghai Qiao <dqiao@redhat.com>
d57b6a
Date:   Wed May 19 14:19:05 2021 -0400
d57b6a
d57b6a
    futex: Ensure the correct return value from futex_lock_pi()
d57b6a
d57b6a
    Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1935108
d57b6a
    Upstream status: 12bb3f7f1b03d5913b3f9d4236a488aa7774dfe9
d57b6a
    CVE: CVE-2021-3347
d57b6a
d57b6a
    Conflicts:
d57b6a
    This original upstream patch relies heavily on c1e2f0eaf015 ("futex: Avoid
d57b6a
    violating the 10th rule of futex") which is one of the upstream commits listed
d57b6a
    below. But the backport for c1e2f0eaf015 requires we resolve very complex chain
d57b6a
    of dependencies across multiple critical kernel source files therefore the risk
d57b6a
    is considered too high for 7.9.z.
d57b6a
d57b6a
    Instead of pulling together tons of the relevant commits in to 7.9.z, we just
d57b6a
    want to take a light risk approach by digesting the fix 12bb3f7f1b03 ("futex:
d57b6a
    Ensure the correct return value from futex_lock_pi()") for 7.9.z. All we need
d57b6a
    to do is to make the changed functions fixup_owner() and fixup_pi_state_owner()
d57b6a
    of 7.9.z return the required values as this upstream fix suggests in every
d57b6a
    circumstance. This way, we can cleanly cut this CVE patch set with merely four
d57b6a
    patches, without having to backport tons of patches in the chain of dependency.
d57b6a
d57b6a
    Besides, an extra change made to fixup_owner() (see HUNK -2063,13 +2062,11 in
d57b6a
    this backport patch) is to eliminate a mistake made by upstream, where the
d57b6a
    specification of a local variable "ret" was removed from that function, but
d57b6a
    there was still a dereference to "ret" as shown by that HUNK.
d57b6a
d57b6a
    16ffa12d7425 ("futex: Pull rt_mutex_futex_unlock() out from under hb->lock")
d57b6a
    c1e2f0eaf015 ("futex: Avoid violating the 10th rule of futex")
d57b6a
    734009e96d19 ("futex: Change locking rules")
d57b6a
    d7c5ed73b19c ("futex: Remove needless goto's")
d57b6a
    6b4f4bc9cb22 ("locking/futex: Allow low-level atomic operations to return -EAGAIN")
d57b6a
d57b6a
    commit 12bb3f7f1b03d5913b3f9d4236a488aa7774dfe9
d57b6a
    Author: Thomas Gleixner <tglx@linutronix.de>
d57b6a
    Date:   Wed, 20 Jan 2021 16:00:24 +0100
d57b6a
d57b6a
        futex: Ensure the correct return value from futex_lock_pi()
d57b6a
d57b6a
        In case that futex_lock_pi() was aborted by a signal or a timeout and the
d57b6a
        task returned without acquiring the rtmutex, but is the designated owner of
d57b6a
        the futex due to a concurrent futex_unlock_pi() fixup_owner() is invoked to
d57b6a
        establish consistent state. In that case it invokes fixup_pi_state_owner()
d57b6a
        which in turn tries to acquire the rtmutex again. If that succeeds then it
d57b6a
        does not propagate this success to fixup_owner() and futex_lock_pi()
d57b6a
        returns -EINTR or -ETIMEOUT despite having the futex locked.
d57b6a
d57b6a
        Return success from fixup_pi_state_owner() in all cases where the current
d57b6a
        task owns the rtmutex and therefore the futex and propagate it correctly
d57b6a
        through fixup_owner(). Fixup the other callsite which does not expect a
d57b6a
        positive return value.
d57b6a
d57b6a
        Fixes: c1e2f0eaf015 ("futex: Avoid violating the 10th rule of futex")
d57b6a
        Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
d57b6a
        Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
d57b6a
        Cc: stable@vger.kernel.org
d57b6a
d57b6a
    Signed-off-by: Donghai Qiao <dqiao@redhat.com>
d57b6a
d57b6a
Signed-off-by: Artem Savkov <asavkov@redhat.com>
d57b6a
Acked-by: Joe Lawrence <joe.lawrence@redhat.com>
d57b6a
Acked-by: Yannick Cote <ycote@redhat.com>
d57b6a
---
d57b6a
 kernel/futex.c | 123 +++++++++++++++++++++++++------------------------
d57b6a
 1 file changed, 63 insertions(+), 60 deletions(-)
d57b6a
d57b6a
diff --git a/kernel/futex.c b/kernel/futex.c
d57b6a
index 877831775d7aa..8ec57c357ca58 100644
d57b6a
--- a/kernel/futex.c
d57b6a
+++ b/kernel/futex.c
d57b6a
@@ -640,6 +640,29 @@ static struct futex_pi_state * alloc_pi_state(void)
d57b6a
 	return pi_state;
d57b6a
 }
d57b6a
 
d57b6a
+static void pi_state_update_owner(struct futex_pi_state *pi_state,
d57b6a
+				  struct task_struct *new_owner)
d57b6a
+{
d57b6a
+	struct task_struct *old_owner = pi_state->owner;
d57b6a
+
d57b6a
+	lockdep_assert_held(&pi_state->pi_mutex.wait_lock);
d57b6a
+
d57b6a
+	if (old_owner) {
d57b6a
+		raw_spin_lock_irq(&old_owner->pi_lock);
d57b6a
+		WARN_ON(list_empty(&pi_state->list));
d57b6a
+		list_del_init(&pi_state->list);
d57b6a
+		raw_spin_unlock_irq(&old_owner->pi_lock);
d57b6a
+	}
d57b6a
+
d57b6a
+	if (new_owner) {
d57b6a
+		raw_spin_lock_irq(&new_owner->pi_lock);
d57b6a
+		WARN_ON(!list_empty(&pi_state->list));
d57b6a
+		list_add(&pi_state->list, &new_owner->pi_state_list);
d57b6a
+		pi_state->owner = new_owner;
d57b6a
+		raw_spin_unlock_irq(&new_owner->pi_lock);
d57b6a
+	}
d57b6a
+}
d57b6a
+
d57b6a
 static void free_pi_state(struct futex_pi_state *pi_state)
d57b6a
 {
d57b6a
 	if (!atomic_dec_and_test(&pi_state->refcount))
d57b6a
@@ -650,10 +673,7 @@ static void free_pi_state(struct futex_pi_state *pi_state)
d57b6a
 	 * and has cleaned up the pi_state already
d57b6a
 	 */
d57b6a
 	if (pi_state->owner) {
d57b6a
-		raw_spin_lock_irq(&pi_state->owner->pi_lock);
d57b6a
-		list_del_init(&pi_state->list);
d57b6a
-		raw_spin_unlock_irq(&pi_state->owner->pi_lock);
d57b6a
-
d57b6a
+		pi_state_update_owner(pi_state, NULL);
d57b6a
 		rt_mutex_proxy_unlock(&pi_state->pi_mutex, pi_state->owner);
d57b6a
 	}
d57b6a
 
d57b6a
@@ -791,7 +811,8 @@ void exit_pi_state_list(struct task_struct *curr)
d57b6a
  *	FUTEX_OWNER_DIED bit. See [4]
d57b6a
  *
d57b6a
  * [10] There is no transient state which leaves owner and user space
d57b6a
- *	TID out of sync.
d57b6a
+ *	TID out of sync. Except one error case where the kernel is denied
d57b6a
+ *	write access to the user address, see fixup_pi_state_owner().
d57b6a
  */
d57b6a
 static int
d57b6a
 lookup_pi_state(u32 uval, struct futex_hash_bucket *hb,
d57b6a
@@ -1168,16 +1189,7 @@ static int wake_futex_pi(u32 __user *uaddr, u32 uval, struct futex_q *this)
d57b6a
 		return ret;
d57b6a
 	}
d57b6a
 
d57b6a
-	raw_spin_lock_irq(&pi_state->owner->pi_lock);
d57b6a
-	WARN_ON(list_empty(&pi_state->list));
d57b6a
-	list_del_init(&pi_state->list);
d57b6a
-	raw_spin_unlock_irq(&pi_state->owner->pi_lock);
d57b6a
-
d57b6a
-	raw_spin_lock_irq(&new_owner->pi_lock);
d57b6a
-	WARN_ON(!list_empty(&pi_state->list));
d57b6a
-	list_add(&pi_state->list, &new_owner->pi_state_list);
d57b6a
-	pi_state->owner = new_owner;
d57b6a
-	raw_spin_unlock_irq(&new_owner->pi_lock);
d57b6a
+	pi_state_update_owner(pi_state, new_owner);
d57b6a
 
d57b6a
 	raw_spin_unlock(&pi_state->pi_mutex.wait_lock);
d57b6a
 	rt_mutex_unlock(&pi_state->pi_mutex);
d57b6a
@@ -1953,20 +1965,9 @@ retry:
d57b6a
 	 * We fixed up user space. Now we need to fix the pi_state
d57b6a
 	 * itself.
d57b6a
 	 */
d57b6a
-	if (pi_state->owner != NULL) {
d57b6a
-		raw_spin_lock_irq(&pi_state->owner->pi_lock);
d57b6a
-		WARN_ON(list_empty(&pi_state->list));
d57b6a
-		list_del_init(&pi_state->list);
d57b6a
-		raw_spin_unlock_irq(&pi_state->owner->pi_lock);
d57b6a
-	}
d57b6a
+	pi_state_update_owner(pi_state, newowner);
d57b6a
 
d57b6a
-	pi_state->owner = newowner;
d57b6a
-
d57b6a
-	raw_spin_lock_irq(&newowner->pi_lock);
d57b6a
-	WARN_ON(!list_empty(&pi_state->list));
d57b6a
-	list_add(&pi_state->list, &newowner->pi_state_list);
d57b6a
-	raw_spin_unlock_irq(&newowner->pi_lock);
d57b6a
-	return 0;
d57b6a
+	return newowner == current;
d57b6a
 
d57b6a
 	/*
d57b6a
 	 * To handle the page fault we need to drop the hash bucket
d57b6a
@@ -1989,10 +1990,26 @@ handle_fault:
d57b6a
 	 * Check if someone else fixed it for us:
d57b6a
 	 */
d57b6a
 	if (pi_state->owner != oldowner)
d57b6a
-		return 0;
d57b6a
+		return newowner == current;
d57b6a
+
d57b6a
+	if (ret) {
d57b6a
+		/*
d57b6a
+		 * fault_in_user_writeable() failed so user state is immutable. At
d57b6a
+		 * best we can make the kernel state consistent but user state will
d57b6a
+		 * be most likely hosed and any subsequent unlock operation will be
d57b6a
+		 * rejected due to PI futex rule [10].
d57b6a
+		 *
d57b6a
+		 * Ensure that the rtmutex owner is also the pi_state owner despite
d57b6a
+		 * the user space value claiming something different. There is no
d57b6a
+		 * point in unlocking the rtmutex if current is the owner as it
d57b6a
+		 * would need to wait until the next waiter has taken the rtmutex
d57b6a
+		 * to guarantee consistent state. Keep it simple. Userspace asked
d57b6a
+		 * for this wreckaged state.
d57b6a
+		 */
d57b6a
+		pi_state_update_owner(pi_state, rt_mutex_owner(&pi_state->pi_mutex));
d57b6a
 
d57b6a
-	if (ret)
d57b6a
 		return ret;
d57b6a
+	}
d57b6a
 
d57b6a
 	goto retry;
d57b6a
 }
d57b6a
@@ -2014,10 +2031,10 @@ static long futex_wait_restart(struct restart_block *restart);
d57b6a
  *  0 - success, lock not taken;
d57b6a
  * <0 - on error (-EFAULT)
d57b6a
  */
d57b6a
+__attribute__((optimize("-fno-optimize-sibling-calls")))
d57b6a
 static int fixup_owner(u32 __user *uaddr, struct futex_q *q, int locked)
d57b6a
 {
d57b6a
 	struct task_struct *owner;
d57b6a
-	int ret = 0;
d57b6a
 
d57b6a
 	if (locked) {
d57b6a
 		/*
d57b6a
@@ -2025,8 +2042,8 @@ static int fixup_owner(u32 __user *uaddr, struct futex_q *q, int locked)
d57b6a
 		 * did a lock-steal - fix up the PI-state in that case:
d57b6a
 		 */
d57b6a
 		if (q->pi_state->owner != current)
d57b6a
-			ret = fixup_pi_state_owner(uaddr, q, current);
d57b6a
-		goto out;
d57b6a
+			return fixup_pi_state_owner(uaddr, q, current);
d57b6a
+		return 1;
d57b6a
 	}
d57b6a
 
d57b6a
 	/*
d57b6a
@@ -2040,8 +2057,7 @@ static int fixup_owner(u32 __user *uaddr, struct futex_q *q, int locked)
d57b6a
 		 * rt_mutex waiters list.
d57b6a
 		 */
d57b6a
 		if (rt_mutex_trylock(&q->pi_state->pi_mutex)) {
d57b6a
-			locked = 1;
d57b6a
-			goto out;
d57b6a
+			return 1;
d57b6a
 		}
d57b6a
 
d57b6a
 		/*
d57b6a
@@ -2054,22 +2070,18 @@ static int fixup_owner(u32 __user *uaddr, struct futex_q *q, int locked)
d57b6a
 		if (!owner)
d57b6a
 			owner = rt_mutex_next_owner(&q->pi_state->pi_mutex);
d57b6a
 		raw_spin_unlock(&q->pi_state->pi_mutex.wait_lock);
d57b6a
-		ret = fixup_pi_state_owner(uaddr, q, owner);
d57b6a
-		goto out;
d57b6a
+
d57b6a
+		return fixup_pi_state_owner(uaddr, q, owner);
d57b6a
 	}
d57b6a
 
d57b6a
 	/*
d57b6a
 	 * Paranoia check. If we did not take the lock, then we should not be
d57b6a
-	 * the owner of the rt_mutex.
d57b6a
+	 * the owner of the rt_mutex. Warn and establish consistent state.
d57b6a
 	 */
d57b6a
-	if (rt_mutex_owner(&q->pi_state->pi_mutex) == current)
d57b6a
-		printk(KERN_ERR "fixup_owner: ret = %d pi-mutex: %p "
d57b6a
-				"pi-state %p\n", ret,
d57b6a
-				q->pi_state->pi_mutex.owner,
d57b6a
-				q->pi_state->owner);
d57b6a
+	if (WARN_ON_ONCE(rt_mutex_owner(&q->pi_state->pi_mutex) == current))
d57b6a
+		return fixup_pi_state_owner(uaddr, q, current);
d57b6a
 
d57b6a
-out:
d57b6a
-	return ret ? ret : locked;
d57b6a
+	return 0;
d57b6a
 }
d57b6a
 
d57b6a
 /**
d57b6a
@@ -2363,13 +2375,6 @@ retry_private:
d57b6a
 	if (res)
d57b6a
 		ret = (res < 0) ? res : 0;
d57b6a
 
d57b6a
-	/*
d57b6a
-	 * If fixup_owner() faulted and was unable to handle the fault, unlock
d57b6a
-	 * it and return the fault to userspace.
d57b6a
-	 */
d57b6a
-	if (ret && (rt_mutex_owner(&q.pi_state->pi_mutex) == current))
d57b6a
-		rt_mutex_unlock(&q.pi_state->pi_mutex);
d57b6a
-
d57b6a
 	/* Unqueue and drop the lock */
d57b6a
 	unqueue_me_pi(&q);
d57b6a
 
d57b6a
@@ -2666,6 +2671,11 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags,
d57b6a
 			spin_lock(q.lock_ptr);
d57b6a
 			ret = fixup_pi_state_owner(uaddr2, &q, current);
d57b6a
 			spin_unlock(q.lock_ptr);
d57b6a
+			/*
d57b6a
+			 * Adjust the return value. It's either -EFAULT or
d57b6a
+			 * success (1) but the caller expects 0 for success.
d57b6a
+			 */
d57b6a
+			ret = ret < 0 ? ret : 0;
d57b6a
 		}
d57b6a
 	} else {
d57b6a
 		/*
d57b6a
@@ -2695,14 +2705,7 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags,
d57b6a
 		unqueue_me_pi(&q);
d57b6a
 	}
d57b6a
 
d57b6a
-	/*
d57b6a
-	 * If fixup_pi_state_owner() faulted and was unable to handle the
d57b6a
-	 * fault, unlock the rt_mutex and return the fault to userspace.
d57b6a
-	 */
d57b6a
-	if (ret == -EFAULT) {
d57b6a
-		if (pi_mutex && rt_mutex_owner(pi_mutex) == current)
d57b6a
-			rt_mutex_unlock(pi_mutex);
d57b6a
-	} else if (ret == -EINTR) {
d57b6a
+	if (ret == -EINTR) {
d57b6a
 		/*
d57b6a
 		 * We've already been requeued, but cannot restart by calling
d57b6a
 		 * futex_lock_pi() directly. We could restart this syscall, but
d57b6a
-- 
d57b6a
2.26.3
d57b6a