From 5b01682641dddee8fad7d9df160bed215d074dcb Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Wed, 16 Jul 2025 15:23:43 -0700 Subject: [PATCH 1/2] Arm64Emitter: Disable GCS in the simulator FEX isn't going to be compatible with this. PR #4670 requires this --- FEXCore/Source/Interface/Core/ArchHelpers/Arm64Emitter.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/FEXCore/Source/Interface/Core/ArchHelpers/Arm64Emitter.cpp b/FEXCore/Source/Interface/Core/ArchHelpers/Arm64Emitter.cpp index b2893308d..753bd27b3 100644 --- a/FEXCore/Source/Interface/Core/ArchHelpers/Arm64Emitter.cpp +++ b/FEXCore/Source/Interface/Core/ArchHelpers/Arm64Emitter.cpp @@ -370,6 +370,8 @@ Arm64Emitter::Arm64Emitter(FEXCore::Context::ContextImpl* ctx, void* EmissionPtr // Hardcode a 256-bit vector width if we are running in the simulator. // Allow the user to override this. Simulator.SetVectorLengthInBits(ForceSVEWidth() ? ForceSVEWidth() : 256); + // FEX doesn't support GCS. + Simulator.DisableGCSCheck(); #endif #ifdef VIXL_DISASSEMBLER // Only setup the disassembler if enabled. From 8f1d4bc710c555559d4a562265df9657457a3b24 Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Wed, 16 Jul 2025 15:24:16 -0700 Subject: [PATCH 2/2] FEXLoader: Check for GCS being enabled There is a ELF note for this but currently clang doesn't support a `no-gcs` flag. The best we can do is check if the kernel has GCS enabled for the current process and early exit. Then continue to use the kernel's locking functionality to disable it if the guest happens to try, ensuring safety. --- Source/Tools/FEXLoader/FEXLoader.cpp | 29 ++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/Source/Tools/FEXLoader/FEXLoader.cpp b/Source/Tools/FEXLoader/FEXLoader.cpp index d9ebe995c..0081eeeba 100644 --- a/Source/Tools/FEXLoader/FEXLoader.cpp +++ b/Source/Tools/FEXLoader/FEXLoader.cpp @@ -270,6 +270,33 @@ void SetupCompatInput(bool enable) { } } // namespace FEX::CompatInput +namespace FEX::GCS { + void CheckForGCS() { +#ifndef PR_GET_SHADOW_STACK_STATUS +#define PR_GET_SHADOW_STACK_STATUS 74 +#endif +#ifndef PR_LOCK_SHADOW_STACK_STATUS +#define PR_LOCK_SHADOW_STACK_STATUS 76 +#endif +#ifndef PR_SHADOW_STACK_ENABLE +#define PR_SHADOW_STACK_ENABLE (1ULL << 0) +#endif + uint64_t ShadowStackWord {}; + if (prctl(PR_GET_SHADOW_STACK_STATUS, &ShadowStackWord, 0, 0, 0) == -1) { + return; + } + + // Kernel supports shadow stack. + if (ShadowStackWord & PR_SHADOW_STACK_ENABLE) { + // Welp. + ERROR_AND_DIE_FMT("Shadow stack is enabled which FEX is incompatible with!"); + } + + // Disable if we've gotten this far, to ensure guest can't try. + prctl(PR_LOCK_SHADOW_STACK_STATUS, ~0ULL, 0, 0, 0); + } +} + /** * @brief Get an FD from an environment variable and then unset the environment variable. * @@ -314,6 +341,8 @@ int main(int argc, char** argv, char** const envp) { return 0; } + FEX::GCS::CheckForGCS(); + FEX::Config::LoadConfig(std::move(ArgsLoader), Program.ProgramName, envp, PortableInfo); // Reload the meta layer