From 1593219a41bdb9d8efa62abf5fca462b38563878 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Sun, 14 Feb 2021 00:53:53 +0100 Subject: [PATCH] Kernel: Map signal trampoline into each process's address space The signal trampoline was previously in kernelspace memory, but with a special exception to make it user-accessible. This patch moves it into each process's regular address space so we can stop supporting user-allowed memory above 0xc0000000. --- Kernel/Process.cpp | 24 ++++++++++-------------- Kernel/Process.h | 5 +++-- Kernel/Syscalls/execve.cpp | 16 ++++++++++++++++ Kernel/Thread.cpp | 2 +- 4 files changed, 30 insertions(+), 17 deletions(-) diff --git a/Kernel/Process.cpp b/Kernel/Process.cpp index a83e51c798..9b1d572fc5 100644 --- a/Kernel/Process.cpp +++ b/Kernel/Process.cpp @@ -58,15 +58,15 @@ namespace Kernel { -static void create_signal_trampolines(); +static void create_signal_trampoline(); RecursiveSpinLock g_processes_lock; static Atomic next_pid; InlineLinkedList* g_processes; String* g_hostname; Lock* g_hostname_lock; -VirtualAddress g_return_to_ring3_from_signal_trampoline; HashMap>* g_modules; +Region* g_signal_trampoline_region; ProcessID Process::allocate_pid() { @@ -88,7 +88,7 @@ void Process::initialize() g_hostname = new String("courage"); g_hostname_lock = new Lock; - create_signal_trampolines(); + create_signal_trampoline(); } Vector Process::all_pids() @@ -285,25 +285,21 @@ void signal_trampoline_dummy() extern "C" void asm_signal_trampoline(void); extern "C" void asm_signal_trampoline_end(void); -void create_signal_trampolines() +void create_signal_trampoline() { // NOTE: We leak this region. - auto* trampoline_region = MM.allocate_user_accessible_kernel_region(PAGE_SIZE, "Signal trampolines", Region::Access::Read | Region::Access::Write | Region::Access::Execute, false).leak_ptr(); - trampoline_region->set_syscall_region(true); - g_return_to_ring3_from_signal_trampoline = trampoline_region->vaddr(); + g_signal_trampoline_region = MM.allocate_kernel_region(PAGE_SIZE, "Signal trampolines", Region::Access::Read | Region::Access::Write, false).leak_ptr(); + g_signal_trampoline_region->set_syscall_region(true); u8* trampoline = (u8*)asm_signal_trampoline; u8* trampoline_end = (u8*)asm_signal_trampoline_end; size_t trampoline_size = trampoline_end - trampoline; - { - SmapDisabler disabler; - u8* code_ptr = (u8*)trampoline_region->vaddr().as_ptr(); - memcpy(code_ptr, trampoline, trampoline_size); - } + u8* code_ptr = (u8*)g_signal_trampoline_region->vaddr().as_ptr(); + memcpy(code_ptr, trampoline, trampoline_size); - trampoline_region->set_writable(false); - trampoline_region->remap(); + g_signal_trampoline_region->set_writable(false); + g_signal_trampoline_region->remap(); } void Process::crash(int signal, u32 eip, bool out_of_memory) diff --git a/Kernel/Process.h b/Kernel/Process.h index 5a0485265d..06339be322 100644 --- a/Kernel/Process.h +++ b/Kernel/Process.h @@ -57,8 +57,6 @@ namespace Kernel { timeval kgettimeofday(); void kgettimeofday(timeval&); -extern VirtualAddress g_return_to_ring3_from_signal_trampoline; - #define ENUMERATE_PLEDGE_PROMISES \ __ENUMERATE_PLEDGE_PROMISE(stdio) \ __ENUMERATE_PLEDGE_PROMISE(rpath) \ @@ -458,6 +456,8 @@ public: Space& space() { return *m_space; } const Space& space() const { return *m_space; } + VirtualAddress signal_trampoline() const { return m_signal_trampoline; } + private: friend class MemoryManager; friend class Scheduler; @@ -507,6 +507,7 @@ private: String m_name; OwnPtr m_space; + VirtualAddress m_signal_trampoline; ProcessID m_pid { 0 }; SessionID m_sid { 0 }; diff --git a/Kernel/Syscalls/execve.cpp b/Kernel/Syscalls/execve.cpp index f4575f8f6a..5ddc338303 100644 --- a/Kernel/Syscalls/execve.cpp +++ b/Kernel/Syscalls/execve.cpp @@ -47,6 +47,8 @@ namespace Kernel { +extern Region* g_signal_trampoline_region; + struct LoadResult { OwnPtr space; FlatPtr load_base { 0 }; @@ -481,6 +483,12 @@ int Process::do_exec(NonnullRefPtr main_program_description, Ve return load_result_or_error.error(); } + auto signal_trampoline_range = load_result_or_error.value().space->allocate_range({}, PAGE_SIZE); + if (!signal_trampoline_range.has_value()) { + dbgln("do_exec: Failed to allocate VM for signal trampoline"); + return -ENOMEM; + } + // We commit to the new executable at this point. There is no turning back! // Prevent other processes from attaching to us with ptrace while we're doing this. @@ -510,6 +518,14 @@ int Process::do_exec(NonnullRefPtr main_program_description, Ve m_space = load_result.space.release_nonnull(); MemoryManager::enter_space(*m_space); + auto signal_trampoline_region = m_space->allocate_region_with_vmobject(signal_trampoline_range.value(), g_signal_trampoline_region->vmobject(), 0, "Signal trampoline", PROT_READ | PROT_EXEC, true); + if (signal_trampoline_region.is_error()) { + ASSERT_NOT_REACHED(); + } + + signal_trampoline_region.value()->set_syscall_region(true); + m_signal_trampoline = signal_trampoline_region.value()->vaddr(); + m_executable = main_program_description->custody(); m_arguments = arguments; m_environment = environment; diff --git a/Kernel/Thread.cpp b/Kernel/Thread.cpp index 7a4726eec8..cb3b0de285 100644 --- a/Kernel/Thread.cpp +++ b/Kernel/Thread.cpp @@ -834,7 +834,7 @@ DispatchSignalResult Thread::dispatch_signal(u8 signal) // valid (fork, exec etc) but the tss will, so we use that instead. auto& regs = get_register_dump_from_stack(); setup_stack(regs); - regs.eip = g_return_to_ring3_from_signal_trampoline.get(); + regs.eip = process.signal_trampoline().get(); #if SIGNAL_DEBUG dbgln("signal: Thread in state '{}' has been primed with signal handler {:04x}:{:08x} to deliver {}", state_string(), m_tss.cs, m_tss.eip, signal);