From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from galois.linutronix.de (Galois.linutronix.de [193.142.43.55]) (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 855F132B118 for ; Fri, 17 Jul 2026 09:38:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=193.142.43.55 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784281114; cv=none; b=ZegYVmxcSf4Tu+TGMX0LimUu35nJEEHm77nFwBetBjpCyWbmvCk5VC3hDfvBsOgq/YV1JgfRoTyDUpjyO4J2MqkY95IhZJwX61GI47tsN+ZOERklzkgZ+iDz9etG8ZNYUjhhUtv6epUVq/BOP+2OTobXnpLnvjn3iJa52ywtJ6M= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784281114; c=relaxed/simple; bh=TLbxwrEGTlv4tme7oP7wP+zk6Y3gctPVHLd/SlOc3Hg=; h=Date:From:To:Cc:Subject:Message-ID:References:MIME-Version: Content-Type:Content-Disposition:In-Reply-To; b=KEKlmIIk+hZZ3Ygq+9w0XoChaX5Ylie3ooB9RfOoxrDqIlrTtkEn0iJlomciP7Lna1tTe9PJz6RezrLYlk85MstIcUrXqyCbh9J0vkN4CvE3aGL69/SVD2aZ4IppigS/NN2kMYy6JuSr/94F0eT+O+X6sLHuS55gIpCWnQXPnvU= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linutronix.de; spf=pass smtp.mailfrom=linutronix.de; dkim=pass (2048-bit key) header.d=linutronix.de header.i=@linutronix.de header.b=gvHeR8jS; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b=4dLwbHnc; arc=none smtp.client-ip=193.142.43.55 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linutronix.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linutronix.de Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="gvHeR8jS"; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="4dLwbHnc" Date: Fri, 17 Jul 2026 11:38:29 +0200 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1784281111; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: in-reply-to:in-reply-to:references:references; bh=LojD36OYj2ADgDjPR3/QIh48N/PiYQxgXj2/z6Ro/bc=; b=gvHeR8jSIcQwCkZw2VfFQFdac2dMtyeh6oA+0zWtcxIPo13dwK5n9Sopbhr+cCgZvBDJkH tCEukh7Dpr2CigFZTk4ClDoCalhgmyrdKjd4lKGfH8dUtPb9qqetxl/cteIFCtjDYm0RBc JXvS8MlMMs2xir71WcHUyZ8+AgHxVj18rQ1iViChm9KPcxOUTgkvaXBxUcR0FcJkehT+VZ a+TbnLZonMCMNsITKulKzyZz13+kU7frrlz3kI9/wmYMLDEzkNOTd7qeYWIA/O6j7S4onl DtlUJBiQ4mndsBBiIT7/EazZff0HQv4+S6B8FNmDNSsDcri1j0P+oT8op1G5Yg== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1784281111; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: in-reply-to:in-reply-to:references:references; bh=LojD36OYj2ADgDjPR3/QIh48N/PiYQxgXj2/z6Ro/bc=; b=4dLwbHncGfhx7sH2pFxkO5JWlf9C4EGSlN6KQ2Lz4Xfg5mvnBKnCCMvyIS1sMJcQhiJqTz 85T17wLABMVqa+Ag== From: Sebastian Andrzej Siewior To: Yao Kai Cc: linux-kernel@vger.kernel.org, tglx@kernel.org, mingo@redhat.com, peterz@infradead.org, dvhart@infradead.org, dave@stgolabs.net, andrealmeid@igalia.com, liuyongqiang13@huawei.com Subject: Re: [PATCH 2/2] futex/requeue: Prevent rcuwait use-after-free during requeue PI Message-ID: <20260717093829.K07Gk1tS@linutronix.de> References: <20260717084922.4153317-1-yaokai34@huawei.com> <20260717084922.4153317-3-yaokai34@huawei.com> 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=utf-8 Content-Disposition: inline In-Reply-To: <20260717084922.4153317-3-yaokai34@huawei.com> On 2026-07-17 16:49:22 [+0800], Yao Kai wrote: > On PREEMPT_RT, FUTEX_CMP_REQUEUE_PI can trigger a KASAN report: > > BUG: KASAN: slab-out-of-bounds in _raw_spin_lock_irqsave+0x76/0xe0 > Call Trace: > _raw_spin_lock_irqsave+0x76/0xe0 > try_to_wake_up+0xab/0x1540 > rcuwait_wake_up+0x39/0x60 > futex_requeue+0x18c3/0x1e10 > > The futex_q used by futex_wait_requeue_pi() is allocated on the waiter's > stack. An early wakeup can race with a PI requeue as follows: > > waiter requeue task > ------ ------------ > futex_wait_requeue_pi() > futex_do_wait() > schedule() > > * timeout/signal wakes waiter * > > futex_requeue_pi_wakeup_sync() > IN_PROGRESS -> WAIT > rcuwait_wait_event() > requeue_pi_wake_futex() > task = READ_ONCE(q->task) > futex_requeue_pi_complete() > WAIT -> LOCKED > return LOCKED > return > // q lifetime ends > rcuwait_wake_up() > > futex_requeue_pi_complete() publishes LOCKED before calling > rcuwait_wake_up(). Once the waiter observes LOCKED, it can return from > futex_wait_requeue_pi() and let q go out of scope before rcuwait_wake_up() > reads q->requeue_wait.task and passes the stale pointer to > try_to_wake_up(). > > Skip rcuwait_wake_up() for Q_REQUEUE_PI_LOCKED. requeue_pi_wake_futex() > already saves q->task before publishing LOCKED and wakes the saved task > afterward. > > Fixes: 07d91ef510fb1 ("futex: Prevent requeue_pi() lock nesting issue on RT") > Cc: stable@vger.kernel.org > Signed-off-by: Yao Kai > --- > kernel/futex/requeue.c | 9 +++++++-- > 1 file changed, 7 insertions(+), 2 deletions(-) > > diff --git a/kernel/futex/requeue.c b/kernel/futex/requeue.c > index abc652b5b2dd..59e587775d9b 100644 > --- a/kernel/futex/requeue.c > +++ b/kernel/futex/requeue.c > @@ -155,8 +155,13 @@ static inline void futex_requeue_pi_complete(struct futex_q *q, int locked) > } while (!atomic_try_cmpxchg(&q->requeue_state, &old, new)); > > #ifdef CONFIG_PREEMPT_RT > - /* If the waiter interleaved with the requeue let it know */ > - if (unlikely(old == Q_REQUEUE_PI_WAIT)) > + /* > + * If the waiter interleaved with the requeue, let it know. For LOCKED, > + * q may already be invalid, so requeue_pi_wake_futex() wakes the saved > + * task instead. > + */ > + if (unlikely(old == Q_REQUEUE_PI_WAIT) && > + new != Q_REQUEUE_PI_LOCKED) > rcuwait_wake_up(&q->requeue_wait); Your whole assumption is based on the requeue_state in futex_requeue_pi_wakeup_sync() changes from Q_REQUEUE_PI_IN_PROGRESS to Q_REQUEUE_PI_WAIT and the rcuwait_wait_event() does not wait because the condition becomes true before that happens. So the rcuwait_wake_up() could access q.requeue_wait which is allocated on behalf of the waiter which is gone. Certainly possible. But if we skip the wait in thise case we probably miss the 99% cases where the waiter did wait, no? This looks similar to commit b549113738e8c ("futex: Prevent use-after-free during requeue-PI"). > #endif > } Sebastian