lkml.org 
[lkml]   [2016]   [May]   [2]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 4.5 046/200] futex: Handle unlock_pi race gracefully
    Date
    4.5-stable review patch.  If anyone has any objections, please let me know.

    ------------------

    From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>

    commit 89e9e66ba1b3bde9d8ea90566c2aee20697ad681 upstream.

    If userspace calls UNLOCK_PI unconditionally without trying the TID -> 0
    transition in user space first then the user space value might not have the
    waiters bit set. This opens the following race:

    CPU0 CPU1
    uval = get_user(futex)
    lock(hb)
    lock(hb)
    futex |= FUTEX_WAITERS
    ....
    unlock(hb)

    cmpxchg(futex, uval, newval)

    So the cmpxchg fails and returns -EINVAL to user space, which is wrong because
    the futex value is valid.

    To handle this (yes, yet another) corner case gracefully, check for a flag
    change and retry.

    [ tglx: Massaged changelog and slightly reworked implementation ]

    Fixes: ccf9e6a80d9e ("futex: Make unlock_pi more robust")
    Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
    Cc: Davidlohr Bueso <dave@stgolabs.net>
    Cc: Darren Hart <dvhart@linux.intel.com>
    Cc: Peter Zijlstra <peterz@infradead.org>
    Link: http://lkml.kernel.org/r/1460723739-5195-1-git-send-email-bigeasy@linutronix.de
    Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

    ---
    kernel/futex.c | 25 ++++++++++++++++++++++---
    1 file changed, 22 insertions(+), 3 deletions(-)

    --- a/kernel/futex.c
    +++ b/kernel/futex.c
    @@ -1212,10 +1212,20 @@ static int wake_futex_pi(u32 __user *uad
    if (unlikely(should_fail_futex(true)))
    ret = -EFAULT;

    - if (cmpxchg_futex_value_locked(&curval, uaddr, uval, newval))
    + if (cmpxchg_futex_value_locked(&curval, uaddr, uval, newval)) {
    ret = -EFAULT;
    - else if (curval != uval)
    - ret = -EINVAL;
    + } else if (curval != uval) {
    + /*
    + * If a unconditional UNLOCK_PI operation (user space did not
    + * try the TID->0 transition) raced with a waiter setting the
    + * FUTEX_WAITERS flag between get_user() and locking the hash
    + * bucket lock, retry the operation.
    + */
    + if ((FUTEX_TID_MASK & curval) == uval)
    + ret = -EAGAIN;
    + else
    + ret = -EINVAL;
    + }
    if (ret) {
    raw_spin_unlock_irq(&pi_state->pi_mutex.wait_lock);
    return ret;
    @@ -2536,6 +2546,15 @@ retry:
    if (ret == -EFAULT)
    goto pi_faulted;
    /*
    + * A unconditional UNLOCK_PI op raced against a waiter
    + * setting the FUTEX_WAITERS bit. Try again.
    + */
    + if (ret == -EAGAIN) {
    + spin_unlock(&hb->lock);
    + put_futex_key(&key);
    + goto retry;
    + }
    + /*
    * wake_futex_pi has detected invalid state. Tell user
    * space.
    */

    \
     
     \ /
      Last update: 2016-05-03 03:01    [W:4.072 / U:0.036 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site