|
|
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 |
|