From c1fe844da4df3061ac575567f662ad723cc2cccb Mon Sep 17 00:00:00 2001 From: Idan Horowitz Date: Sun, 10 Jul 2022 16:38:34 +0300 Subject: [PATCH] Kernel: Stop leaking first thread on errors in sys$fork Until the thread is first set as Runnable at the end of sys$fork, its state is Invalid, and as a result, the Finalizer which is searching for Dying threads will never find it if the syscall short-circuits due to an error condition like OOM. This also meant the parent Process of the thread would be leaked as well. --- Kernel/Syscalls/fork.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Kernel/Syscalls/fork.cpp b/Kernel/Syscalls/fork.cpp index 5183448a0d..833a68771b 100644 --- a/Kernel/Syscalls/fork.cpp +++ b/Kernel/Syscalls/fork.cpp @@ -18,6 +18,15 @@ ErrorOr Process::sys$fork(RegisterState& regs) VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this); TRY(require_promise(Pledge::proc)); RefPtr child_first_thread; + + ArmedScopeGuard thread_finalizer_guard = [&child_first_thread]() { + SpinlockLocker lock(g_scheduler_lock); + if (child_first_thread) { + child_first_thread->detach(); + child_first_thread->set_state(Thread::State::Dying); + } + }; + auto child_name = TRY(m_name->try_clone()); auto child = TRY(Process::try_create(child_first_thread, move(child_name), uid(), gid(), pid(), m_is_kernel_process, current_directory(), m_executable, m_tty, this)); TRY(m_unveil_data.with([&](auto& parent_unveil_data) -> ErrorOr { @@ -120,6 +129,8 @@ ErrorOr Process::sys$fork(RegisterState& regs) } } + thread_finalizer_guard.disarm(); + Process::register_new(*child); PerformanceManager::add_process_created_event(*child);