From c136fd3fe22506d594a0624071d08b311f78cc41 Mon Sep 17 00:00:00 2001 From: Drew Stratford Date: Mon, 7 Oct 2019 22:22:50 +1300 Subject: [PATCH] Kernel: Send SIGSEGV on seg-fault Now programs can catch the SIGSEGV signal when they segfault. This commit also introduced the send_urgent_signal_to_self method, which is needed to send signals to a thread when handling exceptions caused by the same thread. --- Kernel/Arch/i386/CPU.cpp | 5 +++++ Kernel/Thread.cpp | 24 ++++++++++++++++++++++++ Kernel/Thread.h | 2 ++ 3 files changed, 31 insertions(+) diff --git a/Kernel/Arch/i386/CPU.cpp b/Kernel/Arch/i386/CPU.cpp index 6d9bead1ea..a394405055 100644 --- a/Kernel/Arch/i386/CPU.cpp +++ b/Kernel/Arch/i386/CPU.cpp @@ -262,6 +262,11 @@ void exception_14_handler(RegisterDump& regs) auto response = MM.handle_page_fault(PageFault(regs.exception_code, VirtualAddress(fault_address))); if (response == PageFaultResponse::ShouldCrash) { + if(current->has_signal_handler(SIGSEGV)){ + current->send_urgent_signal_to_self(SIGSEGV); + return; + } + kprintf("\033[31;1m%s(%u:%u) Unrecoverable page fault, %s address %p\033[0m\n", current->process().name().characters(), current->pid(), diff --git a/Kernel/Thread.cpp b/Kernel/Thread.cpp index 9ced4e1806..f03a7030c3 100644 --- a/Kernel/Thread.cpp +++ b/Kernel/Thread.cpp @@ -246,6 +246,23 @@ void Thread::send_signal(u8 signal, Process* sender) m_pending_signals |= 1 << (signal - 1); } +// Certain exceptions, such as SIGSEGV and SIGILL, put a +// thread into a state where the signal handler must be +// invoked immediately, otherwise it will continue to fault. +// This function should be used in an exception handler to +// ensure that when the thread resumes, it's executing in +// the appropriate signal handler. +void Thread::send_urgent_signal_to_self(u8 signal) +{ + // FIXME: because of a bug in dispatch_signal we can't + // setup a signal while we are the current thread. Because of + // this we use a work-around where we send the signal and then + // block, allowing the scheduler to properly dispatch the signal + // before the thread is next run. + send_signal(signal, &process()); + (void)block(SemiPermanentBlocker::Reason::Signal); +} + bool Thread::has_unmasked_pending_signals() const { return m_pending_signals & ~m_signal_mask; @@ -330,6 +347,13 @@ bool Thread::should_ignore_signal(u8 signal) const return false; } +bool Thread::has_signal_handler(u8 signal) const +{ + ASSERT(signal < 32); + auto& action = m_signal_action_data[signal]; + return !action.handler_or_sigaction.is_null(); +} + ShouldUnblockThread Thread::dispatch_signal(u8 signal) { ASSERT_INTERRUPTS_DISABLED(); diff --git a/Kernel/Thread.h b/Kernel/Thread.h index edfd20b4dd..3f5cacec70 100644 --- a/Kernel/Thread.h +++ b/Kernel/Thread.h @@ -273,6 +273,7 @@ public: void set_selector(u16 s) { m_far_ptr.selector = s; } void set_state(State); + void send_urgent_signal_to_self(u8 signal); void send_signal(u8 signal, Process* sender); void consider_unblock(time_t now_sec, long now_usec); @@ -283,6 +284,7 @@ public: bool has_unmasked_pending_signals() const; void terminate_due_to_signal(u8 signal); bool should_ignore_signal(u8 signal) const; + bool has_signal_handler(u8 signal) const; FPUState& fpu_state() { return *m_fpu_state; } bool has_used_fpu() const { return m_has_used_fpu; }