// Apple Internal Sanitizer dylib path
SANITIZER_DYLIB_DIR = /usr/appleinternal/lib/sanitizers
-ASAN_CFLAGS_ =
-ASAN_CFLAGS_YES = -DCURRENT_VARIANT_asan=1
-ASAN_LDFLAGS_ =
+ASAN_CFLAGS_NO =
+ASAN_CFLAGS_YES = -DSUPPORT_ASAN=1
+ASAN_LDFLAGS_NO =
SHARED_ASAN_LDFLAGS = -L $(SDKROOT)$(SANITIZER_DYLIB_DIR) -Xlinker -not_for_dyld_shared_cache -rpath $(SANITIZER_DYLIB_DIR)/
ASAN_LDFLAGS_YES[sdk=macosx*] = $(SHARED_ASAN_LDFLAGS) -Xlinker -upward-lclang_rt.asan_osx_dynamic
ASAN_LDFLAGS_YES[sdk=iphoneos*] = $(SHARED_ASAN_LDFLAGS) -Xlinker -upward-lclang_rt.asan_ios_dynamic
ASAN_LDFLAGS_YES[sdk=watchos*] = $(SHARED_ASAN_LDFLAGS) -Xlinker -upward-lclang_rt.asan_watchos_dynamic
ASAN_LDFLAGS_YES[sdk=appletvos*] = $(SHARED_ASAN_LDFLAGS) -Xlinker -upward-lclang_rt.asan_tvos_dynamic
ASAN_LDFLAGS_YES[sdk=bridgeos*] = $(SHARED_ASAN_LDFLAGS) -Xlinker -upward-lclang_rt.asan_bridgeos_dynamic
-ASAN_IN_NORMAL_VARIANT_CFLAGS = $(ASAN_CFLAGS_$(ASAN_IN_NORMAL_VARIANT))
-ASAN_IN_NORMAL_VARIANT_LDFLAGS = $(ASAN_LDFLAGS_$(ASAN_IN_NORMAL_VARIANT))
+
+// "no_asan" variant
+//
+// The "no_asan" variant is only built when ASAN_IN_NORMAL_VARIANT=YES.
+// The variant exists to provide a way to opt-out processes from the
+// "Whole OS ASan" mode. It should be identical to the "normal" variant
+// except it does **not** upward link the ASan runtime. Despite the name,
+// this does not enforce that ASan is not used. This is because an ASan
+// instrumented binary could also cause the ASan runtime to be loaded.
+NOASAN_CFLAGS_YES = $(ASAN_CFLAGS_YES)
+NOASAN_LDFLAGS_YES =
+EXTRA_BUILD_VARIANTS_ASAN_IN_NORMAL_VARIANT_NO =
+EXTRA_BUILD_VARIANTS_ASAN_IN_NORMAL_VARIANT_YES = no_asan
+EXTRA_BUILD_VARIANTS_ASAN_IN_NORMAL_VARIANT = $(EXTRA_BUILD_VARIANTS_ASAN_IN_NORMAL_VARIANT_$(ASAN_IN_NORMAL_VARIANT))
SDK_INSTALL_VARIANT = $(SDK_INSTALL_VARIANT_$(DRIVERKIT))
SDK_INSTALL_VARIANT_1 = driverkit
SDK_RUNTIME_HEADERS_PREFIX = Runtime
BUILD_VARIANTS = $(BUILD_VARIANTS_$(SDK_INSTALL_VARIANT))
-BUILD_VARIANTS_default = normal debug asan
+BUILD_VARIANTS_default = normal debug asan $(EXTRA_BUILD_VARIANTS_ASAN_IN_NORMAL_VARIANT)
BUILD_VARIANTS_driverkit = normal debug
SUPPORTED_PLATFORMS = macosx iphoneos iphonesimulator appletvos appletvsimulator watchos watchsimulator
INSTALL_PATH = $(SDK_INSTALL_ROOT)/usr/lib
ORDER_FILE[sdk=driverkit*] =
SYSTEM_HEADER_SEARCH_PATHS = $(SDKROOT)/$(SDK_INSTALL_HEADERS_ROOT)/System/Library/Frameworks/System.framework/PrivateHeaders $(SDKROOT)/$(SDK_INSTALL_HEADERS_ROOT)/usr/local/include $(SDKROOT)/$(SDK_INSTALL_HEADERS_ROOT)/usr/include
SYSTEM_FRAMEWORK_SEARCH_PATHS = $(SDKROOT)/$(SDK_INSTALL_HEADERS_ROOT)/System/Library/PrivateFrameworks $(SDKROOT)/$(SDK_INSTALL_HEADERS_ROOT)/System/Library/Frameworks
-OTHER_CFLAGS = -include $(BUILT_PRODUCTS_DIR)/config.$(CURRENT_ARCH).$(CURRENT_VARIANT).h -DCURRENT_VARIANT_$(CURRENT_VARIANT)=1 $(ASAN_IN_NORMAL_VARIANT_CFLAGS)
-OTHER_LDFLAGS = -Wl,-search_paths_first -nodefaultlibs @$(BUILT_PRODUCTS_DIR)/linker_arguments.$(CURRENT_ARCH).$(CURRENT_VARIANT).txt $(ASAN_IN_NORMAL_VARIANT_LDFLAGS) $(DRIVERKIT_LDFLAGS)
+
+OTHER_CFLAGS = -include $(BUILT_PRODUCTS_DIR)/config.$(CURRENT_ARCH).$(CURRENT_VARIANT).h -DCURRENT_VARIANT_$(CURRENT_VARIANT)=1
+OTHER_CFLAGS_normal = $(ASAN_CFLAGS_$(ASAN_IN_NORMAL_VARIANT:default=NO))
+// Preserve existing behaviour of modifying debug variant.
+OTHER_CFLAGS_debug = $(ASAN_CFLAGS_$(ASAN_IN_NORMAL_VARIANT:default=NO))
+OTHER_CFLAGS_asan = $(ASAN_CFLAGS_YES)
+OTHER_CFLAGS_no_asan = $(NOASAN_CFLAGS_YES)
+
+OTHER_LDFLAGS = -Wl,-search_paths_first -nodefaultlibs @$(BUILT_PRODUCTS_DIR)/linker_arguments.$(CURRENT_ARCH).$(CURRENT_VARIANT).txt $(DRIVERKIT_LDFLAGS)
+OTHER_LDFLAGS_normal = $(ASAN_LDFLAGS_$(ASAN_IN_NORMAL_VARIANT:default=NO))
+// Preserve existing behaviour of modifying debug variant.
+OTHER_LDFLAGS_debug = $(ASAN_LDFLAGS_$(ASAN_IN_NORMAL_VARIANT:default=NO))
OTHER_LDFLAGS_asan = $(ASAN_LDFLAGS_YES)
+OTHER_LDFLAGS_no_asan = $(NOASAN_LDFLAGS_YES)
+
+
// whitelist of libraries in DriverKit SDK allowed to link directly against libSystem.dylib (outside of the umbrella)
DRIVERKIT_LDFLAGS[sdk=driverkit*] = -Wl,-allowable_client,c++ -Wl,-allowable_client,c++abi -Wl,-allowable_client,DriverKit
LD_GENERATE_MAP_FILE = YES
#include <pthread/private.h>
#if !TARGET_OS_DRIVERKIT
#include <dlfcn.h>
+#include <os/variant_private.h>
#endif
#include <fcntl.h>
#include <errno.h>
void libSystem_atfork_parent(void);
void libSystem_atfork_child(void);
-#if CURRENT_VARIANT_asan
+#if SUPPORT_ASAN
const char *__asan_default_options(void);
#endif
#endif
};
- static const struct _malloc_functions malloc_funcs = {
- .version = 1,
-#if !TARGET_OS_DRIVERKIT
- .dlopen = dlopen,
- .dlsym = dlsym,
-#endif
- };
-
_libSystem_ktrace0(ARIADNE_LIFECYCLE_libsystem_init | DBG_FUNC_START);
__libkernel_init(&libkernel_funcs, envp, apple, vars);
_libxpc_initializer();
_libSystem_ktrace_init_func(LIBXPC);
-#if CURRENT_VARIANT_asan
+#if SUPPORT_ASAN
setenv("DT_BYPASS_LEAKS_CHECK", "1", 1);
#endif
#endif // !TARGET_OS_DRIVERKIT
_libSystem_ktrace_init_func(DARWIN);
#endif // !TARGET_OS_DRIVERKIT
- __stack_logging_early_finished(&malloc_funcs);
+ const struct _malloc_late_init mli = {
+ .version = 1,
+#if !TARGET_OS_DRIVERKIT
+ .dlopen = dlopen,
+ .dlsym = dlsym,
+ // this must come after _libxpc_initializer()
+ .internal_diagnostics = os_variant_has_internal_diagnostics("com.apple.libsystem"),
+#endif
+ };
+
+ __malloc_late_init(&mli);
#if !TARGET_OS_IPHONE
/* <rdar://problem/22139800> - Preserve the old behavior of apple[] for
_pthread_atfork_child_handlers();
}
-#if CURRENT_VARIANT_asan
-#define DEFAULT_ASAN_OPTIONS "color=never" \
- ":handle_segv=0:handle_sigbus=0:handle_sigill=0:handle_sigfpe=0" \
- ":external_symbolizer_path=" \
- ":log_path=stderr:log_exe_name=0" \
- ":halt_on_error=0" \
- ":print_module_map=2" \
- ":start_deactivated=1" \
- ":detect_odr_violation=0"
+#if SUPPORT_ASAN
+
+// Prevents use of coloring terminal signals in report. These
+// hinder readability when writing to files or the system log.
+#define ASAN_OPT_NO_COLOR "color=never"
+
+// Disables ASan's signal handlers. It's better to let the system catch
+// these kinds of crashes.
+#define ASAN_OPT_NO_SIGNAL_HANDLERS ":handle_segv=0:handle_sigbus=0:handle_sigill=0:handle_sigfpe=0"
+
+// Disables using the out-of-process symbolizer (atos) but still allows
+// in-process symbolization via `dladdr()`. This gives useful function names
+// (unless they are redacted) which can be helpful in the event we can't
+// symbolize offline. Out-of-process symbolization isn't useful because
+// the dSYMs are usually not present on the device.
+#define ASAN_OPT_NO_OOP_SYMBOLIZER ":external_symbolizer_path="
+
+// Don't try to log to a file. It's difficult to find a location for the file
+// that is writable so just write to stderr.
+#define ASAN_OPT_FILE_LOG ":log_path=stderr:log_exe_name=0"
+
+// Print the module map when finding an issue. This is necessary for offline
+// symbolication.
+#define ASAN_OPT_MODULE_MAP ":print_module_map=2"
+
+// Disable ODR violation checking.
+// <rdar://problem/71021707> Investigate enabling ODR checking for ASan in BATS and in the `_asan` variant
+#define ASAN_OPT_NO_ODR_VIOLATION ":detect_odr_violation=0"
+
+// Start ASan in deactivated mode. This reduces memory overhead until
+// instrumented code is loaded. This prevents catching bugs if no instrumented
+// code is loaded.
+#define ASAN_OPT_START_DEACTIVATED ":start_deactivated=1"
+
+// Do not crash when an error is found. This always works for errors caught via
+// ASan's interceptors. This won't work for errors caught in ASan
+// instrumentation unless the code is compiled with
+// `-fsanitize-recover=address`. If this option is being used then the ASan
+// reports can only be found by looking at the system log.
+#define ASAN_OPT_NO_HALT_ON_ERROR ":halt_on_error=0"
+
+// Crash when an error is found.
+#define ASAN_OPT_HALT_ON_ERROR ":halt_on_error=1"
+
+// ASan options common to all supported variants
+#define COMMON_ASAN_OPTIONS \
+ ASAN_OPT_NO_COLOR \
+ ASAN_OPT_NO_SIGNAL_HANDLERS \
+ ASAN_OPT_NO_OOP_SYMBOLIZER \
+ ASAN_OPT_FILE_LOG \
+ ASAN_OPT_MODULE_MAP \
+ ASAN_OPT_NO_ODR_VIOLATION
+
+#if defined(CURRENT_VARIANT_normal) || defined(CURRENT_VARIANT_debug) || defined (CURRENT_VARIANT_no_asan)
+
+// In the normal variant ASan will be running in all userspace processes ("whole userspace ASan").
+// This mode exists to support "ASan in BATS".
+//
+// Supporting ASan in the debug variant preserves existing behavior.
+//
+// The no_asan variant does not load the ASan runtime. However, the runtime
+// might still be loaded if a program or its dependencies are instrumented.
+// There is nothing we can do to prevent this so we should set the appropriate
+// ASan options (same as normal variant) if it does happen. We try to do this
+// here but this currently doesn't work due to rdar://problem/72212914.
+//
+// These variants use the following extra options:
+//
+// ASAN_OPT_NO_HALT_ON_ERROR - Try to avoid crash loops and increase the
+// chances of booting successfully.
+// ASAN_OPT_START_DEACTIVATED - Try to reduce memory overhead.
+
+# define DEFAULT_ASAN_OPTIONS \
+ COMMON_ASAN_OPTIONS \
+ ASAN_OPT_START_DEACTIVATED \
+ ASAN_OPT_NO_HALT_ON_ERROR
+
+#elif defined(CURRENT_VARIANT_asan)
+
+// The `_asan` variant is used to support running proceses with
+// `DYLD_IMAGE_SUFFIX=_asan`. This mode is typically used to target select parts of the OS.
+//
+// It uses the following extra options:
+//
+// ASAN_OPT_HALT_ON_ERROR - Crashing is better than just writing the error to the system log
+// if the system can handle this. This workflow is
+// more tolerant (e.g. `launchctl debug`) to crashing
+// than the "whole userspace ASan" workflow.
+
+# define DEFAULT_ASAN_OPTIONS \
+ COMMON_ASAN_OPTIONS \
+ ASAN_OPT_HALT_ON_ERROR
+
+#else
+# error Supporting ASan is not supported in the current variant
+#endif
+
char dynamic_asan_opts[1024] = {0};
const char *__asan_default_options(void) {
- char executable_path[4096] = {0};
- uint32_t size = sizeof(executable_path);
- const char *process_name = "";
- if (_NSGetExecutablePath(executable_path, &size) == 0) {
- process_name = strrchr(executable_path, '/') + 1;
- }
-
int fd = open("/System/Library/Preferences/com.apple.asan.options", O_RDONLY);
if (fd != -1) {
ssize_t remaining_size = sizeof(dynamic_asan_opts) - 1;
return DEFAULT_ASAN_OPTIONS;
}
+
+#undef ASAN_OPT_NO_COLOR
+#undef ASAN_OPT_NO_SIGNAL_HANDLERS
+#undef ASAN_OPT_NO_OOP_SYMBOLIZER
+#undef ASAN_OPT_FILE_LOG
+#undef ASAN_OPT_MODULE_MAP
+#undef ASAN_OPT_NO_ODR_VIOLATION
+#undef ASAN_OPT_START_DEACTIVATED
+#undef ASAN_OPT_NO_HALT_ON_ERROR
+#undef ASAN_OPT_HALT_ON_ERROR
+
+#undef COMMON_ASAN_OPTIONS
+#undef DEFAULT_ASAN_OPTIONS
+
#endif
/*