Commit 7193bea53f9d9730bbc859777c2f86c76349914d
Exists in
master
and in
4 other branches
Merge branch 'core-futexes-for-linus' of git://git.kernel.org/pub/scm/linux/kern…
…el/git/tip/linux-2.6-tip * 'core-futexes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip: futex: Detect mismatched requeue targets futex: Correct futex_wait_requeue_pi() commentary
Showing 1 changed file Side-by-side Diff
kernel/futex.c
... | ... | @@ -115,6 +115,9 @@ |
115 | 115 | /* rt_waiter storage for requeue_pi: */ |
116 | 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 | 121 | /* Bitset for the optional bitmasked wakeup */ |
119 | 122 | u32 bitset; |
120 | 123 | }; |
... | ... | @@ -1089,6 +1092,10 @@ |
1089 | 1092 | if (!top_waiter) |
1090 | 1093 | return 0; |
1091 | 1094 | |
1095 | + /* Ensure we requeue to the expected futex. */ | |
1096 | + if (!match_futex(top_waiter->requeue_pi_key, key2)) | |
1097 | + return -EINVAL; | |
1098 | + | |
1092 | 1099 | /* |
1093 | 1100 | * Try to take the lock for top_waiter. Set the FUTEX_WAITERS bit in |
1094 | 1101 | * the contended case or if set_waiters is 1. The pi_state is returned |
... | ... | @@ -1276,6 +1283,12 @@ |
1276 | 1283 | continue; |
1277 | 1284 | } |
1278 | 1285 | |
1286 | + /* Ensure we requeue to the expected futex for requeue_pi. */ | |
1287 | + if (requeue_pi && !match_futex(this->requeue_pi_key, &key2)) { | |
1288 | + ret = -EINVAL; | |
1289 | + break; | |
1290 | + } | |
1291 | + | |
1279 | 1292 | /* |
1280 | 1293 | * Requeue nr_requeue waiters and possibly one more in the case |
1281 | 1294 | * of requeue_pi if we couldn't acquire the lock atomically. |
... | ... | @@ -1751,6 +1764,7 @@ |
1751 | 1764 | q.pi_state = NULL; |
1752 | 1765 | q.bitset = bitset; |
1753 | 1766 | q.rt_waiter = NULL; |
1767 | + q.requeue_pi_key = NULL; | |
1754 | 1768 | |
1755 | 1769 | if (abs_time) { |
1756 | 1770 | to = &timeout; |
... | ... | @@ -1858,6 +1872,7 @@ |
1858 | 1872 | |
1859 | 1873 | q.pi_state = NULL; |
1860 | 1874 | q.rt_waiter = NULL; |
1875 | + q.requeue_pi_key = NULL; | |
1861 | 1876 | retry: |
1862 | 1877 | q.key = FUTEX_KEY_INIT; |
1863 | 1878 | ret = get_futex_key(uaddr, fshared, &q.key, VERIFY_WRITE); |
1864 | 1879 | |
... | ... | @@ -2118,11 +2133,11 @@ |
2118 | 2133 | * We call schedule in futex_wait_queue_me() when we enqueue and return there |
2119 | 2134 | * via the following: |
2120 | 2135 | * 1) wakeup on uaddr2 after an atomic lock acquisition by futex_requeue() |
2121 | - * 2) wakeup on uaddr2 after a requeue and subsequent unlock | |
2122 | - * 3) signal (before or after requeue) | |
2123 | - * 4) timeout (before or after requeue) | |
2136 | + * 2) wakeup on uaddr2 after a requeue | |
2137 | + * 3) signal | |
2138 | + * 4) timeout | |
2124 | 2139 | * |
2125 | - * If 3, we setup a restart_block with futex_wait_requeue_pi() as the function. | |
2140 | + * If 3, cleanup and return -ERESTARTNOINTR. | |
2126 | 2141 | * |
2127 | 2142 | * If 2, we may then block on trying to take the rt_mutex and return via: |
2128 | 2143 | * 5) successful lock |
... | ... | @@ -2130,7 +2145,7 @@ |
2130 | 2145 | * 7) timeout |
2131 | 2146 | * 8) other lock acquisition failure |
2132 | 2147 | * |
2133 | - * If 6, we setup a restart_block with futex_lock_pi() as the function. | |
2148 | + * If 6, return -EWOULDBLOCK (restarting the syscall would do the same). | |
2134 | 2149 | * |
2135 | 2150 | * If 4 or 7, we cleanup and return with -ETIMEDOUT. |
2136 | 2151 | * |
2137 | 2152 | |
... | ... | @@ -2169,15 +2184,16 @@ |
2169 | 2184 | debug_rt_mutex_init_waiter(&rt_waiter); |
2170 | 2185 | rt_waiter.task = NULL; |
2171 | 2186 | |
2172 | - q.pi_state = NULL; | |
2173 | - q.bitset = bitset; | |
2174 | - q.rt_waiter = &rt_waiter; | |
2175 | - | |
2176 | 2187 | key2 = FUTEX_KEY_INIT; |
2177 | 2188 | ret = get_futex_key(uaddr2, fshared, &key2, VERIFY_WRITE); |
2178 | 2189 | if (unlikely(ret != 0)) |
2179 | 2190 | goto out; |
2180 | 2191 | |
2192 | + q.pi_state = NULL; | |
2193 | + q.bitset = bitset; | |
2194 | + q.rt_waiter = &rt_waiter; | |
2195 | + q.requeue_pi_key = &key2; | |
2196 | + | |
2181 | 2197 | /* Prepare to wait on uaddr. */ |
2182 | 2198 | ret = futex_wait_setup(uaddr, val, fshared, &q, &hb); |
2183 | 2199 | if (ret) |
... | ... | @@ -2248,14 +2264,11 @@ |
2248 | 2264 | rt_mutex_unlock(pi_mutex); |
2249 | 2265 | } else if (ret == -EINTR) { |
2250 | 2266 | /* |
2251 | - * We've already been requeued, but we have no way to | |
2252 | - * restart by calling futex_lock_pi() directly. We | |
2253 | - * could restart the syscall, but that will look at | |
2254 | - * the user space value and return right away. So we | |
2255 | - * drop back with EWOULDBLOCK to tell user space that | |
2256 | - * "val" has been changed. That's the same what the | |
2257 | - * restart of the syscall would do in | |
2258 | - * futex_wait_setup(). | |
2267 | + * We've already been requeued, but cannot restart by calling | |
2268 | + * futex_lock_pi() directly. We could restart this syscall, but | |
2269 | + * it would detect that the user space "val" changed and return | |
2270 | + * -EWOULDBLOCK. Save the overhead of the restart and return | |
2271 | + * -EWOULDBLOCK directly. | |
2259 | 2272 | */ |
2260 | 2273 | ret = -EWOULDBLOCK; |
2261 | 2274 | } |