From afebf73e8fa49b37cf5e45397fac536b7d62cc41 Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Tue, 28 Nov 2023 12:50:12 -0800 Subject: [PATCH] FEXCore: Moves XID check to the frontend The XID signal handler is OS specific and needs to be delegated to being handled in the frontend. This only happens when we create a thread with pthread rather than clone/fork/vfork. The first created pthread will reset the XID signal handler in glibc, which we need to check the first time this occurs. A little bit disjoint while the actual thread creation still happens in the backend but will come together once the thread creation gets moved to the frontend. The only game I am aware of that requires this to work is SOMA since its one of its middleware libraries tries asking for root privileges. Retested the game to make sure it still works as expected. --- FEXCore/Source/Interface/Context/Context.h | 1 - FEXCore/Source/Interface/Core/Core.cpp | 11 ----------- FEXCore/include/FEXCore/Core/SignalDelegator.h | 8 -------- Source/Tools/CommonTools/DummyHandlers.h | 2 -- .../Tools/FEXLoader/LinuxSyscalls/SignalDelegator.h | 8 +++++++- Source/Tools/FEXLoader/LinuxSyscalls/Syscalls.h | 4 ++++ .../Tools/FEXLoader/LinuxSyscalls/Syscalls/Thread.cpp | 11 +++++++++++ 7 files changed, 22 insertions(+), 23 deletions(-) diff --git a/FEXCore/Source/Interface/Context/Context.h b/FEXCore/Source/Interface/Context/Context.h index c9c5da72a..221074bdb 100644 --- a/FEXCore/Source/Interface/Context/Context.h +++ b/FEXCore/Source/Interface/Context/Context.h @@ -254,7 +254,6 @@ namespace FEXCore::Context { FEXCore::Core::InternalThreadState* ParentThread{}; fextl::vector Threads; std::atomic_bool CoreShuttingDown{false}; - bool NeedToCheckXID{true}; std::mutex IdleWaitMutex; std::condition_variable IdleWaitCV; diff --git a/FEXCore/Source/Interface/Core/Core.cpp b/FEXCore/Source/Interface/Core/Core.cpp index 7c09d7831..ce2ac2a5c 100644 --- a/FEXCore/Source/Interface/Core/Core.cpp +++ b/FEXCore/Source/Interface/Core/Core.cpp @@ -530,21 +530,10 @@ namespace FEXCore::Context { ExecutionThreadHandler *Arg = reinterpret_cast(FEXCore::Allocator::malloc(sizeof(ExecutionThreadHandler))); Arg->This = this; Arg->Thread = Thread; - Thread->StartPaused = NeedToCheckXID; Thread->ExecutionThread = FEXCore::Threads::Thread::Create(ThreadHandler, Arg); // Wait for the thread to have started Thread->ThreadWaiting.Wait(); - - if (NeedToCheckXID) { - // The first time an application creates a thread, GLIBC installs their SETXID signal handler. - // FEX needs to capture all signals and defer them to the guest. - // Once FEX creates its first guest thread, overwrite the GLIBC SETXID handler *again* to ensure - // FEX maintains control of the signal handler on this signal. - NeedToCheckXID = false; - SignalDelegation->CheckXIDHandler(); - Thread->StartRunning.NotifyAll(); - } } void ContextImpl::InitializeThreadTLSData(FEXCore::Core::InternalThreadState *Thread) { diff --git a/FEXCore/include/FEXCore/Core/SignalDelegator.h b/FEXCore/include/FEXCore/Core/SignalDelegator.h index 85cb0cccd..5b9fe8826 100644 --- a/FEXCore/include/FEXCore/Core/SignalDelegator.h +++ b/FEXCore/include/FEXCore/Core/SignalDelegator.h @@ -47,14 +47,6 @@ namespace Core { virtual void RegisterTLSState(FEXCore::Core::InternalThreadState *Thread) = 0; virtual void UninstallTLSState(FEXCore::Core::InternalThreadState *Thread) = 0; - /** - * @brief Check to ensure the XID handler is still set to the FEX handler - * - * On a new thread GLIBC will set the XID handler underneath us. - * After the first thread is created check this. - */ - virtual void CheckXIDHandler() = 0; - struct SignalDelegatorConfig { bool StaticRegisterAllocation{}; bool SupportsAVX{}; diff --git a/Source/Tools/CommonTools/DummyHandlers.h b/Source/Tools/CommonTools/DummyHandlers.h index a7c4bd6c6..6c2428c60 100644 --- a/Source/Tools/CommonTools/DummyHandlers.h +++ b/Source/Tools/CommonTools/DummyHandlers.h @@ -25,8 +25,6 @@ class DummySyscallHandler: public FEXCore::HLE::SyscallHandler, public FEXCore:: class DummySignalDelegator final : public FEXCore::SignalDelegator, public FEXCore::Allocator::FEXAllocOperators { public: - void CheckXIDHandler() override {} - void SignalThread(FEXCore::Core::InternalThreadState *Thread, FEXCore::Core::SignalEvent Event) override {} FEXCore::Core::InternalThreadState *GetBackingTLSThread() { diff --git a/Source/Tools/FEXLoader/LinuxSyscalls/SignalDelegator.h b/Source/Tools/FEXLoader/LinuxSyscalls/SignalDelegator.h index 3c81ae3d6..af1e23d97 100644 --- a/Source/Tools/FEXLoader/LinuxSyscalls/SignalDelegator.h +++ b/Source/Tools/FEXLoader/LinuxSyscalls/SignalDelegator.h @@ -89,7 +89,13 @@ namespace FEX::HLE { uint64_t GuestSignalFD(int fd, const uint64_t *set, size_t sigsetsize , int flags); /** @} */ - void CheckXIDHandler() override; + /** + * @brief Check to ensure the XID handler is still set to the FEX handler + * + * On a new thread GLIBC will set the XID handler underneath us. + * After the first thread is created check this. + */ + void CheckXIDHandler(); void UninstallHostHandler(int Signal); FEXCore::Context::Context *CTX; diff --git a/Source/Tools/FEXLoader/LinuxSyscalls/Syscalls.h b/Source/Tools/FEXLoader/LinuxSyscalls/Syscalls.h index 11de00ee8..afddc2a85 100644 --- a/Source/Tools/FEXLoader/LinuxSyscalls/Syscalls.h +++ b/Source/Tools/FEXLoader/LinuxSyscalls/Syscalls.h @@ -225,6 +225,9 @@ public: SourcecodeResolver *GetSourcecodeResolver() override { return this; } + bool NeedXIDCheck() const { return NeedToCheckXID; } + void DisableXIDCheck() { NeedToCheckXID = false; } + protected: SyscallHandler(FEXCore::Context::Context *_CTX, FEX::HLE::SignalDelegator *_SignalDelegation); @@ -250,6 +253,7 @@ private: std::mutex FutexMutex; std::mutex SyscallMutex; FEXCore::CodeLoader *LocalLoader{}; + bool NeedToCheckXID{true}; #ifdef DEBUG_STRACE void Strace(FEXCore::HLE::SyscallArguments *Args, uint64_t Ret); diff --git a/Source/Tools/FEXLoader/LinuxSyscalls/Syscalls/Thread.cpp b/Source/Tools/FEXLoader/LinuxSyscalls/Syscalls/Thread.cpp index 22f8adcd4..fd08ca73c 100644 --- a/Source/Tools/FEXLoader/LinuxSyscalls/Syscalls/Thread.cpp +++ b/Source/Tools/FEXLoader/LinuxSyscalls/Syscalls/Thread.cpp @@ -59,8 +59,19 @@ namespace FEX::HLE { } auto NewThread = CTX->CreateThread(0, 0, &NewThreadState, args->args.parent_tid); + bool NeedsXIDCheck = FEX::HLE::_SyscallHandler->NeedXIDCheck(); + NewThread->StartPaused = NeedsXIDCheck; CTX->InitializeThread(NewThread); + if (NeedsXIDCheck) { + // The first time an application creates a thread, GLIBC installs their SETXID signal handler. + // FEX needs to capture all signals and defer them to the guest. + // Once FEX creates its first guest thread, overwrite the GLIBC SETXID handler *again* to ensure + // FEX maintains control of the signal handler on this signal. + FEX::HLE::_SyscallHandler->GetSignalDelegator()->CheckXIDHandler(); + FEX::HLE::_SyscallHandler->DisableXIDCheck(); + } + if (FEX::HLE::_SyscallHandler->Is64BitMode()) { if (flags & CLONE_SETTLS) { x64::SetThreadArea(NewThread->CurrentFrame, reinterpret_cast(args->args.tls));