diff options
author | Darren Hart <dvhart@linux.intel.com> | 2010-10-17 11:35:04 -0400 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2010-10-19 05:41:54 -0400 |
commit | 7ada876a8703f23befbb20a7465a702ee39b1704 (patch) | |
tree | adee9cf8676fed56a0a6ad1d270ae5fb84d32553 /kernel/futex.c | |
parent | 2b666ca4a68cbc22483b0f2e1ba3c0e59b01ae9e (diff) |
futex: Fix errors in nested key ref-counting
futex_wait() is leaking key references due to futex_wait_setup()
acquiring an additional reference via the queue_lock() routine. The
nested key ref-counting has been masking bugs and complicating code
analysis. queue_lock() is only called with a previously ref-counted
key, so remove the additional ref-counting from the queue_(un)lock()
functions.
Also futex_wait_requeue_pi() drops one key reference too many in
unqueue_me_pi(). Remove the key reference handling from
unqueue_me_pi(). This was paired with a queue_lock() in
futex_lock_pi(), so the count remains unchanged.
Document remaining nested key ref-counting sites.
Signed-off-by: Darren Hart <dvhart@linux.intel.com>
Reported-and-tested-by: Matthieu Fertré<matthieu.fertre@kerlabs.com>
Reported-by: Louis Rilling<louis.rilling@kerlabs.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Eric Dumazet <eric.dumazet@gmail.com>
Cc: John Kacur <jkacur@redhat.com>
Cc: Rusty Russell <rusty@rustcorp.com.au>
LKML-Reference: <4CBB17A8.70401@linux.intel.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: stable@kernel.org
Diffstat (limited to 'kernel/futex.c')
-rw-r--r-- | kernel/futex.c | 31 |
1 files changed, 16 insertions, 15 deletions
diff --git a/kernel/futex.c b/kernel/futex.c index 6a3a5fa1526d..e328f574c97c 100644 --- a/kernel/futex.c +++ b/kernel/futex.c | |||
@@ -1363,7 +1363,6 @@ static inline struct futex_hash_bucket *queue_lock(struct futex_q *q) | |||
1363 | { | 1363 | { |
1364 | struct futex_hash_bucket *hb; | 1364 | struct futex_hash_bucket *hb; |
1365 | 1365 | ||
1366 | get_futex_key_refs(&q->key); | ||
1367 | hb = hash_futex(&q->key); | 1366 | hb = hash_futex(&q->key); |
1368 | q->lock_ptr = &hb->lock; | 1367 | q->lock_ptr = &hb->lock; |
1369 | 1368 | ||
@@ -1375,7 +1374,6 @@ static inline void | |||
1375 | queue_unlock(struct futex_q *q, struct futex_hash_bucket *hb) | 1374 | queue_unlock(struct futex_q *q, struct futex_hash_bucket *hb) |
1376 | { | 1375 | { |
1377 | spin_unlock(&hb->lock); | 1376 | spin_unlock(&hb->lock); |
1378 | drop_futex_key_refs(&q->key); | ||
1379 | } | 1377 | } |
1380 | 1378 | ||
1381 | /** | 1379 | /** |
@@ -1480,8 +1478,6 @@ static void unqueue_me_pi(struct futex_q *q) | |||
1480 | q->pi_state = NULL; | 1478 | q->pi_state = NULL; |
1481 | 1479 | ||
1482 | spin_unlock(q->lock_ptr); | 1480 | spin_unlock(q->lock_ptr); |
1483 | |||
1484 | drop_futex_key_refs(&q->key); | ||
1485 | } | 1481 | } |
1486 | 1482 | ||
1487 | /* | 1483 | /* |
@@ -1812,7 +1808,10 @@ static int futex_wait(u32 __user *uaddr, int fshared, | |||
1812 | } | 1808 | } |
1813 | 1809 | ||
1814 | retry: | 1810 | retry: |
1815 | /* Prepare to wait on uaddr. */ | 1811 | /* |
1812 | * Prepare to wait on uaddr. On success, holds hb lock and increments | ||
1813 | * q.key refs. | ||
1814 | */ | ||
1816 | ret = futex_wait_setup(uaddr, val, fshared, &q, &hb); | 1815 | ret = futex_wait_setup(uaddr, val, fshared, &q, &hb); |
1817 | if (ret) | 1816 | if (ret) |
1818 | goto out; | 1817 | goto out; |
@@ -1822,24 +1821,23 @@ retry: | |||
1822 | 1821 | ||
1823 | /* If we were woken (and unqueued), we succeeded, whatever. */ | 1822 | /* If we were woken (and unqueued), we succeeded, whatever. */ |
1824 | ret = 0; | 1823 | ret = 0; |
1824 | /* unqueue_me() drops q.key ref */ | ||
1825 | if (!unqueue_me(&q)) | 1825 | if (!unqueue_me(&q)) |
1826 | goto out_put_key; | 1826 | goto out; |
1827 | ret = -ETIMEDOUT; | 1827 | ret = -ETIMEDOUT; |
1828 | if (to && !to->task) | 1828 | if (to && !to->task) |
1829 | goto out_put_key; | 1829 | goto out; |
1830 | 1830 | ||
1831 | /* | 1831 | /* |
1832 | * We expect signal_pending(current), but we might be the | 1832 | * We expect signal_pending(current), but we might be the |
1833 | * victim of a spurious wakeup as well. | 1833 | * victim of a spurious wakeup as well. |
1834 | */ | 1834 | */ |
1835 | if (!signal_pending(current)) { | 1835 | if (!signal_pending(current)) |
1836 | put_futex_key(fshared, &q.key); | ||
1837 | goto retry; | 1836 | goto retry; |
1838 | } | ||
1839 | 1837 | ||
1840 | ret = -ERESTARTSYS; | 1838 | ret = -ERESTARTSYS; |
1841 | if (!abs_time) | 1839 | if (!abs_time) |
1842 | goto out_put_key; | 1840 | goto out; |
1843 | 1841 | ||
1844 | restart = ¤t_thread_info()->restart_block; | 1842 | restart = ¤t_thread_info()->restart_block; |
1845 | restart->fn = futex_wait_restart; | 1843 | restart->fn = futex_wait_restart; |
@@ -1856,8 +1854,6 @@ retry: | |||
1856 | 1854 | ||
1857 | ret = -ERESTART_RESTARTBLOCK; | 1855 | ret = -ERESTART_RESTARTBLOCK; |
1858 | 1856 | ||
1859 | out_put_key: | ||
1860 | put_futex_key(fshared, &q.key); | ||
1861 | out: | 1857 | out: |
1862 | if (to) { | 1858 | if (to) { |
1863 | hrtimer_cancel(&to->timer); | 1859 | hrtimer_cancel(&to->timer); |
@@ -2236,7 +2232,10 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, int fshared, | |||
2236 | q.rt_waiter = &rt_waiter; | 2232 | q.rt_waiter = &rt_waiter; |
2237 | q.requeue_pi_key = &key2; | 2233 | q.requeue_pi_key = &key2; |
2238 | 2234 | ||
2239 | /* Prepare to wait on uaddr. */ | 2235 | /* |
2236 | * Prepare to wait on uaddr. On success, increments q.key (key1) ref | ||
2237 | * count. | ||
2238 | */ | ||
2240 | ret = futex_wait_setup(uaddr, val, fshared, &q, &hb); | 2239 | ret = futex_wait_setup(uaddr, val, fshared, &q, &hb); |
2241 | if (ret) | 2240 | if (ret) |
2242 | goto out_key2; | 2241 | goto out_key2; |
@@ -2254,7 +2253,9 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, int fshared, | |||
2254 | * In order for us to be here, we know our q.key == key2, and since | 2253 | * In order for us to be here, we know our q.key == key2, and since |
2255 | * we took the hb->lock above, we also know that futex_requeue() has | 2254 | * we took the hb->lock above, we also know that futex_requeue() has |
2256 | * completed and we no longer have to concern ourselves with a wakeup | 2255 | * completed and we no longer have to concern ourselves with a wakeup |
2257 | * race with the atomic proxy lock acquition by the requeue code. | 2256 | * race with the atomic proxy lock acquisition by the requeue code. The |
2257 | * futex_requeue dropped our key1 reference and incremented our key2 | ||
2258 | * reference count. | ||
2258 | */ | 2259 | */ |
2259 | 2260 | ||
2260 | /* Check if the requeue code acquired the second futex for us. */ | 2261 | /* Check if the requeue code acquired the second futex for us. */ |