aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/futex.c
diff options
context:
space:
mode:
authorDarren Hart <dvhltc@us.ibm.com>2009-08-13 20:36:53 -0400
committerThomas Gleixner <tglx@linutronix.de>2009-08-16 04:59:05 -0400
commit84bc4af59081ee974dd80210e694ab59ebe51ce8 (patch)
treea07c68106814d0a748e00c75466d741d05d7e908 /kernel/futex.c
parentcc6db4e60116c1f76577b6850a35ae7de69a95b6 (diff)
futex: Detect mismatched requeue targets
There is currently no check to ensure that userspace uses the same futex requeue target (uaddr2) in futex_requeue() that the waiter used in futex_wait_requeue_pi(). A mismatch here could very unexpected results as the waiter assumes it either wakes on uaddr1 or uaddr2. We could detect this on wakeup in the waiter, but the cleanup is more intense after the improper requeue has occured. This patch stores the waiter's expected requeue target in a new requeue_pi_key pointer in the futex_q which futex_requeue() checks prior to attempting to do a proxy lock acquistion or a requeue when requeue_pi=1. If they don't match, return -EINVAL from futex_requeue, aborting the requeue of any remaining waiters. Signed-off-by: Darren Hart <dvhltc@us.ibm.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Eric Dumazet <eric.dumazet@gmail.com> Cc: John Kacur <jkacur@redhat.com> Cc: Dinakar Guniguntala <dino@in.ibm.com> Cc: John Stultz <johnstul@us.ibm.com> LKML-Reference: <20090814003650.14634.63916.stgit@Aeon> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'kernel/futex.c')
-rw-r--r--kernel/futex.c24
1 files changed, 20 insertions, 4 deletions
diff --git a/kernel/futex.c b/kernel/futex.c
index d077201b393d..f0dea283e77e 100644
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -115,6 +115,9 @@ struct futex_q {
115 /* rt_waiter storage for requeue_pi: */ 115 /* rt_waiter storage for requeue_pi: */
116 struct rt_mutex_waiter *rt_waiter; 116 struct rt_mutex_waiter *rt_waiter;
117 117
118 /* The expected requeue pi target futex key: */
119 union futex_key *requeue_pi_key;
120
118 /* Bitset for the optional bitmasked wakeup */ 121 /* Bitset for the optional bitmasked wakeup */
119 u32 bitset; 122 u32 bitset;
120}; 123};
@@ -1080,6 +1083,10 @@ static int futex_proxy_trylock_atomic(u32 __user *pifutex,
1080 if (!top_waiter) 1083 if (!top_waiter)
1081 return 0; 1084 return 0;
1082 1085
1086 /* Ensure we requeue to the expected futex. */
1087 if (!match_futex(top_waiter->requeue_pi_key, key2))
1088 return -EINVAL;
1089
1083 /* 1090 /*
1084 * Try to take the lock for top_waiter. Set the FUTEX_WAITERS bit in 1091 * Try to take the lock for top_waiter. Set the FUTEX_WAITERS bit in
1085 * the contended case or if set_waiters is 1. The pi_state is returned 1092 * the contended case or if set_waiters is 1. The pi_state is returned
@@ -1260,6 +1267,12 @@ retry_private:
1260 continue; 1267 continue;
1261 } 1268 }
1262 1269
1270 /* Ensure we requeue to the expected futex for requeue_pi. */
1271 if (requeue_pi && !match_futex(this->requeue_pi_key, &key2)) {
1272 ret = -EINVAL;
1273 break;
1274 }
1275
1263 /* 1276 /*
1264 * Requeue nr_requeue waiters and possibly one more in the case 1277 * Requeue nr_requeue waiters and possibly one more in the case
1265 * of requeue_pi if we couldn't acquire the lock atomically. 1278 * of requeue_pi if we couldn't acquire the lock atomically.
@@ -1735,6 +1748,7 @@ static int futex_wait(u32 __user *uaddr, int fshared,
1735 q.pi_state = NULL; 1748 q.pi_state = NULL;
1736 q.bitset = bitset; 1749 q.bitset = bitset;
1737 q.rt_waiter = NULL; 1750 q.rt_waiter = NULL;
1751 q.requeue_pi_key = NULL;
1738 1752
1739 if (abs_time) { 1753 if (abs_time) {
1740 to = &timeout; 1754 to = &timeout;
@@ -1842,6 +1856,7 @@ static int futex_lock_pi(u32 __user *uaddr, int fshared,
1842 1856
1843 q.pi_state = NULL; 1857 q.pi_state = NULL;
1844 q.rt_waiter = NULL; 1858 q.rt_waiter = NULL;
1859 q.requeue_pi_key = NULL;
1845retry: 1860retry:
1846 q.key = FUTEX_KEY_INIT; 1861 q.key = FUTEX_KEY_INIT;
1847 ret = get_futex_key(uaddr, fshared, &q.key, VERIFY_WRITE); 1862 ret = get_futex_key(uaddr, fshared, &q.key, VERIFY_WRITE);
@@ -2153,15 +2168,16 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, int fshared,
2153 debug_rt_mutex_init_waiter(&rt_waiter); 2168 debug_rt_mutex_init_waiter(&rt_waiter);
2154 rt_waiter.task = NULL; 2169 rt_waiter.task = NULL;
2155 2170
2156 q.pi_state = NULL;
2157 q.bitset = bitset;
2158 q.rt_waiter = &rt_waiter;
2159
2160 key2 = FUTEX_KEY_INIT; 2171 key2 = FUTEX_KEY_INIT;
2161 ret = get_futex_key(uaddr2, fshared, &key2, VERIFY_WRITE); 2172 ret = get_futex_key(uaddr2, fshared, &key2, VERIFY_WRITE);
2162 if (unlikely(ret != 0)) 2173 if (unlikely(ret != 0))
2163 goto out; 2174 goto out;
2164 2175
2176 q.pi_state = NULL;
2177 q.bitset = bitset;
2178 q.rt_waiter = &rt_waiter;
2179 q.requeue_pi_key = &key2;
2180
2165 /* Prepare to wait on uaddr. */ 2181 /* Prepare to wait on uaddr. */
2166 ret = futex_wait_setup(uaddr, val, fshared, &q, &hb); 2182 ret = futex_wait_setup(uaddr, val, fshared, &q, &hb);
2167 if (ret) 2183 if (ret)