diff options
author | Andreas Kling <awesomekling@gmail.com> | 2019-11-17 12:11:43 +0100 |
---|---|---|
committer | Andreas Kling <awesomekling@gmail.com> | 2019-11-17 12:15:43 +0100 |
commit | 794758df3ace052c1d2f0d90dc99e6154e90be9d (patch) | |
tree | 99fdc414d7a50bed086fed34260e41bd74b75810 /Kernel/Arch | |
parent | 197ed1bb2a56677c6311d440d6246c9cd4b0a767 (diff) | |
download | serenity-794758df3ace052c1d2f0d90dc99e6154e90be9d.zip |
Kernel: Implement some basic stack pointer validation
VM regions can now be marked as stack regions, which is then validated
on syscall, and on page fault.
If a thread is caught with its stack pointer pointing into anything
that's *not* a Region with its stack bit set, we'll crash the whole
process with SIGSTKFLT.
Userspace must now allocate custom stacks by using mmap() with the new
MAP_STACK flag. This mechanism was first introduced in OpenBSD, and now
we have it too, yay! :^)
Diffstat (limited to 'Kernel/Arch')
-rw-r--r-- | Kernel/Arch/i386/CPU.cpp | 14 | ||||
-rw-r--r-- | Kernel/Arch/i386/CPU.h | 2 |
2 files changed, 13 insertions, 3 deletions
diff --git a/Kernel/Arch/i386/CPU.cpp b/Kernel/Arch/i386/CPU.cpp index 1bbdb0bd50..1b88059ade 100644 --- a/Kernel/Arch/i386/CPU.cpp +++ b/Kernel/Arch/i386/CPU.cpp @@ -131,7 +131,7 @@ static void dump(const RegisterDump& regs) u16 ss; u32 esp; if (!current || current->process().is_ring0()) { - ss = regs.ds; + ss = regs.ss; esp = regs.esp; } else { ss = regs.ss_if_crossRing; @@ -160,14 +160,14 @@ static void dump(const RegisterDump& regs) } } -static void handle_crash(RegisterDump& regs, const char* description, int signal) +void handle_crash(RegisterDump& regs, const char* description, int signal) { if (!current) { kprintf("%s with !current\n", description); hang(); } - kprintf("\033[31;1mCRASH: %s %s: %s(%u)\033[0m\n", + kprintf("\033[31;1mCRASH: %s. %s: %s(%u)\033[0m\n", description, current->process().is_ring0() ? "Kernel" : "Process", current->process().name().characters(), @@ -181,6 +181,7 @@ static void handle_crash(RegisterDump& regs, const char* description, int signal hang(); } + cli(); current->process().crash(signal, regs.eip); } @@ -263,6 +264,13 @@ void exception_14_handler(RegisterDump regs) dump(regs); #endif + bool faulted_in_userspace = (regs.cs & 3) == 3; + if (faulted_in_userspace && !MM.validate_user_stack(current->process(), VirtualAddress(regs.esp_if_crossRing))) { + dbgprintf("Invalid stack pointer: %p\n", regs.esp_if_crossRing); + handle_crash(regs, "Bad stack on page fault", SIGSTKFLT); + ASSERT_NOT_REACHED(); + } + auto response = MM.handle_page_fault(PageFault(regs.exception_code, VirtualAddress(fault_address))); if (response == PageFaultResponse::ShouldCrash) { diff --git a/Kernel/Arch/i386/CPU.h b/Kernel/Arch/i386/CPU.h index 5b14c84d98..5fa9057bb1 100644 --- a/Kernel/Arch/i386/CPU.h +++ b/Kernel/Arch/i386/CPU.h @@ -193,6 +193,7 @@ static_assert(sizeof(PageDirectoryEntry) == 4); static_assert(sizeof(PageTableEntry) == 4); class IRQHandler; +struct RegisterDump; void gdt_init(); void idt_init(); @@ -208,6 +209,7 @@ u16 gdt_alloc_entry(); void gdt_free_entry(u16); Descriptor& get_gdt_entry(u16 selector); void write_gdt_entry(u16 selector, Descriptor&); +void handle_crash(RegisterDump&, const char* description, int signal); [[noreturn]] static inline void hang() { |