From: Waiman Long <llong@redhat.com>
To: Peter Zijlstra <peterz@infradead.org>,
Ingo Molnar <mingo@redhat.com>, Will Deacon <will@kernel.org>,
Boqun Feng <boqun.feng@gmail.com>,
Jonathan Corbet <corbet@lwn.net>
Cc: linux-kernel@vger.kernel.org,
Linus Torvalds <torvalds@linux-foundation.org>,
Jann Horn <jannh@google.com>
Subject: Re: [PATCH] locking/mutex: Disable preemption in __mutex_unlock_slowpath()
Date: Wed, 9 Jul 2025 14:19:06 -0400 [thread overview]
Message-ID: <4fcb119f-9a5d-417b-aeaa-977a3a794b4c@redhat.com> (raw)
In-Reply-To: <20250709180550.147205-1-longman@redhat.com>
On 7/9/25 2:05 PM, Waiman Long wrote:
> Jann reported a possible UAF scenario where a task in the mutex_unlock()
> path had released the mutex and was about to acquire the wait_lock
> to check out the waiters. In the interim, another task could come in,
> acquire and release the mutex and then free the memory object holding
> the mutex after that.
>
> Thread A Thread B
> ======== ========
> eventpoll_release_file
> mutex_lock
> [success on trylock fastpath]
> __ep_remove
> ep_refcount_dec_and_test
> [drop refcount from 2 to 1]
>
> ep_eventpoll_release
> ep_clear_and_put
> mutex_lock
> __mutex_lock_slowpath
> __mutex_lock
> __mutex_lock_common
> __mutex_add_waiter
> [enqueue waiter]
> [set MUTEX_FLAG_WAITERS]
>
> mutex_unlock
> __mutex_unlock_slowpath
> atomic_long_try_cmpxchg_release
> [reads MUTEX_FLAG_WAITERS]
> [drops lock ownership]
>
> __mutex_trylock
> [success]
> __mutex_remove_waiter
> ep_refcount_dec_and_test
> [drop refcount from 1 to 0]
> mutex_unlock
> ep_free
> kfree(ep)
>
> raw_spin_lock_irqsave(&lock->wait_lock)
> *** UAF WRITE ***
>
> This race condition is possible especially if a preemption happens right
> after releasing the lock but before acquiring the wait_lock. Rwsem's
> __up_write() and __up_read() helpers have already disabled
> preemption to minimize this vulnernable time period, do the same for
> __mutex_unlock_slowpath() to minimize the chance of this race condition.
>
> Also add a note in Documentation/locking/mutex-design.rst to suggest
> that callers can use rcu_free() to delay the actual memory free to
> eliminate this UAF scenario.
>
> Signed-off-by: Waiman Long <longman@redhat.com>
> ---
> Documentation/locking/mutex-design.rst | 6 ++++--
> kernel/locking/mutex.c | 6 ++++++
> 2 files changed, 10 insertions(+), 2 deletions(-)
>
> diff --git a/Documentation/locking/mutex-design.rst b/Documentation/locking/mutex-design.rst
> index 7c30b4aa5e28..51a3a28ca830 100644
> --- a/Documentation/locking/mutex-design.rst
> +++ b/Documentation/locking/mutex-design.rst
> @@ -117,8 +117,10 @@ the structure anymore.
>
> The mutex user must ensure that the mutex is not destroyed while a
> release operation is still in progress - in other words, callers of
> -mutex_unlock() must ensure that the mutex stays alive until mutex_unlock()
> -has returned.
> +mutex_unlock() must ensure that the mutex stays alive until
> +mutex_unlock() has returned. One possible way to do that is to use
> +kfree_rcu() or its variants to delay the actual freeing the memory
> +object containing the mutex.
>
> Interfaces
> ----------
> diff --git a/kernel/locking/mutex.c b/kernel/locking/mutex.c
> index a39ecccbd106..d33f36d305fb 100644
> --- a/kernel/locking/mutex.c
> +++ b/kernel/locking/mutex.c
> @@ -912,9 +912,15 @@ static noinline void __sched __mutex_unlock_slowpath(struct mutex *lock, unsigne
> * Release the lock before (potentially) taking the spinlock such that
> * other contenders can get on with things ASAP.
> *
> + * Preemption is disabled to minimize the time gap between releasing
> + * the lock and acquiring the wait_lock. Callers may consider using
> + * kfree_rcu() if the memory holding the mutex may be freed after
> + * another mutex_unlock() call to ensure that UAF will not happen.
> + *
> * Except when HANDOFF, in that case we must not clear the owner field,
> * but instead set it to the top waiter.
> */
> + guard(preempt)();
> owner = atomic_long_read(&lock->owner);
> for (;;) {
> MUTEX_WARN_ON(__owner_task(owner) != current);
Note that Linus' patch should fix this particular eventpoll UAF race
condition, but there may be other code paths where similar situations
can happen.
Cheers,
Longman
next prev parent reply other threads:[~2025-07-09 18:19 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-07-09 18:05 Waiman Long
2025-07-09 18:19 ` Waiman Long [this message]
2025-07-09 18:19 ` Linus Torvalds
2025-07-09 18:21 ` Linus Torvalds
2025-07-09 18:28 ` Waiman Long
2025-07-09 18:28 ` Linus Torvalds
2025-07-09 19:42 ` Waiman Long
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4fcb119f-9a5d-417b-aeaa-977a3a794b4c@redhat.com \
--to=llong@redhat.com \
--cc=boqun.feng@gmail.com \
--cc=corbet@lwn.net \
--cc=jannh@google.com \
--cc=linux-kernel@vger.kernel.org \
--cc=mingo@redhat.com \
--cc=peterz@infradead.org \
--cc=torvalds@linux-foundation.org \
--cc=will@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®