diff options
Diffstat (limited to 'Kernel/VM/MemoryManager.cpp')
-rw-r--r-- | Kernel/VM/MemoryManager.cpp | 49 |
1 files changed, 47 insertions, 2 deletions
diff --git a/Kernel/VM/MemoryManager.cpp b/Kernel/VM/MemoryManager.cpp index 30f8a54fc7..46767ac923 100644 --- a/Kernel/VM/MemoryManager.cpp +++ b/Kernel/VM/MemoryManager.cpp @@ -624,10 +624,55 @@ Region* MemoryManager::kernel_region_from_vaddr(VirtualAddress vaddr) return nullptr; } +Region* MemoryManager::find_user_region_from_vaddr_no_lock(Space& space, VirtualAddress vaddr) +{ + VERIFY(space.get_lock().own_lock()); + return space.find_region_containing({ vaddr, 1 }); +} + Region* MemoryManager::find_user_region_from_vaddr(Space& space, VirtualAddress vaddr) { ScopedSpinLock lock(space.get_lock()); - return space.find_region_containing({ vaddr, 1 }); + return find_user_region_from_vaddr_no_lock(space, vaddr); +} + +void MemoryManager::validate_syscall_preconditions(Space& space, RegisterState& regs) +{ + // We take the space lock once here and then use the no_lock variants + // to avoid excessive spinlock recursion in this extemely common path. + ScopedSpinLock lock(space.get_lock()); + + auto unlock_and_handle_crash = [&lock, ®s](const char* description, int signal) { + lock.unlock(); + handle_crash(regs, description, signal); + }; + + { + VirtualAddress userspace_sp = VirtualAddress { regs.userspace_sp() }; + if (!MM.validate_user_stack_no_lock(space, userspace_sp)) { + dbgln("Invalid stack pointer: {:p}", userspace_sp); + unlock_and_handle_crash("Bad stack on syscall entry", SIGSTKFLT); + } + } + + { + VirtualAddress ip = VirtualAddress { regs.ip() }; + auto* calling_region = MM.find_user_region_from_vaddr_no_lock(space, ip); + if (!calling_region) { + dbgln("Syscall from {:p} which has no associated region", ip); + unlock_and_handle_crash("Syscall from unknown region", SIGSEGV); + } + + if (calling_region->is_writable()) { + dbgln("Syscall from writable memory at {:p}", ip); + unlock_and_handle_crash("Syscall from writable memory", SIGSEGV); + } + + if (space.enforces_syscall_regions() && !calling_region->is_syscall_region()) { + dbgln("Syscall from non-syscall region"); + unlock_and_handle_crash("Syscall from non-syscall region", SIGSEGV); + } + } } Region* MemoryManager::find_region_from_vaddr(VirtualAddress vaddr) @@ -1039,7 +1084,7 @@ bool MemoryManager::validate_user_stack_no_lock(Space& space, VirtualAddress vad if (!is_user_address(vaddr)) return false; - auto* region = find_user_region_from_vaddr(space, vaddr); + auto* region = find_user_region_from_vaddr_no_lock(space, vaddr); return region && region->is_user() && region->is_stack(); } |