Kernel: Allow relaxing cleanup task rules during system shutdown

Once we move to a more proper shutdown procedure, processes other than
the finalizer task must be able to perform cleanup and finalization
duties, not only because the finalizer task itself needs to be cleaned
up by someone. This global variable, mirroring the early boot flags,
allows a future shutdown process to perform cleanup on its own.

Note that while this *could* be considered a weakening in security, the
attack surface is minimal and the results are not dramatic. To exploit
this, an attacker would have to gain a Kernel write primitive to this
global variable (bypassing KASLR among other things) and then gain some
way of calling the relevant functions, all of this only to destroy some
other running process. The same effect can be achieved with LPE which
can often be gained with significantly simpler userspace exploits (e.g.
of setuid binaries).
This commit is contained in:
kleines Filmröllchen 2023-07-10 00:20:48 +02:00 committed by Jelle Raaijmakers
parent 021fb3ea05
commit 2fd23745a9
Notes: sideshowbarker 2024-07-17 22:41:14 +09:00
6 changed files with 39 additions and 5 deletions

View file

@ -350,6 +350,7 @@ set(KERNEL_SOURCES
Tasks/FinalizerTask.cpp
Tasks/FutexQueue.cpp
Tasks/PerformanceEventBuffer.cpp
Tasks/PowerStateSwitchTask.cpp
Tasks/Process.cpp
Tasks/ProcessGroup.cpp
Tasks/ProcessList.cpp

View file

@ -14,6 +14,7 @@
#include <Kernel/Memory/MemoryManager.h>
#include <Kernel/Security/Random.h>
#include <Kernel/Tasks/PerformanceManager.h>
#include <Kernel/Tasks/PowerStateSwitchTask.h>
#include <Kernel/Tasks/Process.h>
#include <Kernel/Tasks/Scheduler.h>
@ -323,7 +324,9 @@ void AddressSpace::dump_regions()
void AddressSpace::remove_all_regions(Badge<Process>)
{
VERIFY(Thread::current() == g_finalizer);
if (!g_in_system_shutdown)
VERIFY(Thread::current() == g_finalizer);
{
SpinlockLocker pd_locker(m_page_directory->get_lock());
for (auto& region : m_region_tree.regions())

View file

@ -0,0 +1,11 @@
/*
* Copyright (c) 2023, kleines Filmröllchen <filmroellchen@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
namespace Kernel {
bool g_in_system_shutdown { false };
}

View file

@ -0,0 +1,11 @@
/*
* Copyright (c) 2023, kleines Filmröllchen <filmroellchen@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
namespace Kernel {
extern bool g_in_system_shutdown;
}

View file

@ -46,6 +46,7 @@ namespace Kernel {
static void create_signal_trampoline();
extern ProcessID g_init_pid;
extern bool g_in_system_shutdown;
RecursiveSpinlock<LockRank::None> g_profiling_lock {};
static Atomic<pid_t> next_pid;
@ -749,7 +750,8 @@ ErrorOr<void> Process::dump_perfcore()
void Process::finalize()
{
VERIFY(Thread::current() == g_finalizer);
if (!g_in_system_shutdown)
VERIFY(Thread::current() == g_finalizer);
dbgln_if(PROCESS_DEBUG, "Finalizing process {}", *this);
@ -759,8 +761,12 @@ void Process::finalize()
});
}
if (g_init_pid != 0 && pid() == g_init_pid)
PANIC("Init process quit unexpectedly. Exit code: {}", termination_status());
if (g_init_pid != 0 && pid() == g_init_pid) {
if (g_in_system_shutdown)
dbgln("Init process quitting for shutdown.");
else
PANIC("Init process quit unexpectedly. Exit code: {}", termination_status());
}
if (is_dumpable()) {
if (m_should_generate_coredump) {

View file

@ -23,6 +23,7 @@
#include <Kernel/Memory/ScopedAddressSpaceSwitcher.h>
#include <Kernel/Sections.h>
#include <Kernel/Tasks/PerformanceEventBuffer.h>
#include <Kernel/Tasks/PowerStateSwitchTask.h>
#include <Kernel/Tasks/Process.h>
#include <Kernel/Tasks/Scheduler.h>
#include <Kernel/Tasks/Thread.h>
@ -537,7 +538,8 @@ StringView Thread::state_string() const
void Thread::finalize()
{
VERIFY(Thread::current() == g_finalizer);
if (!g_in_system_shutdown)
VERIFY(Thread::current() == g_finalizer);
VERIFY(Thread::current() != this);
#if LOCK_DEBUG