summaryrefslogtreecommitdiff
path: root/Kernel/Arch/i386
diff options
context:
space:
mode:
authorTom <tomut@yahoo.com>2020-09-14 13:10:49 -0600
committerAndreas Kling <kling@serenityos.org>2020-09-14 21:18:59 +0200
commit365fa05a8256d1ba44cff5d05c44dda5021571e9 (patch)
treea1186034f6efe32f439f1e3cbf9a32c9b2cb3371 /Kernel/Arch/i386
parent95964e7cbe6f54194ec24676a3f9dcb8eab2d774 (diff)
downloadserenity-365fa05a8256d1ba44cff5d05c44dda5021571e9.zip
Kernel: Handle safe_memcpy/safe_memset/safe_strnlen faults in irq handlers
Fix gracefully failing these calls if used within IRQ handlers. If we're handling IRQs, we need to handle these failures first, because we can't really resolve page faults in a meaningful way. But if we know that it was one of these functions that failed, then we can gracefully handle the situation. This solves a crash where the Scheduler attempts to produce backtraces in the timer irq, some of which cause faults. Fixes #3492
Diffstat (limited to 'Kernel/Arch/i386')
-rw-r--r--Kernel/Arch/i386/CPU.cpp20
1 files changed, 17 insertions, 3 deletions
diff --git a/Kernel/Arch/i386/CPU.cpp b/Kernel/Arch/i386/CPU.cpp
index d1a9ccb136..ca5425cffd 100644
--- a/Kernel/Arch/i386/CPU.cpp
+++ b/Kernel/Arch/i386/CPU.cpp
@@ -401,9 +401,23 @@ void page_fault_handler(TrapFrame* trap)
dump(regs);
#endif
- bool faulted_in_userspace = (regs.cs & 3) == 3;
+ bool faulted_in_kernel = !(regs.cs & 3);
+
+ if (faulted_in_kernel && Processor::current().in_irq()) {
+ // If we're faulting in an IRQ handler, first check if we failed
+ // due to safe_memcpy, safe_strnlen, or safe_memset. If we did,
+ // gracefully continue immediately. Because we're in an IRQ handler
+ // we can't really try to resolve the page fault in a meaningful
+ // way, so we need to do this before calling into
+ // MemoryManager::handle_page_fault, which would just bail and
+ // request a crash
+ if (handle_safe_access_fault(regs, fault_address))
+ return;
+ }
+
+
auto current_thread = Thread::current();
- if (faulted_in_userspace && !MM.validate_user_stack(current_thread->process(), VirtualAddress(regs.userspace_esp))) {
+ if (!faulted_in_kernel && !MM.validate_user_stack(current_thread->process(), VirtualAddress(regs.userspace_esp))) {
dbg() << "Invalid stack pointer: " << VirtualAddress(regs.userspace_esp);
handle_crash(regs, "Bad stack on page fault", SIGSTKFLT);
ASSERT_NOT_REACHED();
@@ -412,7 +426,7 @@ void page_fault_handler(TrapFrame* trap)
auto response = MM.handle_page_fault(PageFault(regs.exception_code, VirtualAddress(fault_address)));
if (response == PageFaultResponse::ShouldCrash || response == PageFaultResponse::OutOfMemory) {
- if (!(regs.cs & 3) && handle_safe_access_fault(regs, fault_address)) {
+ if (faulted_in_kernel && handle_safe_access_fault(regs, fault_address)) {
// If this would be a ring0 (kernel) fault and the fault was triggered by
// safe_memcpy, safe_strnlen, or safe_memset then we resume execution at
// the appropriate _fault label rather than crashing