diff --git a/Makefile b/Makefile
index 86949932..b67c9cd6 100644
--- a/Makefile
+++ b/Makefile
@@ -208,8 +208,23 @@ ifneq (,$(findstring linux,$(OS))$(findstring bsd,$(OS))$(findstring sunos,$(OS)
USE_X11 ?= 1
endif
-ifneq (,$(findstring darwin,$(OS))$(findstring serenity,$(OS)))
-# Enable SDL2 on Darwin, Serenity by default
+ifneq (,$(findstring darwin,$(OS)))
+# Enable SDL2 on Darwin by default
+USE_SDL ?= 2
+ifeq ($(USE_ISOLATION),2)
+# Foundation/Cocoa runtime
+override LDFLAGS += -lobjc -framework Cocoa
+endif
+ifeq ($(and $(if $(LTO_SUPPORTED),1),$(if $(filter 1,$(USE_DEBUG)$(USE_DEBUG_FULL)),1),$(if $(findstring clang,$(CC_INFO))$(findstring LLVM,$(CC_INFO))),1),1)
+# Generate symbols properly with lto on debug on apple clang and darwin>=15.x
+override LDFLAGS += -Wl,-object_path_lto,$(BUILDDIR)/obj/lto
+# Generate dSYM symbol bundle explicitly on darwin>=15.x, currently messy and is not used but i'll leave it as todo
+# override CFLAGS += -Wl, -dsym-dir $(BUILDDIR)/$(BINARY).dSYM
+endif
+endif
+
+ifneq (,$(findstring serenity,$(OS)))
+# Enable SDL2 on Serenity by default
USE_SDL ?= 2
endif
@@ -556,9 +571,16 @@ override CC_LD := $(CXX)
endif
# Sign binaries on MacOS host
-ifneq (,$(if $(findstring darwin,$(OS)),$(shell which codesign $(NULL_STDERR))))
-override ENTITLEMENTS := $(SRCDIR)/bindings/macos_codesign/rvvm_debug.entitlements
-override CODESIGN = codesign -s - --force --options=runtime --entitlements $(ENTITLEMENTS) $@
+ifneq (,$(findstring darwin,$(OS)),$(shell which codesign $(NULL_STDERR)),$(USE_EXPERIMENTAL_SHIT))
+ifeq ($(USE_ISOLATION),2)
+ENTITLEMENTS = $(SRCDIR)/bindings/macos_codesign/rvvm.entitlements
+# todo: fixup sdl2 loading while sandboxing is engaged, can't atm, should opt in as external lib
+# $(info $(WHITE)[$(GREEN)RPATH$(WHITE)] $(shell install_name_tool -change /opt/homebrew/Cellar/sdl2/*/lib/libSDL2-2.0.0.dylib @rpath/libSDL2-2.0.0.dylib $@ $(RESET))
+# todo: proper entitlements with a certificate authority
+override CODESIGN = $(info $(WHITE)[$(GREEN)ENT$(WHITE)] $(shell plutil $(ENTITLEMENTS)) $(RESET)) \
+ $(info $(WHITE)[$(GREEN)CODESIGN$(WHITE)] $(shell codesign -s - -d -o runtime,library --timestamp --strict --verbose=4 --preserve-metadata=entitlements,requirements,flags,runtime --entitlements $(ENTITLEMENTS) $@ 2>&1) $(RESET)) \
+ $(info $(WHITE)[$(GREEN)VERIFY$(WHITE)] $(shell spctl --assess --verbose=4 --type execute $@ 2>&1) $(RESET))
+endif
endif
#
diff --git a/src/bindings/macos_codesign/codesign.sh b/src/bindings/macos_codesign/codesign.sh
index b13a64f1..b786a977 100644
--- a/src/bindings/macos_codesign/codesign.sh
+++ b/src/bindings/macos_codesign/codesign.sh
@@ -1,2 +1,2 @@
#!/bin/sh
-codesign -s - --force --options=runtime --entitlements rvvm_debug.entitlements $@
+codesign -s - -d -o runtime,library --timestamp --strict --verbose=4 --preserve-metadata=entitlements,requirements,flags,runtime --entitlements rvvm.entitlements $@
diff --git a/src/bindings/macos_codesign/rvvm.entitlements b/src/bindings/macos_codesign/rvvm.entitlements
new file mode 100644
index 00000000..c0fedb5e
--- /dev/null
+++ b/src/bindings/macos_codesign/rvvm.entitlements
@@ -0,0 +1,26 @@
+
+
+
+
+ com.apple.security.app-sandbox
+
+ com.apple.security.library-validation
+
+ com.apple.security.network.server
+
+ com.apple.security.network.client
+
+ com.apple.security.get-task-allow
+
+ com.apple.security.cs.allow-jit
+
+ com.apple.security.hypervisor
+
+ com.apple.security.files.user-selected.read-write
+
+ com.apple.security.temporary-exception.files.absolute-path.read-only
+
+ /opt/homebrew/Cellar/sdl2/*/lib/libSDL2-2.0.0.dylib
+
+
+
diff --git a/src/bindings/macos_codesign/rvvm_debug.entitlements b/src/bindings/macos_codesign/rvvm_debug.entitlements
index ea0bb78d..abe99f30 100644
--- a/src/bindings/macos_codesign/rvvm_debug.entitlements
+++ b/src/bindings/macos_codesign/rvvm_debug.entitlements
@@ -8,6 +8,7 @@
com.apple.security.cs.disable-executable-page-protection
- com.apple.security.get-task-allow
+ com.apple.security.cs.allow-jit
+
diff --git a/src/bindings/macos_codesign/rvvm_isolement.entitlements b/src/bindings/macos_codesign/rvvm_isolement.entitlements
deleted file mode 100644
index c1ce5e6a..00000000
--- a/src/bindings/macos_codesign/rvvm_isolement.entitlements
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
- com.apple.security.cs.allow-dyld-environment-variables
-
- com.apple.security.get-task-allow
-
- com.apple.security.app-sandbox
-
- com.apple.security.inherit
-
-
-
diff --git a/src/bindings/macos_codesign/sandbox.sb b/src/bindings/macos_codesign/sandbox.sb
new file mode 100644
index 00000000..4a0831f3
--- /dev/null
+++ b/src/bindings/macos_codesign/sandbox.sb
@@ -0,0 +1 @@
+(version 3)(allow default)(allow file-read-data file-read-metadata (subpath "/opt/homebrew/Cellar/sdl2/"))(allow process-exec)(allow process-fork)
diff --git a/src/rvvm_isolation.c b/src/rvvm_isolation.c
index 503fb0f4..f594382e 100644
--- a/src/rvvm_isolation.c
+++ b/src/rvvm_isolation.c
@@ -1,6 +1,6 @@
/*
rvvm_isolation.c - Process & thread isolation
-Copyright (C) 2024 LekKit
+Copyright (C) 2024 LekKit foxxie
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -60,6 +60,23 @@ along with this program. If not, see .
#define ISOLATION_PLEDGE_IMPL
#endif
+#if defined(__APPLE__) && (USE_EXPERIMENTAL_SHIT) && CHECK_INCLUDE(objc/objc-api.h, 0)
+#include
+#include
+#if USE_ISOLATION == 1
+// Isolate with legacy
+#include
+#define ISOLATION_GATEKEEPER_IMPL1
+#elif USE_ISOLATION == 2
+// Isolate via MacOS Cocoa sandbox.
+#include
+#include
+#include
+#include
+#define ISOLATION_GATEKEEPER_IMPL2
+#endif
+#endif
+
#endif
// Drop all the capabilities of the calling thread, prevent privilege escalation
@@ -541,8 +558,70 @@ static void seccomp_setup_syscall_filter(bool all_threads) {
#endif
+#ifdef ISOLATION_GATEKEEPER_IMPL1
+static void engage_legacy_sandboxing(void) {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ #if defined(__clang__)// && defined(__llvm__)
+ #pragma clang diagnostic push
+ #pragma clang diagnostic ignored "-Wdeprecated-declarations"
+ #endif
+ char* errorbuf = "";
+ if (sandbox_init(kSBXProfileNoWriteExceptTemporary, SANDBOX_NAMED, &errorbuf)) {
+ DO_ONCE(rvvm_warn("Failed to enforce gatekeeper: %s!", errorbuf));
+ } else {
+ rvvm_info("Sandbox engaged successfully");
+ }
+ sandbox_free_error(errorbuf);
+ #if defined(__clang__)// && defined(__llvm__)
+ #pragma clang diagnostic pop
+ #endif
+ });
+};
+#endif
+
+#ifdef ISOLATION_GATEKEEPER_IMPL2
+static void engage_gatekeeper_sandboxing(void) {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ char* errorbuf = "";
+ id NSHomeDirectory (void);
+ id NSFileManager (void);
+
+ /*
+ const char nsfm = ((const char* (*)(id,SEL) &objc_getClass) (NSFileManager), sel_registerName("defaultFileManager"));
+ const char sharedManager = ((const char* (*)(id,SEL)) &objc_msgSend) nsfm;
+ id paths = objc_msgSend(NSFileManager, sel_getUid("URLsForDirectory:inDomains:"), 9, 1);
+ // NSDocumentDirectory = 9
+ id documentsDirectory = objc_msgSend(paths, sel_getUid("lastObject"));
+ // Create the file path
+ id filePath = objc_msgSend(documentsDirectory, sel_getUid("URLByAppendingPathComponent:"), objc_msgSend(objc_getClass("NSString"), sel_getUid("stringWithUTF8String:"), "your_file.txt"));
+ // Read the file
+ id fileContents = objc_msgSend(objc_getClass("NSString"), sel_getUid("stringWithContentsOfURL:encoding:error:"), filePath, 4, NULL); // NSUTF8StringEncoding = 4
+ // id NSString (char *path); // = @"/path/to/your/file.txt";
+ // id fileHandleForWritingAtPath (char *);
+
+ // For more info see: https://opensource.apple.com/source/objc4/objc4-551.1/runtime/message.h.auto.html
+ // Parameters are passed as an array containing key,value,buff.
+ // TODO: proper profile for rvvm and rvjit
+ */
+ int sandbox_init_with_parameters(const char *profile, uint64_t flags, const char *const parameters[], char **errorbuf);
+ const char profile[] = "(version 3)(allow default)(allow file-read-data file-read-metadata (subpath \"/opt/homebrew/Cellar/sdl2/\"))(allow process-exec)";
+ const char* restrict_dir = ((const char* (*)(id,SEL, char *)) &objc_msgSend) (NSHomeDirectory(), sel_registerName("UTF8String"), errorbuf);
+ const char* parameters[] = { "USER_HOME_DIR", restrict_dir, NULL };
+
+ rvvm_debug("Attempting to sandbox...\nProfile is: %s restrict_dir is: %s", profile, restrict_dir);
+
+ if (sandbox_init_with_parameters(profile, 0, parameters, &errorbuf)) {
+ rvvm_warn("Failed to enforce gatekeeper sandbox: %s!", errorbuf);
+ } else {
+ rvvm_info("Sandbox engaged successfully");
+ };
+ });
+};
+#endif
+
void rvvm_restrict_this_thread(void)
{
+ rvvm_debug("We hit thread sandboxing stage...");
drop_root_user();
drop_thread_caps();
#if defined(ISOLATION_SECCOMP_IMPL) && !defined(SANITIZERS_PRESENT)
@@ -553,6 +632,7 @@ void rvvm_restrict_this_thread(void)
PUBLIC void rvvm_restrict_process(void)
{
+ rvvm_debug("We hit process sandboxing stage...");
drop_root_user();
drop_thread_caps();
#if defined(SANITIZERS_PRESENT)
@@ -563,5 +643,10 @@ PUBLIC void rvvm_restrict_process(void)
if (pledge("stdio inet tty ioctl dns audio drm vmm error", "")) {
DO_ONCE(rvvm_warn("Failed to enforce pledge: %s!", strerror(errno)));
}
+#elif defined(ISOLATION_GATEKEEPER_IMPL1)
+ rvvm_warn("Legacy isolation used, may not work in newer versions!");
+ engage_legacy_sandboxing();
+#elif defined(ISOLATION_GATEKEEPER_IMPL2)
+ engage_gatekeeper_sandboxing();
#endif
}