1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 16:17:45 +00:00

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! :^)
This commit is contained in:
Andreas Kling 2019-11-17 12:11:43 +01:00
parent 197ed1bb2a
commit 794758df3a
12 changed files with 101 additions and 5 deletions

View file

@ -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) {