Sfoglia il codice sorgente

Kernel: Dispatch handle-able signals instead of crashing if possible

This matches the behaviour of the other *nixs and allows processes to
try and recover from such signals in userland.
Idan Horowitz 3 anni fa
parent
commit
40f64d7379

+ 1 - 1
Kernel/Arch/x86/CPU.h

@@ -36,7 +36,7 @@ inline u32 get_iopl_from_eflags(u32 eflags)
 const DescriptorTablePointer& get_gdtr();
 const DescriptorTablePointer& get_idtr();
 
-[[noreturn]] void handle_crash(RegisterState const&, char const* description, int signal, bool out_of_memory = false);
+void handle_crash(RegisterState const&, char const* description, int signal, bool out_of_memory = false);
 
 #define LSW(x) ((u32)(x)&0xFFFF)
 #define MSW(x) (((u32)(x) >> 16) & 0xFFFF)

+ 11 - 5
Kernel/Arch/x86/common/Interrupts.cpp

@@ -215,10 +215,16 @@ static void dump(const RegisterState& regs)
 
 void handle_crash(RegisterState const& regs, char const* description, int signal, bool out_of_memory)
 {
-    if (!Process::has_current())
-        PANIC("{} with !current", description);
+    auto* current_thread = Thread::current();
+    if (!current_thread)
+        PANIC("{} with !Thread::current()", description);
 
-    auto& process = Process::current();
+    if (!current_thread->should_ignore_signal(signal) && !current_thread->is_signal_masked(signal)) {
+        current_thread->send_urgent_signal_to_self(signal);
+        return;
+    }
+
+    auto& process = current_thread->process();
 
     // If a process crashed while inspecting another process,
     // make sure we switch back to the right page tables.
@@ -316,7 +322,7 @@ void page_fault_handler(TrapFrame* trap)
     VirtualAddress userspace_sp = VirtualAddress { regs.userspace_sp() };
     if (!faulted_in_kernel && !MM.validate_user_stack(current_thread->process().address_space(), userspace_sp)) {
         dbgln("Invalid stack pointer: {}", userspace_sp);
-        handle_crash(regs, "Bad stack on page fault", SIGSEGV);
+        return handle_crash(regs, "Bad stack on page fault", SIGSEGV);
     }
 
     if (fault_address >= (FlatPtr)&start_of_ro_after_init && fault_address < (FlatPtr)&end_of_ro_after_init) {
@@ -417,7 +423,7 @@ void page_fault_handler(TrapFrame* trap)
             }
         }
 
-        handle_crash(regs, "Page Fault", SIGSEGV, response == PageFaultResponse::OutOfMemory);
+        return handle_crash(regs, "Page Fault", SIGSEGV, response == PageFaultResponse::OutOfMemory);
     } else if (response == PageFaultResponse::Continue) {
         dbgln_if(PAGE_FAULT_DEBUG, "Continuing after resolved page fault");
     } else {

+ 4 - 4
Kernel/Memory/MemoryManager.cpp

@@ -654,7 +654,7 @@ void MemoryManager::validate_syscall_preconditions(AddressSpace& space, Register
         VirtualAddress userspace_sp = VirtualAddress { regs.userspace_sp() };
         if (!MM.validate_user_stack_no_lock(space, userspace_sp)) {
             dbgln("Invalid stack pointer: {}", userspace_sp);
-            unlock_and_handle_crash("Bad stack on syscall entry", SIGSEGV);
+            return unlock_and_handle_crash("Bad stack on syscall entry", SIGSEGV);
         }
     }
 
@@ -663,17 +663,17 @@ void MemoryManager::validate_syscall_preconditions(AddressSpace& space, Register
         auto* calling_region = MM.find_user_region_from_vaddr_no_lock(space, ip);
         if (!calling_region) {
             dbgln("Syscall from {:p} which has no associated region", ip);
-            unlock_and_handle_crash("Syscall from unknown region", SIGSEGV);
+            return unlock_and_handle_crash("Syscall from unknown region", SIGSEGV);
         }
 
         if (calling_region->is_writable()) {
             dbgln("Syscall from writable memory at {:p}", ip);
-            unlock_and_handle_crash("Syscall from writable memory", SIGSEGV);
+            return unlock_and_handle_crash("Syscall from writable memory", SIGSEGV);
         }
 
         if (space.enforces_syscall_regions() && !calling_region->is_syscall_region()) {
             dbgln("Syscall from non-syscall region");
-            unlock_and_handle_crash("Syscall from non-syscall region", SIGSEGV);
+            return unlock_and_handle_crash("Syscall from non-syscall region", SIGSEGV);
         }
     }
 }

+ 6 - 0
Kernel/Thread.cpp

@@ -802,6 +802,12 @@ bool Thread::has_signal_handler(u8 signal) const
     return !action.handler_or_sigaction.is_null();
 }
 
+bool Thread::is_signal_masked(u8 signal) const
+{
+    VERIFY(signal < 32);
+    return (1 << (signal - 1)) & m_signal_mask;
+}
+
 bool Thread::has_alternative_signal_stack() const
 {
     return m_alternative_signal_stack_size != 0;

+ 1 - 0
Kernel/Thread.h

@@ -1023,6 +1023,7 @@ public:
     [[nodiscard]] bool has_unmasked_pending_signals() const { return m_have_any_unmasked_pending_signals.load(AK::memory_order_consume); }
     [[nodiscard]] bool should_ignore_signal(u8 signal) const;
     [[nodiscard]] bool has_signal_handler(u8 signal) const;
+    [[nodiscard]] bool is_signal_masked(u8 signal) const;
     u32 pending_signals() const;
     u32 pending_signals_for_state() const;