Skip to content

Commit

Permalink
New exception handler adoption with fallback
Browse files Browse the repository at this point in the history
https://bugs.webkit.org/show_bug.cgi?id=271489
rdar://119256062

Reviewed by Per Arne Vollan.

Patch by Brandon Kayes and Keith Miller.

This adopts the new hardened mach exception mechanism which was
introduced in darwin recently. See the radar for more details.
This attempt to land this patch should work with stale sandbox
profiles, which was causing problems with the previous iteration.

* Source/JavaScriptCore/jsc.cpp:
(main):
(CommandLine::parseArguments):
* Source/JavaScriptCore/runtime/InitializeThreading.cpp:
(JSC::initialize):
* Source/JavaScriptCore/runtime/MachineContext.h:
(JSC::MachineContext::setInstructionPointer):
* Source/JavaScriptCore/runtime/VMTraps.cpp:
* Source/JavaScriptCore/wasm/WasmFaultSignalHandler.cpp:
(JSC::Wasm::MachExceptionSigningKey::MachExceptionSigningKey):
(JSC::Wasm::trapHandler):
(JSC::Wasm::activateSignalingMemory):
(): Deleted.
* Source/JavaScriptCore/wasm/WasmFaultSignalHandler.h:
* Source/WTF/WTF.xcodeproj/project.pbxproj:
* Source/WTF/wtf/PlatformJSCOnly.cmake:
* Source/WTF/wtf/PlatformMac.cmake:
* Source/WTF/wtf/PlatformRegisters.cpp:
(WTF::threadStatePCInternal):
* Source/WTF/wtf/PlatformRegisters.h:
* Source/WTF/wtf/spi/darwin/SandboxSPI.h:
* Source/WTF/wtf/threads/Signals.cpp:
(WTF::initMachExceptionHandlerThread):
(WTF::setExceptionPorts):
(WTF::activateSignalHandlersFor):
(WTF::finalizeSignalHandlers):
(WTF::toMachMask): Deleted.
* Source/WTF/wtf/threads/Signals.h:
(WTF::toMachMask):
(WTF::initializeSignalHandling):
(WTF::disableSignalHandling):
* Source/WTF/wtf/win/SignalsWin.cpp:
(WTF::finalizeSignalHandlers):
* Source/WebKit/Resources/SandboxProfiles/ios/com.apple.WebKit.WebContent.sb.in:
* Source/WebKit/WebProcess/com.apple.WebProcess.sb.in:
* Tools/TestWebKitAPI/Tests/WTF/Signals.cpp:
(TEST):

Canonical link: https://commits.webkit.org/276579@main
  • Loading branch information
kmiller68 committed Mar 22, 2024
1 parent 7f19d5a commit 66f743c
Show file tree
Hide file tree
Showing 18 changed files with 302 additions and 63 deletions.
19 changes: 17 additions & 2 deletions Source/JavaScriptCore/jsc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3496,7 +3496,9 @@ int main(int argc, char** argv WTF_TZONE_EXTRA_MAIN_ARGS)

#if OS(UNIX)
if (getenv("JS_SHELL_WAIT_FOR_SIGUSR2_TO_EXIT")) {
initializeSignalHandling();
uint32_t key = 0;
int mask = 0;
initializeSignalHandling(key, mask);
addSignalHandler(Signal::Usr, SignalHandler([&] (Signal, SigInfo&, PlatformRegisters&) {
dataLogLn("Signal handler hit, we can exit now.");
waitToExit.signal();
Expand Down Expand Up @@ -3970,7 +3972,19 @@ void CommandLine::parseArguments(int argc, char** argv)
}
if (!strcmp(arg, "-s")) {
#if OS(UNIX)
initializeSignalHandling();
uint32_t key = 0;
int mask = 0;
#if HAVE(MACH_EXCEPTIONS)
mask |= toMachMask(Signal::IllegalInstruction);
mask |= toMachMask(Signal::AccessFault);
mask |= toMachMask(Signal::FloatingPoint);
mask |= toMachMask(Signal::Breakpoint);
#if !OS(DARWIN)
mask |= toMachMask(Signal::Abort);
#endif // !OS(DARWIN)
#endif // HAVE(MACH_EXCEPTIONS)

initializeSignalHandling(key, mask);

SignalAction (*exit)(Signal, SigInfo&, PlatformRegisters&) = [] (Signal, SigInfo&, PlatformRegisters&) {
dataLogLn("Signal handler hit. Exiting with status 0");
Expand All @@ -3993,6 +4007,7 @@ void CommandLine::parseArguments(int argc, char** argv)
addSignalHandler(Signal::Abort, SignalHandler(exit));
activateSignalHandlersFor(Signal::Abort);
#endif
finalizeSignalHandlers();
#endif
continue;
}
Expand Down
10 changes: 9 additions & 1 deletion Source/JavaScriptCore/runtime/InitializeThreading.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,15 @@ void initialize()

if (Wasm::isSupported() || !Options::usePollingTraps()) {
// JSLock::lock() can call registerThreadForMachExceptionHandling() which crashes if this has not been called first.
initializeSignalHandling();
int mask = 0;
#if CPU(ARM64E) && HAVE(HARDENED_MACH_EXCEPTIONS)
JSC::Wasm::MachExceptionSigningKey keygen;
uint32_t signingKey = keygen.randomSigningKey;
mask |= toMachMask(Signal::AccessFault);
#else
uint32_t signingKey = 0;
#endif // CPU(ARM64E) && HAVE(HARDENED_MACH_EXCEPTIONS)
initializeSignalHandling(signingKey, mask);

if (!Options::usePollingTraps())
VMTraps::initializeSignals();
Expand Down
14 changes: 14 additions & 0 deletions Source/JavaScriptCore/runtime/MachineContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ template<typename T = void*> T framePointer(const PlatformRegisters&);
inline CodePtr<PlatformRegistersLRPtrTag> linkRegister(const PlatformRegisters&);
inline std::optional<CodePtr<PlatformRegistersPCPtrTag>> instructionPointer(const PlatformRegisters&);
inline void setInstructionPointer(PlatformRegisters&, CodePtr<CFunctionPtrTag>);
inline void setInstructionPointer(PlatformRegisters&, void *);

template<size_t N> void*& argumentPointer(PlatformRegisters&);
template<size_t N> void* argumentPointer(const PlatformRegisters&);
Expand Down Expand Up @@ -463,6 +464,19 @@ inline void setInstructionPointer(PlatformRegisters& regs, CodePtr<CFunctionPtrT
instructionPointerImpl(regs) = value.taggedPtr();
#endif
}

inline void setInstructionPointer(PlatformRegisters& regs, void* value)
{
#if USE(PLATFORM_REGISTERS_WITH_PROFILE)
WTF_WRITE_PLATFORM_REGISTERS_PC_WITH_PROFILE(regs, value);
#elif USE(DARWIN_REGISTER_MACROS) && HAVE(HARDENED_MACH_EXCEPTIONS) && CPU(ARM64E)
__darwin_arm_thread_state64_set_presigned_pc_fptr(regs, value);
#elif USE(DARWIN_REGISTER_MACROS)
__darwin_arm_thread_state64_set_pc_fptr(regs, value);
#else
instructionPointerImpl(regs) = value;
#endif
}
#endif // OS(WINDOWS) || HAVE(MACHINE_CONTEXT)


Expand Down
1 change: 1 addition & 0 deletions Source/JavaScriptCore/runtime/VMTraps.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ class VMTraps::SignalSender final : public AutomaticThread {
, m_vm(vm)
{
activateSignalHandlersFor(Signal::AccessFault);
finalizeSignalHandlers();
}

static void initializeSignals()
Expand Down
25 changes: 25 additions & 0 deletions Source/JavaScriptCore/wasm/WasmFaultSignalHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,30 @@
#include "WasmExceptionType.h"
#include "WasmMemory.h"
#include "WasmThunks.h"
#include <wtf/CodePtr.h>
#include <wtf/CryptographicallyRandomNumber.h>
#include <wtf/HashSet.h>
#include <wtf/Lock.h>
#include <wtf/threads/Signals.h>

namespace JSC { namespace Wasm {

using WTF::CodePtr;

#if CPU(ARM64E) && HAVE(HARDENED_MACH_EXCEPTIONS)
void* presignedTrampoline = { };

MachExceptionSigningKey::MachExceptionSigningKey()
{
// Sign the trampoline pointer using a random diversifier and stash it away before webcontent has started so that
// even a PAC signing gadget cannot fake this random diversifier
randomSigningKey = WTF::cryptographicallyRandomNumber<uint32_t>() & __DARWIN_ARM_THREAD_STATE64_USER_DIVERSIFIER_MASK;
uint64_t diversifier = ptrauth_blend_discriminator((void *)(unsigned long)randomSigningKey, ptrauth_string_discriminator("pc"));
presignedTrampoline = JSC::LLInt::getCodePtr<CFunctionPtrTag>(wasm_throw_from_fault_handler_trampoline_reg_instance).untaggedPtr();
presignedTrampoline = ptrauth_sign_unauthenticated(presignedTrampoline, ptrauth_key_function_pointer, diversifier);
}
#endif // CPU(ARM64E) && HAVE(HARDENED_MACH_EXCEPTIONS)

namespace {
namespace WasmFaultSignalHandlerInternal {
static constexpr bool verbose = false;
Expand Down Expand Up @@ -96,6 +114,12 @@ static SignalAction trapHandler(Signal signal, SigInfo& sigInfo, PlatformRegiste
};

if (didFaultInWasm(faultingInstruction)) {
#if CPU(ARM64E) && HAVE(HARDENED_MACH_EXCEPTIONS)
if (!WTF::fallbackToOldExceptions.load()) {
MachineContext::setInstructionPointer(context, presignedTrampoline);
return SignalAction::Handled;
}
#endif
MachineContext::setInstructionPointer(context, LLInt::getCodePtr<CFunctionPtrTag>(wasm_throw_from_fault_handler_trampoline_reg_instance));
return SignalAction::Handled;
}
Expand All @@ -115,6 +139,7 @@ void activateSignalingMemory()
return;

activateSignalHandlersFor(Signal::AccessFault);
WTF::finalizeSignalHandlers();
});
}

Expand Down
9 changes: 8 additions & 1 deletion Source/JavaScriptCore/wasm/WasmFaultSignalHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
namespace JSC {

namespace Wasm {

#if ENABLE(WEBASSEMBLY)
void activateSignalingMemory();
void prepareSignalingMemory();
Expand All @@ -37,4 +36,12 @@ inline void activateSignalingMemory() { }
inline void prepareSignalingMemory() { }
#endif // ENABLE(WEBASSEMBLY)

#if CPU(ARM64E) && HAVE(HARDENED_MACH_EXCEPTIONS)
class MachExceptionSigningKey {
public:
uint32_t randomSigningKey = { };
MachExceptionSigningKey();
};
#endif // CPU(ARM64E) && HAVE(HARDENED_MACH_EXCEPTIONS)

} } // namespace JSC::Wasm
3 changes: 3 additions & 0 deletions Source/WTF/WTF.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -4064,13 +4064,15 @@
isa = XCBuildConfiguration;
baseConfigurationReference = 5D247B7014689C4700E78B76 /* DebugRelease.xcconfig */;
buildSettings = {
OTHER_MIGFLAGS = "-DMACH_EXC_SERVER_TASKIDTOKEN_STATE";
};
name = Debug;
};
5D247B6514689B8600E78B76 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 5D247B7014689C4700E78B76 /* DebugRelease.xcconfig */;
buildSettings = {
OTHER_MIGFLAGS = "-DMACH_EXC_SERVER_TASKIDTOKEN_STATE";
};
name = Release;
};
Expand All @@ -4092,6 +4094,7 @@
isa = XCBuildConfiguration;
baseConfigurationReference = 5D247B6E14689C4700E78B76 /* Base.xcconfig */;
buildSettings = {
OTHER_MIGFLAGS = "-DMACH_EXC_SERVER_TASKIDTOKEN_STATE";
};
name = Production;
};
Expand Down
2 changes: 1 addition & 1 deletion Source/WTF/wtf/PlatformJSCOnly.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ elseif (APPLE)
${WTF_DERIVED_SOURCES_DIR}/mach_excUser.c
MAIN_DEPENDENCY mac/MachExceptions.defs
WORKING_DIRECTORY ${WTF_DERIVED_SOURCES_DIR}
COMMAND mig -sheader MachExceptionsServer.h MachExceptions.defs
COMMAND mig -DMACH_EXC_SERVER_TASKIDTOKEN_STATE -sheader MachExceptionsServer.h MachExceptions.defs
VERBATIM)
list(APPEND WTF_SOURCES
cocoa/MemoryFootprintCocoa.cpp
Expand Down
2 changes: 1 addition & 1 deletion Source/WTF/wtf/PlatformMac.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ add_custom_command(
${WTF_DERIVED_SOURCES_DIR}/mach_excUser.c
MAIN_DEPENDENCY mac/MachExceptions.defs
WORKING_DIRECTORY ${WTF_DERIVED_SOURCES_DIR}
COMMAND mig -sheader MachExceptionsServer.h MachExceptions.defs
COMMAND mig -DMACH_EXC_SERVER_TASKIDTOKEN_STATE -sheader MachExceptionsServer.h MachExceptions.defs
VERBATIM)
list(APPEND WTF_SOURCES
${WTF_DERIVED_SOURCES_DIR}/mach_excServer.c
Expand Down
8 changes: 8 additions & 0 deletions Source/WTF/wtf/PlatformRegisters.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,14 @@ void* threadStateLRInternal(PlatformRegisters& regs)

void* threadStatePCInternal(PlatformRegisters& regs)
{
#if CPU(ARM64E) && HAVE(HARDENED_MACH_EXCEPTIONS)
// If userspace has modified the PC and set it to the presignedTrampoline,
// we want to avoid authing the value as it is using a custom ptrauth signing scheme.
_STRUCT_ARM_THREAD_STATE64* ts = &(regs);
if (!(ts->__opaque_flags & __DARWIN_ARM_THREAD_STATE64_FLAGS_KERNEL_SIGNED_PC))
return nullptr;
#endif // CPU(ARM64E) && HAVE(HARDENED_MACH_EXCEPTIONS)

void* candidatePC = arm_thread_state64_get_pc_fptr(regs);

#if USE(UNTAGGED_THREAD_STATE_PTR)
Expand Down
6 changes: 6 additions & 0 deletions Source/WTF/wtf/PlatformRegisters.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include <wtf/StdLibExtras.h>

#if OS(DARWIN)
#include <mach/exception_types.h>
#include <mach/thread_act.h>
#include <signal.h>
#elif OS(WINDOWS)
Expand Down Expand Up @@ -130,8 +131,13 @@ using WTF::threadStatePCInternal;
#define WTF_READ_PLATFORM_REGISTERS_PC_WITH_PROFILE(regs) \
threadStatePCInternal(const_cast<PlatformRegisters&>(regs))

#if CPU(ARM64) && HAVE(HARDENED_MACH_EXCEPTIONS)
#define WTF_WRITE_PLATFORM_REGISTERS_PC_WITH_PROFILE(regs, newPointer) \
arm_thread_state64_set_pc_presigned_fptr(regs, newPointer)
#else
#define WTF_WRITE_PLATFORM_REGISTERS_PC_WITH_PROFILE(regs, newPointer) \
arm_thread_state64_set_pc_fptr(regs, newPointer)
#endif // CPU(ARM64) && HAVE(HARDENED_MACH_EXCEPTIONS)

#define WTF_READ_MACHINE_CONTEXT_SP_WITH_PROFILE(machineContext) \
WTF_READ_PLATFORM_REGISTERS_SP_WITH_PROFILE(machineContext->__ss)
Expand Down
1 change: 1 addition & 0 deletions Source/WTF/wtf/spi/darwin/SandboxSPI.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
enum sandbox_filter_type {
SANDBOX_FILTER_NONE,
SANDBOX_FILTER_GLOBAL_NAME = 2,
SANDBOX_FILTER_PREFERENCE_DOMAIN = 6,
SANDBOX_FILTER_XPC_SERVICE_NAME = 12,
SANDBOX_FILTER_IOKIT_CONNECTION,
SANDBOX_FILTER_SYSCALL_NUMBER,
Expand Down
Loading

0 comments on commit 66f743c

Please sign in to comment.