diff options
Diffstat (limited to 'kernel/futex.c')
-rw-r--r-- | kernel/futex.c | 34 |
1 files changed, 21 insertions, 13 deletions
diff --git a/kernel/futex.c b/kernel/futex.c index 157bfcd725b8..476603afd147 100644 --- a/kernel/futex.c +++ b/kernel/futex.c | |||
@@ -199,6 +199,7 @@ static void drop_futex_key_refs(union futex_key *key) | |||
199 | * @uaddr: virtual address of the futex | 199 | * @uaddr: virtual address of the futex |
200 | * @fshared: 0 for a PROCESS_PRIVATE futex, 1 for PROCESS_SHARED | 200 | * @fshared: 0 for a PROCESS_PRIVATE futex, 1 for PROCESS_SHARED |
201 | * @key: address where result is stored. | 201 | * @key: address where result is stored. |
202 | * @rw: mapping needs to be read/write (values: VERIFY_READ, VERIFY_WRITE) | ||
202 | * | 203 | * |
203 | * Returns a negative error code or 0 | 204 | * Returns a negative error code or 0 |
204 | * The key words are stored in *key on success. | 205 | * The key words are stored in *key on success. |
@@ -209,7 +210,8 @@ static void drop_futex_key_refs(union futex_key *key) | |||
209 | * | 210 | * |
210 | * lock_page() might sleep, the caller should not hold a spinlock. | 211 | * lock_page() might sleep, the caller should not hold a spinlock. |
211 | */ | 212 | */ |
212 | static int get_futex_key(u32 __user *uaddr, int fshared, union futex_key *key) | 213 | static int |
214 | get_futex_key(u32 __user *uaddr, int fshared, union futex_key *key, int rw) | ||
213 | { | 215 | { |
214 | unsigned long address = (unsigned long)uaddr; | 216 | unsigned long address = (unsigned long)uaddr; |
215 | struct mm_struct *mm = current->mm; | 217 | struct mm_struct *mm = current->mm; |
@@ -232,7 +234,7 @@ static int get_futex_key(u32 __user *uaddr, int fshared, union futex_key *key) | |||
232 | * but access_ok() should be faster than find_vma() | 234 | * but access_ok() should be faster than find_vma() |
233 | */ | 235 | */ |
234 | if (!fshared) { | 236 | if (!fshared) { |
235 | if (unlikely(!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))) | 237 | if (unlikely(!access_ok(rw, uaddr, sizeof(u32)))) |
236 | return -EFAULT; | 238 | return -EFAULT; |
237 | key->private.mm = mm; | 239 | key->private.mm = mm; |
238 | key->private.address = address; | 240 | key->private.address = address; |
@@ -241,7 +243,7 @@ static int get_futex_key(u32 __user *uaddr, int fshared, union futex_key *key) | |||
241 | } | 243 | } |
242 | 244 | ||
243 | again: | 245 | again: |
244 | err = get_user_pages_fast(address, 1, 0, &page); | 246 | err = get_user_pages_fast(address, 1, rw == VERIFY_WRITE, &page); |
245 | if (err < 0) | 247 | if (err < 0) |
246 | return err; | 248 | return err; |
247 | 249 | ||
@@ -834,7 +836,7 @@ static int futex_wake(u32 __user *uaddr, int fshared, int nr_wake, u32 bitset) | |||
834 | if (!bitset) | 836 | if (!bitset) |
835 | return -EINVAL; | 837 | return -EINVAL; |
836 | 838 | ||
837 | ret = get_futex_key(uaddr, fshared, &key); | 839 | ret = get_futex_key(uaddr, fshared, &key, VERIFY_READ); |
838 | if (unlikely(ret != 0)) | 840 | if (unlikely(ret != 0)) |
839 | goto out; | 841 | goto out; |
840 | 842 | ||
@@ -880,10 +882,10 @@ futex_wake_op(u32 __user *uaddr1, int fshared, u32 __user *uaddr2, | |||
880 | int ret, op_ret; | 882 | int ret, op_ret; |
881 | 883 | ||
882 | retry: | 884 | retry: |
883 | ret = get_futex_key(uaddr1, fshared, &key1); | 885 | ret = get_futex_key(uaddr1, fshared, &key1, VERIFY_READ); |
884 | if (unlikely(ret != 0)) | 886 | if (unlikely(ret != 0)) |
885 | goto out; | 887 | goto out; |
886 | ret = get_futex_key(uaddr2, fshared, &key2); | 888 | ret = get_futex_key(uaddr2, fshared, &key2, VERIFY_WRITE); |
887 | if (unlikely(ret != 0)) | 889 | if (unlikely(ret != 0)) |
888 | goto out_put_key1; | 890 | goto out_put_key1; |
889 | 891 | ||
@@ -1131,10 +1133,11 @@ retry: | |||
1131 | pi_state = NULL; | 1133 | pi_state = NULL; |
1132 | } | 1134 | } |
1133 | 1135 | ||
1134 | ret = get_futex_key(uaddr1, fshared, &key1); | 1136 | ret = get_futex_key(uaddr1, fshared, &key1, VERIFY_READ); |
1135 | if (unlikely(ret != 0)) | 1137 | if (unlikely(ret != 0)) |
1136 | goto out; | 1138 | goto out; |
1137 | ret = get_futex_key(uaddr2, fshared, &key2); | 1139 | ret = get_futex_key(uaddr2, fshared, &key2, |
1140 | requeue_pi ? VERIFY_WRITE : VERIFY_READ); | ||
1138 | if (unlikely(ret != 0)) | 1141 | if (unlikely(ret != 0)) |
1139 | goto out_put_key1; | 1142 | goto out_put_key1; |
1140 | 1143 | ||
@@ -1267,7 +1270,12 @@ retry_private: | |||
1267 | out_unlock: | 1270 | out_unlock: |
1268 | double_unlock_hb(hb1, hb2); | 1271 | double_unlock_hb(hb1, hb2); |
1269 | 1272 | ||
1270 | /* drop_futex_key_refs() must be called outside the spinlocks. */ | 1273 | /* |
1274 | * drop_futex_key_refs() must be called outside the spinlocks. During | ||
1275 | * the requeue we moved futex_q's from the hash bucket at key1 to the | ||
1276 | * one at key2 and updated their key pointer. We no longer need to | ||
1277 | * hold the references to key1. | ||
1278 | */ | ||
1271 | while (--drop_count >= 0) | 1279 | while (--drop_count >= 0) |
1272 | drop_futex_key_refs(&key1); | 1280 | drop_futex_key_refs(&key1); |
1273 | 1281 | ||
@@ -1660,7 +1668,7 @@ static int futex_wait_setup(u32 __user *uaddr, u32 val, int fshared, | |||
1660 | */ | 1668 | */ |
1661 | retry: | 1669 | retry: |
1662 | q->key = FUTEX_KEY_INIT; | 1670 | q->key = FUTEX_KEY_INIT; |
1663 | ret = get_futex_key(uaddr, fshared, &q->key); | 1671 | ret = get_futex_key(uaddr, fshared, &q->key, VERIFY_READ); |
1664 | if (unlikely(ret != 0)) | 1672 | if (unlikely(ret != 0)) |
1665 | return ret; | 1673 | return ret; |
1666 | 1674 | ||
@@ -1819,7 +1827,7 @@ static int futex_lock_pi(u32 __user *uaddr, int fshared, | |||
1819 | q.rt_waiter = NULL; | 1827 | q.rt_waiter = NULL; |
1820 | retry: | 1828 | retry: |
1821 | q.key = FUTEX_KEY_INIT; | 1829 | q.key = FUTEX_KEY_INIT; |
1822 | ret = get_futex_key(uaddr, fshared, &q.key); | 1830 | ret = get_futex_key(uaddr, fshared, &q.key, VERIFY_WRITE); |
1823 | if (unlikely(ret != 0)) | 1831 | if (unlikely(ret != 0)) |
1824 | goto out; | 1832 | goto out; |
1825 | 1833 | ||
@@ -1960,7 +1968,7 @@ retry: | |||
1960 | if ((uval & FUTEX_TID_MASK) != task_pid_vnr(current)) | 1968 | if ((uval & FUTEX_TID_MASK) != task_pid_vnr(current)) |
1961 | return -EPERM; | 1969 | return -EPERM; |
1962 | 1970 | ||
1963 | ret = get_futex_key(uaddr, fshared, &key); | 1971 | ret = get_futex_key(uaddr, fshared, &key, VERIFY_WRITE); |
1964 | if (unlikely(ret != 0)) | 1972 | if (unlikely(ret != 0)) |
1965 | goto out; | 1973 | goto out; |
1966 | 1974 | ||
@@ -2171,7 +2179,7 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, int fshared, | |||
2171 | q.rt_waiter = &rt_waiter; | 2179 | q.rt_waiter = &rt_waiter; |
2172 | 2180 | ||
2173 | key2 = FUTEX_KEY_INIT; | 2181 | key2 = FUTEX_KEY_INIT; |
2174 | ret = get_futex_key(uaddr2, fshared, &key2); | 2182 | ret = get_futex_key(uaddr2, fshared, &key2, VERIFY_WRITE); |
2175 | if (unlikely(ret != 0)) | 2183 | if (unlikely(ret != 0)) |
2176 | goto out; | 2184 | goto out; |
2177 | 2185 | ||