Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932860AbcDTLwo (ORCPT ); Wed, 20 Apr 2016 07:52:44 -0400 Received: from terminus.zytor.com ([198.137.202.10]:33072 "EHLO terminus.zytor.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932253AbcDTLwm (ORCPT ); Wed, 20 Apr 2016 07:52:42 -0400 Date: Wed, 20 Apr 2016 04:51:43 -0700 From: tip-bot for Sebastian Andrzej Siewior Message-ID: Cc: dave@stgolabs.net, bigeasy@linutronix.de, tglx@linutronix.de, hpa@zytor.com, dvhart@linux.intel.com, peterz@infradead.org, mingo@kernel.org, linux-kernel@vger.kernel.org Reply-To: mingo@kernel.org, linux-kernel@vger.kernel.org, tglx@linutronix.de, hpa@zytor.com, bigeasy@linutronix.de, dave@stgolabs.net, peterz@infradead.org, dvhart@linux.intel.com In-Reply-To: <1460723739-5195-1-git-send-email-bigeasy@linutronix.de> References: <1460723739-5195-1-git-send-email-bigeasy@linutronix.de> To: linux-tip-commits@vger.kernel.org Subject: [tip:locking/urgent] futex: Handle unlock_pi race gracefully Git-Commit-ID: 89e9e66ba1b3bde9d8ea90566c2aee20697ad681 X-Mailer: tip-git-log-daemon Robot-ID: Robot-Unsubscribe: Contact to get blacklisted from these emails MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Content-Type: text/plain; charset=UTF-8 Content-Disposition: inline Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 2817 Lines: 87 Commit-ID: 89e9e66ba1b3bde9d8ea90566c2aee20697ad681 Gitweb: http://git.kernel.org/tip/89e9e66ba1b3bde9d8ea90566c2aee20697ad681 Author: Sebastian Andrzej Siewior AuthorDate: Fri, 15 Apr 2016 14:35:39 +0200 Committer: Thomas Gleixner CommitDate: Wed, 20 Apr 2016 12:33:13 +0200 futex: Handle unlock_pi race gracefully 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 Cc: stable@vger.kernel.org Cc: Davidlohr Bueso Cc: Darren Hart Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1460723739-5195-1-git-send-email-bigeasy@linutronix.de Signed-off-by: Thomas Gleixner --- kernel/futex.c | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/kernel/futex.c b/kernel/futex.c index a5d2e74..fd204e1 100644 --- a/kernel/futex.c +++ b/kernel/futex.c @@ -1295,10 +1295,20 @@ static int wake_futex_pi(u32 __user *uaddr, u32 uval, struct futex_q *this, 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; @@ -2623,6 +2633,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. */