From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id ADD9E352005 for ; Tue, 4 Aug 2026 18:02:10 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785866531; cv=none; b=bCA0jxnY0qQzcMcps7iBQv2LMMFeNunkuj/FxF2H9RKNFBFHPnamjUp5FkbHKKeYWwn7glqafSUKSOoDVBEmrhh+4d1Etf//qlMk7f1c6qAPgMhiZK10Z6dxQwgyyv8X1cN0bctaGes8aBaJTjQl0WaswHzhOVrGDP1cIZL6DRM= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785866531; c=relaxed/simple; bh=+9lUZUGEh5VbIlSlJWEjsWctNo4hcZOu59e6dhtOIas=; h=Date:From:To:Cc:Subject:Message-ID:MIME-Version:Content-Type: Content-Disposition; b=efIJ+WmaIWGuT44f3UKvWFLcPVk/+Q4i31YfXBpOGAN4MWjt2QY8DeeBvSZObg/usXuT8jrAhC1FhNVb5zlUcdkGD/LK8IW1b/5ayPcl5UDuKJMS/5gizami0AMy5d7kR60etrVz1gtdg4Ui9s1BgtPuIf7Z3L5fKlgheoq1uYo= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=RG49ryA+; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="RG49ryA+" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 6A8781F000E9; Tue, 4 Aug 2026 18:02:08 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1785866530; bh=6I+sJaGf3LegREDefieBiMm2MMdHfDtTTFCtcfx40jY=; h=Date:From:To:Cc:Subject; b=RG49ryA+bqqgp2BInss5eLvtJVRawxM3IdMyhck18i7iZX55Z1lW+k3QtanpCvkJm AE1yaT1kxtZXQxBdOIAVcAj9cIUIYJ1iQnzdWYvyAQObeX8D83Y27rSTJMnK4yqcR4 MNeeo5Foe0jTQ5fknuxe73RvrejjEnMcC8EiAWUNYqenMFdzOZqj3LF4878CK8QAMF uO8P9aSRKDi2b8e8kdQI+hTC7QRyVzo6B6BcYGiRKNcF6jj9BbHWk/x6RcASzXyyqi Opm5i07BHDHnckvCW1iO+MNEalNRLUdGlZWxUn7u/0AS+3g1NCsqU59VYIRgml1FvC Ns9T53u1lrLlA== Date: Tue, 4 Aug 2026 20:02:05 +0200 From: Ingo Molnar To: Linus Torvalds Cc: linux-kernel@vger.kernel.org, Peter Zijlstra , Thomas Gleixner , Will Deacon , Waiman Long , Boqun Feng Subject: [GIT PULL] futex fix Message-ID: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Linus, Please pull the latest locking/urgent Git tree from: git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git locking-urgent-2026-08-04 for you to fetch changes up to 6d4514ca9cdf61fec4ec634cf50386f6f7e69748: - Fix a robust futexes exit race (Keno Fischer) Thanks, Ingo ------------------> Keno Fischer (1): futex: Prevent robust futex exit race some more kernel/futex/core.c | 85 ++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 58 insertions(+), 27 deletions(-) diff --git a/kernel/futex/core.c b/kernel/futex/core.c index 179b26e9c934..2650d1e52803 100644 --- a/kernel/futex/core.c +++ b/kernel/futex/core.c @@ -982,8 +982,11 @@ static int handle_futex_death(u32 __user *uaddr, struct task_struct *curr, return -1; /* - * Special case for regular (non PI) futexes. The unlock path in - * user space has two race scenarios: + * Special case for regular (non PI) futexes. Ordinarily, we do + * not perform any processing here unless the current thread was + * the owner of the futex (by the TID check below). + * + * However, the unlock path has three race scenarios: * * 1. The unlock path releases the user space futex value and * before it can execute the futex() syscall to wake up @@ -992,42 +995,70 @@ static int handle_futex_death(u32 __user *uaddr, struct task_struct *curr, * 2. A woken up waiter is killed before it can acquire the * futex in user space. * - * In the second case, the wake up notification could be generated - * by the unlock path in user space after setting the futex value - * to zero or by the kernel after setting the OWNER_DIED bit below. + * 3. A woken up waiter is killed in user space after another + * thread has acquired the futex, but before it can set + * FUTEX_WAITERS. + * + * Note that, if userspace uses the FUTEX_ROBUST_UNLOCK flag, we + * will not see case 1 here. + * + * In the second and third case, the wake up notification could + * be generated from any of: + * + * i. An ordinary futex wakeup after unlock (with or + * without FUTEX_ROBUST_UNLOCK) + * ii. A robust wakeup from another thread's death + * iii. A previous round through this special case + * + * As a result, the futex world will be in one of four states: + * + * A. The futex word is 0 (unlocked) + * B. The futex word is owned by another thread + * (FUTEX_WAITERS is not set) + * C. The futex word is owned by another thread + * (FUTEX_WAITERS set) + * D. The futex's owner died and OWNER_DIED is set + * (the owner part of the word is 0) * - * In both cases the TID validation below prevents a wakeup of - * potential waiters which can cause these waiters to block - * forever. + * The key issue is that the kernel usually (at least from + * sources ii. and iii. or when so requested by userspace from + * source i.) only ever wakes *one* waiter at a time. If this + * waiter dies before acquiring the futex (or setting the + * FUTEX_WAITERS bit), the kernel *must* still wake the next + * waiter down the line to uphold the futex invariants and + * avoid lost wakeups. Note we do not need to handle state C, + * as it does not matter to us whether *we* successfully set + * the bit or a third thread did so in the meantime. * - * In both cases the following conditions are met: + * Therefore, in these cases we must issue an additional + * futex_wake(). Note however that we *must not* set OWNER_DIED + * here. Our thread is *not* the owner of the futex. * - * 1) task->futex.robust_list->list_op_pending != NULL - * @pending_op == true - * 2) The owner part of user space futex value == 0 + * Thus to summarize, the conditions for needing the additional + * futex_wake() are: + * + * 1) @pending_op == true (the thread has not finished the + * mutex operation) + * 2) The futex word is in one of the states A, B or D * 3) Regular futex: @pi == false * - * If these conditions are met, it is safe to attempt waking up a - * potential waiter without touching the user space futex value and - * trying to set the OWNER_DIED bit. If the futex value is zero, - * the rest of the user space mutex state is consistent, so a woken - * waiter will just take over the uncontended futex. Setting the - * OWNER_DIED bit would create inconsistent state and malfunction - * of the user space owner died handling. Otherwise, the OWNER_DIED - * bit is already set, and the woken waiter is expected to deal with - * this. + * Note in particular that in all of the states A-D the owner + * portion of the futex word differs from our thread's TID + * (unless the actual owner has the same TID in another PID + * namespace, but we cannot currently distinguish that + * scenario), so this can be a special-case wakeup in the bail + * path of the ordinary TID check. */ owner = uval & FUTEX_TID_MASK; - if (pending_op && !pi && !owner) { - futex_wake(uaddr, FLAGS_SIZE_32 | FLAGS_SHARED, NULL, 1, - FUTEX_BITSET_MATCH_ANY); + if (owner != task_pid_vnr(curr)) { + if (pending_op && !pi && (!owner || !(uval & FUTEX_WAITERS))) { + futex_wake(uaddr, FLAGS_SIZE_32 | FLAGS_SHARED, NULL, 1, + FUTEX_BITSET_MATCH_ANY); + } return 0; } - if (owner != task_pid_vnr(curr)) - return 0; - /* * Ok, this dying thread is truly holding a futex * of interest. Set the OWNER_DIED bit atomically