futex: Detect mismatched requeue targets
[safe/jmp/linux-2.6] / kernel / futex.c
index d077201..f0dea28 100644 (file)
@@ -115,6 +115,9 @@ struct futex_q {
        /* rt_waiter storage for requeue_pi: */
        struct rt_mutex_waiter *rt_waiter;
 
+       /* The expected requeue pi target futex key: */
+       union futex_key *requeue_pi_key;
+
        /* Bitset for the optional bitmasked wakeup */
        u32 bitset;
 };
@@ -1080,6 +1083,10 @@ static int futex_proxy_trylock_atomic(u32 __user *pifutex,
        if (!top_waiter)
                return 0;
 
+       /* Ensure we requeue to the expected futex. */
+       if (!match_futex(top_waiter->requeue_pi_key, key2))
+               return -EINVAL;
+
        /*
         * Try to take the lock for top_waiter.  Set the FUTEX_WAITERS bit in
         * the contended case or if set_waiters is 1.  The pi_state is returned
@@ -1260,6 +1267,12 @@ retry_private:
                        continue;
                }
 
+               /* Ensure we requeue to the expected futex for requeue_pi. */
+               if (requeue_pi && !match_futex(this->requeue_pi_key, &key2)) {
+                       ret = -EINVAL;
+                       break;
+               }
+
                /*
                 * Requeue nr_requeue waiters and possibly one more in the case
                 * of requeue_pi if we couldn't acquire the lock atomically.
@@ -1735,6 +1748,7 @@ static int futex_wait(u32 __user *uaddr, int fshared,
        q.pi_state = NULL;
        q.bitset = bitset;
        q.rt_waiter = NULL;
+       q.requeue_pi_key = NULL;
 
        if (abs_time) {
                to = &timeout;
@@ -1842,6 +1856,7 @@ static int futex_lock_pi(u32 __user *uaddr, int fshared,
 
        q.pi_state = NULL;
        q.rt_waiter = NULL;
+       q.requeue_pi_key = NULL;
 retry:
        q.key = FUTEX_KEY_INIT;
        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,
        debug_rt_mutex_init_waiter(&rt_waiter);
        rt_waiter.task = NULL;
 
-       q.pi_state = NULL;
-       q.bitset = bitset;
-       q.rt_waiter = &rt_waiter;
-
        key2 = FUTEX_KEY_INIT;
        ret = get_futex_key(uaddr2, fshared, &key2, VERIFY_WRITE);
        if (unlikely(ret != 0))
                goto out;
 
+       q.pi_state = NULL;
+       q.bitset = bitset;
+       q.rt_waiter = &rt_waiter;
+       q.requeue_pi_key = &key2;
+
        /* Prepare to wait on uaddr. */
        ret = futex_wait_setup(uaddr, val, fshared, &q, &hb);
        if (ret)