aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Johnston <markj@FreeBSD.org>2026-07-27 23:12:37 +0000
committerMark Johnston <markj@FreeBSD.org>2026-07-27 23:12:37 +0000
commit75be70064483158da2b89ab412f83a4694560e58 (patch)
tree33ef33b00417c93cc28f58a99df452ba71bee52d
parent1f4b0ea4f3eb1b8a885eff8bd0d332156f0c3e1f (diff)
umtx: Do not make an exiting thread the owner of a PI mutex
Otherwise an assertion in umtx_thread_alloc() (TAILQ_EMPTY(&uq->uq_pi_contested)) is violated. This use of TDB_EXIT is hacky, but I cannot see another way to check for an exiting thread without adding some more overhead to kern_thr_exit(). Fixes: 2a339d9e3dc1 Reported by: Maik Muench of Secfault Security Reviewed by: kib MFC after: 1 week Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D58447
-rw-r--r--sys/kern/kern_umtx.c21
1 files changed, 15 insertions, 6 deletions
diff --git a/sys/kern/kern_umtx.c b/sys/kern/kern_umtx.c
index ab6e578ab380..4f6e2b339ba6 100644
--- a/sys/kern/kern_umtx.c
+++ b/sys/kern/kern_umtx.c
@@ -2028,7 +2028,7 @@ int
umtxq_sleep_pi(struct umtx_q *uq, struct umtx_pi *pi, uint32_t owner,
const char *wmesg, struct umtx_abs_timeout *timo, bool shared)
{
- struct thread *td, *td1;
+ struct thread *td;
struct umtx_q *uq1;
int error, pri;
#ifdef INVARIANTS
@@ -2044,13 +2044,22 @@ umtxq_sleep_pi(struct umtx_q *uq, struct umtx_pi *pi, uint32_t owner,
umtxq_insert(uq);
mtx_lock(&umtx_lock);
if (pi->pi_owner == NULL) {
+ struct thread *ownertd;
+
mtx_unlock(&umtx_lock);
- td1 = tdfind(owner, shared ? -1 : td->td_proc->p_pid);
+ ownertd = tdfind(owner, shared ? -1 : td->td_proc->p_pid);
mtx_lock(&umtx_lock);
- if (td1 != NULL) {
- if (pi->pi_owner == NULL)
- umtx_pi_setowner(pi, td1);
- PROC_UNLOCK(td1->td_proc);
+ if (ownertd != NULL) {
+ /*
+ * An exiting thread that has already called
+ * umtx_thread_exit() must not be made the owner of a
+ * shared mutex.
+ */
+ if ((ownertd->td_proc->p_flag & P_WEXIT) == 0 &&
+ (ownertd->td_dbgflags & TDB_EXIT) == 0 &&
+ pi->pi_owner == NULL)
+ umtx_pi_setowner(pi, ownertd);
+ PROC_UNLOCK(ownertd->td_proc);
}
}