From: Hyunwoo Kim <imv4bel@gmail.com>
To: tglx@kernel.org, mingo@redhat.com, peterz@infradead.org,
dvhart@infradead.org, dave@stgolabs.net, andrealmeid@igalia.com
Cc: linux-kernel@vger.kernel.org, imv4bel@gmail.com
Subject: [PATCH] futex: Require the PI owner of a private futex to share the key's mm
Date: Sun, 9 Aug 2026 14:08:54 +0900 [thread overview]
Message-ID: <angLZrg_1yeCW0ig@v4bel> (raw)
The futex word read by the FUTEX_LOCK_PI operations can hold an arbitrary
TID. attach_to_pi_owner() only checks whether the task looked up by that
TID is a kernel thread and whether it is already exiting. It does not
verify that the task belongs to the address space the futex key was taken
from.
A private futex key is the pair (mm, address), and the mm is stored as a
plain pointer without taking a reference. __attach_to_pi_owner() copies
that key into the pi_state by value and links the pi_state onto the
owner's futex.pi_state_list, so a key scoped to the waiter's mm ends up on
a task in a different mm.
When the owner exits, exit_pi_state_list() pins the private hash of the
owner's mm with guard(private_hash)(current->mm), but resolves the hash
bucket from the key stored in the pi_state, which points at the waiter's
mm (M below). Nothing holds a reference that keeps that mm alive.
T1 (waiter, mm = M) T2 (owner, mm != M)
prctl(PR_FUTEX_HASH, SET_SLOTS, 2) /* creates M's private hash */
futex_lock_pi()
attach_to_pi_owner()
pi_state->key = *key /* {M, addr} */
list_add(&pi_state->list, &T2->futex.pi_state_list)
do_exit()
exit_pi_state_list()
guard(private_hash)(current->mm)
/* T2's mm, not M */
raw_spin_lock_irq(&curr->pi_lock)
key = pi_state->key // M
CLASS(hbr, hbr)(&key)
hb = hbr.hb
raw_spin_unlock_irq(&curr->pi_lock)
do_exit()
exit_mm()
mmput(M) -> __mmput(M)
futex_hash_free(M)
kvfree(fph)
spin_lock(&hb->lock) // UAF
Once M loses its last mm_users reference, futex_hash_free() in __mmput()
frees the private hash with kvfree() unconditionally, ignoring the fph
references that are still outstanding. When the owner then reaches
spin_lock() with the stale hb, it writes into the freed queues[0].lock.
A private futex only has meaning inside the mm its key was taken from, so
a task that does not share that mm cannot be its owner. Verify in
attach_to_pi_owner() that the candidate owner belongs to the mm of the
private key and return -ESRCH otherwise, as the TID is then simply a bogus
user space value. p->mm is not protected by p->pi_lock, so it is read with
READ_ONCE(). The check is placed after the exit state check. Placing it
before would return -ESRCH for a task whose current->mm has already been
cleared by exit_mm(), instead of letting handle_exit_race() decide.
Fixes: 80367ad01d93 ("futex: Add basic infrastructure for local task local hash")
Cc: stable@kernel.org
Signed-off-by: Hyunwoo Kim <imv4bel@gmail.com>
---
kernel/futex/pi.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/kernel/futex/pi.c b/kernel/futex/pi.c
index 795011ea1202f1..d97611196b34ac 100644
--- a/kernel/futex/pi.c
+++ b/kernel/futex/pi.c
@@ -465,6 +465,13 @@ static int attach_to_pi_owner(u32 __user *uaddr, u32 uval, union futex_key *key,
return ret;
}
+ if (IS_ENABLED(CONFIG_MMU) && futex_key_is_private(key) &&
+ READ_ONCE(p->mm) != key->private.mm) {
+ raw_spin_unlock_irq(&p->pi_lock);
+ put_task_struct(p);
+ return -ESRCH;
+ }
+
__attach_to_pi_owner(p, key, ps);
raw_spin_unlock_irq(&p->pi_lock);
--
2.43.0
reply other threads:[~2026-08-09 5:08 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
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=angLZrg_1yeCW0ig@v4bel \
--to=imv4bel@gmail.com \
--cc=andrealmeid@igalia.com \
--cc=dave@stgolabs.net \
--cc=dvhart@infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=mingo@redhat.com \
--cc=peterz@infradead.org \
--cc=tglx@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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.