diff --git a/Kernel/Arch/i386/CPU.cpp b/Kernel/Arch/i386/CPU.cpp index e0aa077c3b..20be34443f 100644 --- a/Kernel/Arch/i386/CPU.cpp +++ b/Kernel/Arch/i386/CPU.cpp @@ -25,6 +25,7 @@ */ #include +#include #include #include #include @@ -257,6 +258,14 @@ void page_fault_handler(TrapFrame* trap) } auto current_thread = Thread::current(); + + if (current_thread) + current_thread->set_handling_page_fault(true); + ScopeGuard guard = [current_thread] { + if (current_thread) + current_thread->set_handling_page_fault(false); + }; + if (!faulted_in_kernel && !MM.validate_user_stack(current_thread->process(), VirtualAddress(regs.userspace_esp))) { dbgln("Invalid stack pointer: {}", VirtualAddress(regs.userspace_esp)); handle_crash(regs, "Bad stack on page fault", SIGSTKFLT); diff --git a/Kernel/Thread.cpp b/Kernel/Thread.cpp index 209baa35bb..5e7a89eda5 100644 --- a/Kernel/Thread.cpp +++ b/Kernel/Thread.cpp @@ -166,6 +166,12 @@ void Thread::unblock(u8 signal) return; ASSERT(m_blocker); if (signal != 0) { + if (is_handling_page_fault()) { + // Don't let signals unblock threads that are blocked inside a page fault handler. + // This prevents threads from EINTR'ing the inode read in an inode page fault. + // FIXME: There's probably a better way to solve this. + return; + } if (!m_blocker->can_be_interrupted() && !m_should_die) return; m_blocker->set_interrupted_by_signal(signal); @@ -461,6 +467,8 @@ u32 Thread::pending_signals_for_state() const { ASSERT(g_scheduler_lock.own_lock()); constexpr u32 stopped_signal_mask = (1 << (SIGCONT - 1)) | (1 << (SIGKILL - 1)) | (1 << (SIGTRAP - 1)); + if (is_handling_page_fault()) + return 0; return m_state != Stopped ? m_pending_signals : m_pending_signals & stopped_signal_mask; } diff --git a/Kernel/Thread.h b/Kernel/Thread.h index 761fcb33a8..f1096420e2 100644 --- a/Kernel/Thread.h +++ b/Kernel/Thread.h @@ -1155,6 +1155,9 @@ public: return m_kernel_stack_region; } + bool is_handling_page_fault() const { return m_handling_page_fault; } + void set_handling_page_fault(bool b) { m_handling_page_fault = b; } + private: IntrusiveListNode m_runnable_list_node; @@ -1258,6 +1261,7 @@ private: JoinBlockCondition m_join_condition; Atomic m_is_active { false }; bool m_is_joinable { true }; + bool m_handling_page_fault { false }; unsigned m_syscall_count { 0 }; unsigned m_inode_faults { 0 };