From b0f2185bbefaf7e9fdaa50ecb658b9790e835bd9 Mon Sep 17 00:00:00 2001 From: Eric Badger Date: Mon, 15 Aug 2016 20:09:09 +0000 Subject: [PATCH] sem_post(): wake up the sleeper only after adjusting has_waiters If the caller of sem_post() wakes up a thread sleeping via sem_wait() before it clears the has_waiters flag, the caller of sem_wait() has no way of knowing when it is safe to destroy the semaphore and reuse the memory. This is because the caller of sem_post() may be interrupted between the wake step and the clearing of has_waiters. It will then write into the has_waiters flag in userspace after being preempted for some unknown amount of time. Reviewed by: jhb, kib, vangyzen Approved by: kib (mentor), vangyzen (mentor) MFC after: 2 weeks Sponsored by: Dell Inc. Differential Revision: https://reviews.freebsd.org/D7505 --- sys/kern/kern_umtx.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sys/kern/kern_umtx.c b/sys/kern/kern_umtx.c index 8471591e648d..33eb8bca43cc 100644 --- a/sys/kern/kern_umtx.c +++ b/sys/kern/kern_umtx.c @@ -3123,7 +3123,6 @@ do_sem_wake(struct thread *td, struct _usem *sem) umtxq_busy(&key); cnt = umtxq_count(&key); if (cnt > 0) { - umtxq_signal(&key, 1); /* * Check if count is greater than 0, this means the memory is * still being referenced by user code, so we can safely @@ -3136,6 +3135,7 @@ do_sem_wake(struct thread *td, struct _usem *sem) if (error == -1) error = EFAULT; } + umtxq_signal(&key, 1); } umtxq_unbusy(&key); umtxq_unlock(&key); @@ -3235,8 +3235,6 @@ do_sem2_wake(struct thread *td, struct _usem2 *sem) umtxq_busy(&key); cnt = umtxq_count(&key); if (cnt > 0) { - umtxq_signal(&key, 1); - /* * If this was the last sleeping thread, clear the waiters * flag in _count. @@ -3251,6 +3249,8 @@ do_sem2_wake(struct thread *td, struct _usem2 *sem) error = EFAULT; umtxq_lock(&key); } + + umtxq_signal(&key, 1); } umtxq_unbusy(&key); umtxq_unlock(&key);