diff --git a/kernel/src/arch/x86_64/CPU.cpp b/kernel/src/arch/x86_64/CPU.cpp index cb94d306..2855907c 100644 --- a/kernel/src/arch/x86_64/CPU.cpp +++ b/kernel/src/arch/x86_64/CPU.cpp @@ -75,6 +75,16 @@ void decode_page_fault_error_code(u64 code) (code & PF_RESERVED) ? " | Reserved bits set" : "", (code & PF_NX_VIOLATION) ? " | NX violation" : ""); } +static void check_stack(Thread* current, Registers* regs) +{ + if (regs->rsp < current->stack.bottom() || regs->rsp >= current->stack.top()) + kerrorln("Abnormal stack (RSP outside the normal range, %.16lx-%.16lx)", current->stack.bottom(), + current->stack.top()); + + if (regs->rsp >= (current->stack.bottom() - ARCH_PAGE_SIZE) && regs->rsp < current->stack.bottom()) + kerrorln("Likely stack overflow (CPU exception inside guard page)"); +} + void handle_cpu_exception(int signo, const char* err, Registers* regs) { if (err) kerrorln("Caught CPU exception: %s", err); @@ -89,8 +99,11 @@ void handle_cpu_exception(int signo, const char* err, Registers* regs) if (!is_in_kernel(regs)) { - Scheduler::current()->send_signal(signo); - Scheduler::current()->process_pending_signals(regs); + auto* current = Scheduler::current(); + check_stack(current, regs); + + current->send_signal(signo); + current->process_pending_signals(regs); return; } @@ -103,6 +116,8 @@ void handle_page_fault(Registers* regs) asm volatile("mov %%cr2, %0" : "=r"(cr2)); kerrorln("Page fault while accessing %lx!", cr2); + if (cr2 <= ARCH_PAGE_SIZE) kerrorln("Looks like a null pointer dereference!"); + decode_page_fault_error_code(regs->error); handle_cpu_exception(SIGSEGV, nullptr, regs); diff --git a/kernel/src/thread/ThreadImage.cpp b/kernel/src/thread/ThreadImage.cpp index 3d03fd0c..285a2bae 100644 --- a/kernel/src/thread/ThreadImage.cpp +++ b/kernel/src/thread/ThreadImage.cpp @@ -11,16 +11,17 @@ static constexpr u64 THREAD_STACK_BASE = 0x10000; static Result create_user_stack(Stack& user_stack, AddressSpace* space) { - TRY(MemoryManager::alloc_at_zeroed(THREAD_STACK_BASE, DEFAULT_USER_STACK_PAGES, - MMU::ReadWrite | MMU::NoExecute | MMU::User)); - - auto guard = make_scope_guard([] { MemoryManager::unmap_owned(THREAD_STACK_BASE, DEFAULT_USER_STACK_PAGES); }); - if (!TRY(space->test_and_alloc_region(THREAD_STACK_BASE, DEFAULT_USER_STACK_PAGES, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, 0, true))) return err(ENOMEM); - guard.deactivate(); + // Stack overflow guard page, remains unmapped. + if (!TRY(space->test_and_alloc_region(THREAD_STACK_BASE - ARCH_PAGE_SIZE, 1, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, + 0, 0, true))) + return err(ENOMEM); + + TRY(MemoryManager::alloc_at_zeroed(THREAD_STACK_BASE, DEFAULT_USER_STACK_PAGES, + MMU::ReadWrite | MMU::NoExecute | MMU::User)); user_stack = { THREAD_STACK_BASE, DEFAULT_USER_STACK_SIZE };