aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/futex.c
diff options
context:
space:
mode:
authorMichel Lespinasse <walken@google.com>2011-03-10 21:48:51 -0500
committerThomas Gleixner <tglx@linutronix.de>2011-03-11 06:23:08 -0500
commit37a9d912b24f96a0591773e6e6c3642991ae5a70 (patch)
tree5c4d5b9a52e2c533269e589115afbd25b6c8534b /kernel/futex.c
parent522d7decc0370070448a8c28982c8dfd8970489e (diff)
futex: Sanitize cmpxchg_futex_value_locked API
The cmpxchg_futex_value_locked API was funny in that it returned either the original, user-exposed futex value OR an error code such as -EFAULT. This was confusing at best, and could be a source of livelocks in places that retry the cmpxchg_futex_value_locked after trying to fix the issue by running fault_in_user_writeable(). This change makes the cmpxchg_futex_value_locked API more similar to the get_futex_value_locked one, returning an error code and updating the original value through a reference argument. Signed-off-by: Michel Lespinasse <walken@google.com> Acked-by: Chris Metcalf <cmetcalf@tilera.com> [tile] Acked-by: Tony Luck <tony.luck@intel.com> [ia64] Acked-by: Thomas Gleixner <tglx@linutronix.de> Tested-by: Michal Simek <monstr@monstr.eu> [microblaze] Acked-by: David Howells <dhowells@redhat.com> [frv] Cc: Darren Hart <darren@dvhart.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Matt Turner <mattst88@gmail.com> Cc: Russell King <linux@arm.linux.org.uk> Cc: Ralf Baechle <ralf@linux-mips.org> Cc: "James E.J. Bottomley" <jejb@parisc-linux.org> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org> Cc: Martin Schwidefsky <schwidefsky@de.ibm.com> Cc: Paul Mundt <lethal@linux-sh.org> Cc: "David S. Miller" <davem@davemloft.net> Cc: Linus Torvalds <torvalds@linux-foundation.org> LKML-Reference: <20110311024851.GC26122@google.com> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'kernel/futex.c')
-rw-r--r--kernel/futex.c45
1 files changed, 15 insertions, 30 deletions
diff --git a/kernel/futex.c b/kernel/futex.c
index 773815465bac..237f14bfc022 100644
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -381,15 +381,16 @@ static struct futex_q *futex_top_waiter(struct futex_hash_bucket *hb,
381 return NULL; 381 return NULL;
382} 382}
383 383
384static u32 cmpxchg_futex_value_locked(u32 __user *uaddr, u32 uval, u32 newval) 384static int cmpxchg_futex_value_locked(u32 *curval, u32 __user *uaddr,
385 u32 uval, u32 newval)
385{ 386{
386 u32 curval; 387 int ret;
387 388
388 pagefault_disable(); 389 pagefault_disable();
389 curval = futex_atomic_cmpxchg_inatomic(uaddr, uval, newval); 390 ret = futex_atomic_cmpxchg_inatomic(curval, uaddr, uval, newval);
390 pagefault_enable(); 391 pagefault_enable();
391 392
392 return curval; 393 return ret;
393} 394}
394 395
395static int get_futex_value_locked(u32 *dest, u32 __user *from) 396static int get_futex_value_locked(u32 *dest, u32 __user *from)
@@ -688,9 +689,7 @@ retry:
688 if (set_waiters) 689 if (set_waiters)
689 newval |= FUTEX_WAITERS; 690 newval |= FUTEX_WAITERS;
690 691
691 curval = cmpxchg_futex_value_locked(uaddr, 0, newval); 692 if (unlikely(cmpxchg_futex_value_locked(&curval, uaddr, 0, newval)))
692
693 if (unlikely(curval == -EFAULT))
694 return -EFAULT; 693 return -EFAULT;
695 694
696 /* 695 /*
@@ -728,9 +727,7 @@ retry:
728 lock_taken = 1; 727 lock_taken = 1;
729 } 728 }
730 729
731 curval = cmpxchg_futex_value_locked(uaddr, uval, newval); 730 if (unlikely(cmpxchg_futex_value_locked(&curval, uaddr, uval, newval)))
732
733 if (unlikely(curval == -EFAULT))
734 return -EFAULT; 731 return -EFAULT;
735 if (unlikely(curval != uval)) 732 if (unlikely(curval != uval))
736 goto retry; 733 goto retry;
@@ -843,9 +840,7 @@ static int wake_futex_pi(u32 __user *uaddr, u32 uval, struct futex_q *this)
843 840
844 newval = FUTEX_WAITERS | task_pid_vnr(new_owner); 841 newval = FUTEX_WAITERS | task_pid_vnr(new_owner);
845 842
846 curval = cmpxchg_futex_value_locked(uaddr, uval, newval); 843 if (cmpxchg_futex_value_locked(&curval, uaddr, uval, newval))
847
848 if (curval == -EFAULT)
849 ret = -EFAULT; 844 ret = -EFAULT;
850 else if (curval != uval) 845 else if (curval != uval)
851 ret = -EINVAL; 846 ret = -EINVAL;
@@ -880,10 +875,8 @@ static int unlock_futex_pi(u32 __user *uaddr, u32 uval)
880 * There is no waiter, so we unlock the futex. The owner died 875 * There is no waiter, so we unlock the futex. The owner died
881 * bit has not to be preserved here. We are the owner: 876 * bit has not to be preserved here. We are the owner:
882 */ 877 */
883 oldval = cmpxchg_futex_value_locked(uaddr, uval, 0); 878 if (cmpxchg_futex_value_locked(&oldval, uaddr, uval, 0))
884 879 return -EFAULT;
885 if (oldval == -EFAULT)
886 return oldval;
887 if (oldval != uval) 880 if (oldval != uval)
888 return -EAGAIN; 881 return -EAGAIN;
889 882
@@ -1578,9 +1571,7 @@ retry:
1578 while (1) { 1571 while (1) {
1579 newval = (uval & FUTEX_OWNER_DIED) | newtid; 1572 newval = (uval & FUTEX_OWNER_DIED) | newtid;
1580 1573
1581 curval = cmpxchg_futex_value_locked(uaddr, uval, newval); 1574 if (cmpxchg_futex_value_locked(&curval, uaddr, uval, newval))
1582
1583 if (curval == -EFAULT)
1584 goto handle_fault; 1575 goto handle_fault;
1585 if (curval == uval) 1576 if (curval == uval)
1586 break; 1577 break;
@@ -2073,11 +2064,8 @@ retry:
2073 * again. If it succeeds then we can return without waking 2064 * again. If it succeeds then we can return without waking
2074 * anyone else up: 2065 * anyone else up:
2075 */ 2066 */
2076 if (!(uval & FUTEX_OWNER_DIED)) 2067 if (!(uval & FUTEX_OWNER_DIED) &&
2077 uval = cmpxchg_futex_value_locked(uaddr, vpid, 0); 2068 cmpxchg_futex_value_locked(&uval, uaddr, vpid, 0))
2078
2079
2080 if (unlikely(uval == -EFAULT))
2081 goto pi_faulted; 2069 goto pi_faulted;
2082 /* 2070 /*
2083 * Rare case: we managed to release the lock atomically, 2071 * Rare case: we managed to release the lock atomically,
@@ -2464,9 +2452,7 @@ retry:
2464 * userspace. 2452 * userspace.
2465 */ 2453 */
2466 mval = (uval & FUTEX_WAITERS) | FUTEX_OWNER_DIED; 2454 mval = (uval & FUTEX_WAITERS) | FUTEX_OWNER_DIED;
2467 nval = futex_atomic_cmpxchg_inatomic(uaddr, uval, mval); 2455 if (futex_atomic_cmpxchg_inatomic(&nval, uaddr, uval, mval))
2468
2469 if (nval == -EFAULT)
2470 return -1; 2456 return -1;
2471 2457
2472 if (nval != uval) 2458 if (nval != uval)
@@ -2679,8 +2665,7 @@ static int __init futex_init(void)
2679 * implementation, the non-functional ones will return 2665 * implementation, the non-functional ones will return
2680 * -ENOSYS. 2666 * -ENOSYS.
2681 */ 2667 */
2682 curval = cmpxchg_futex_value_locked(NULL, 0, 0); 2668 if (cmpxchg_futex_value_locked(&curval, NULL, 0, 0) == -EFAULT)
2683 if (curval == -EFAULT)
2684 futex_cmpxchg_enabled = 1; 2669 futex_cmpxchg_enabled = 1;
2685 2670
2686 for (i = 0; i < ARRAY_SIZE(futex_queues); i++) { 2671 for (i = 0; i < ARRAY_SIZE(futex_queues); i++) {