aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Gleixner <[email protected]>2011-03-14 10:34:35 +0100
committerThomas Gleixner <[email protected]>2011-03-14 21:08:47 +0100
commit6e0aa9f8a8190e0879a29bd67aa606b51734a122 (patch)
tree66b92176051147b87031cc2755639c39f8a900f8
parent995612178c88407d8330f580ba6572cb8b284dd8 (diff)
futex: Deobfuscate handle_futex_death()
handle_futex_death() uses futex_atomic_cmpxchg_inatomic() without disabling page faults. That's ok, but totally non obvious. We don't hold locks so we actually can and want to fault here, because the get_user() before futex_atomic_cmpxchg_inatomic() does not guarantee a R/W mapping. We could just add a big fat comment to explain this, but actually changing the code so that the functionality is entirely clear is better. Use the helper function which disables page faults around the futex_atomic_cmpxchg_inatomic() and handle a fault with a call to fault_in_user_writeable() as all other places in the futex code do as well. Pointed-out-by: Linus Torvalds <[email protected]> Signed-off-by: Thomas Gleixner <[email protected]> Acked-by: Darren Hart <[email protected]> Cc: Michel Lespinasse <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: Matt Turner <[email protected]> Cc: Russell King <[email protected]> Cc: David Howells <[email protected]> Cc: Tony Luck <[email protected]> Cc: Michal Simek <[email protected]> Cc: Ralf Baechle <[email protected]> Cc: "James E.J. Bottomley" <[email protected]> Cc: Benjamin Herrenschmidt <[email protected]> Cc: Martin Schwidefsky <[email protected]> Cc: Paul Mundt <[email protected]> Cc: "David S. Miller" <[email protected]> Cc: Chris Metcalf <[email protected]> LKML-Reference: <[email protected]> Signed-off-by: Thomas Gleixner <[email protected]>
-rw-r--r--kernel/futex.c17
1 files changed, 14 insertions, 3 deletions
diff --git a/kernel/futex.c b/kernel/futex.c
index c6bef6e404fe..e9251d934f7d 100644
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -2458,9 +2458,20 @@ retry:
* userspace.
*/
mval = (uval & FUTEX_WAITERS) | FUTEX_OWNER_DIED;
- if (futex_atomic_cmpxchg_inatomic(&nval, uaddr, uval, mval))
- return -1;
-
+ /*
+ * We are not holding a lock here, but we want to have
+ * the pagefault_disable/enable() protection because
+ * we want to handle the fault gracefully. If the
+ * access fails we try to fault in the futex with R/W
+ * verification via get_user_pages. get_user() above
+ * does not guarantee R/W access. If that fails we
+ * give up and leave the futex locked.
+ */
+ if (cmpxchg_futex_value_locked(&nval, uaddr, uval, mval)) {
+ if (fault_in_user_writeable(uaddr))
+ return -1;
+ goto retry;
+ }
if (nval != uval)
goto retry;