From 864b50b5c2e0f2c1c4b2e65c28c45755aec7a5f5 Mon Sep 17 00:00:00 2001 From: Tom Date: Tue, 6 Jul 2021 14:18:26 -0600 Subject: [PATCH] Kernel: Do not hold spinlock while touching user mode futex values The user_atomic_* functions are subject to the same rules as copy_from/to/user, which may require preemption. --- Kernel/Syscalls/futex.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Kernel/Syscalls/futex.cpp b/Kernel/Syscalls/futex.cpp index 208a49bf6c..cd3eea648e 100644 --- a/Kernel/Syscalls/futex.cpp +++ b/Kernel/Syscalls/futex.cpp @@ -200,6 +200,7 @@ KResultOr Process::sys$futex(Userspace auto do_wake = [&](VMObject* vmobject, FlatPtr user_address_or_offset, u32 count, Optional bitmask) -> int { if (count == 0) return 0; + ScopedSpinLock lock(queue_lock); auto futex_queue = find_futex_queue(vmobject, user_address_or_offset, false); if (!futex_queue) return 0; @@ -212,8 +213,6 @@ KResultOr Process::sys$futex(Userspace return (int)woke_count; }; - ScopedSpinLock lock(queue_lock); - auto do_wait = [&](u32 bitset) -> int { bool did_create; RefPtr futex_queue; @@ -227,6 +226,7 @@ KResultOr Process::sys$futex(Userspace } atomic_thread_fence(AK::MemoryOrder::memory_order_acquire); + ScopedSpinLock lock(queue_lock); did_create = false; futex_queue = find_futex_queue(vmobject.ptr(), user_address_or_offset, true, &did_create); VERIFY(futex_queue); @@ -234,13 +234,12 @@ KResultOr Process::sys$futex(Userspace // was removed before we were able to queue an imminent wait. } while (!did_create && !futex_queue->queue_imminent_wait()); - // We need to release the lock before blocking. But we have a reference + // We must not hold the lock before blocking. But we have a reference // to the FutexQueue so that we can keep it alive. - lock.unlock(); Thread::BlockResult block_result = futex_queue->wait_on(timeout, bitset); - lock.lock(); + ScopedSpinLock lock(queue_lock); if (futex_queue->is_empty_and_no_imminent_waits()) { // If there are no more waiters, we want to get rid of the futex! remove_futex_queue(vmobject, user_address_or_offset); @@ -260,6 +259,7 @@ KResultOr Process::sys$futex(Userspace atomic_thread_fence(AK::MemoryOrder::memory_order_acquire); int woken_or_requeued = 0; + ScopedSpinLock lock(queue_lock); if (auto futex_queue = find_futex_queue(vmobject.ptr(), user_address_or_offset, false)) { RefPtr target_futex_queue; bool is_empty, is_target_empty;