From: Waiman Long <longman@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>, Waiman Long <longman@redhat.com>
Subject: [PATCH] locking/mutex: Disable preemption in __mutex_unlock_slowpath()
Date: Wed, 9 Jul 2025 14:05:50 -0400 [thread overview]
Message-ID: <20250709180550.147205-1-longman@redhat.com> (raw)
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);
--
2.50.0
next reply other threads:[~2025-07-09 18:06 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-07-09 18:05 Waiman Long [this message]
2025-07-09 18:19 ` Waiman Long
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=20250709180550.147205-1-longman@redhat.com \
--to=longman@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®