Patch "futex: Handle unlock_pi race gracefully" has been added to the 4.5-stable tree
This is a note to let you know that I've just added the patch titled
futex: Handle unlock_pi race gracefully
to the 4.5-stable tree which can be found at:
http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary
The filename of the patch is:
futex-handle-unlock_pi-race-gracefully.patch
and it can be found in the queue-4.5 subdirectory.
If you, or anyone else, feels it should not be added to the stable tree, please let <[email protected]> know about it.
Quoted 1 line
From
89e9e66ba1b3bde9d8ea90566c2aee20697ad681Mon Sep 17 00:00:00 2001
From: Sebastian Andrzej Siewior <[email protected]>
Date: Fri, 15 Apr 2016 14:35:39 +0200
Subject: futex: Handle unlock_pi race gracefully
From: Sebastian Andrzej Siewior <[email protected]>
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 ]
--- kernel/futex.c | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-)
kernel/futex.c +22 -3
@@ -1212,10 +1212,20 @@ static int wake_futex_pi(u32 __user *uadif (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. */
Patches currently in stable-queue which might be from [email protected] are
queue-4.5/futex-handle-unlock_pi-race-gracefully.patch queue-4.5/futex-acknowledge-a-new-waiter-in-counter-before-plist.patch