summaryrefslogtreecommitdiff
path: root/Kernel/Arch
diff options
context:
space:
mode:
authorAndreas Kling <awesomekling@gmail.com>2019-11-17 12:11:43 +0100
committerAndreas Kling <awesomekling@gmail.com>2019-11-17 12:15:43 +0100
commit794758df3ace052c1d2f0d90dc99e6154e90be9d (patch)
tree99fdc414d7a50bed086fed34260e41bd74b75810 /Kernel/Arch
parent197ed1bb2a56677c6311d440d6246c9cd4b0a767 (diff)
downloadserenity-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.cpp14
-rw-r--r--Kernel/Arch/i386/CPU.h2
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()
{