Loading...
--- xnu/xnu-12377.101.15/tests/vm_test_code_signing.c
+++ /dev/null
@@ -1,376 +0,0 @@
-#include <darwintest.h>
-#include <darwintest_utils.h>
-
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <libgen.h>
-
-#include <sys/stat.h>
-
-#include <mach/mach_init.h>
-#include <mach/mach_vm.h>
-#include <mach-o/dyld.h>
-
-T_GLOBAL_META(
- T_META_NAMESPACE("xnu.vm"),
- T_META_RADAR_COMPONENT_NAME("xnu"),
- T_META_RADAR_COMPONENT_VERSION("VM"));
-
-static int expected_code = 0;
-static int panic_on_unsigned_orig = 0;
-
-static void *
-get_sysctl_value_byname(const char *name, size_t *len)
-{
- int rc = -1;
- char *val = NULL;
- size_t val_len = 0;
-
- rc = sysctlbyname(name, NULL, &val_len, NULL, 0);
- T_QUIET;
- T_EXPECT_POSIX_SUCCESS(rc, "retrieve sysctl length");
- if (T_RESULT == T_RESULT_FAIL) {
- return NULL;
- }
-
- T_WITH_ERRNO;
- val = malloc(val_len);
- T_QUIET;
- T_EXPECT_NOTNULL(val, "malloc fail for sysctl value");
- if (T_RESULT == T_RESULT_FAIL) {
- return NULL;
- }
-
- rc = sysctlbyname(name, (void *)val, &val_len, NULL, 0);
- T_QUIET;
- T_EXPECT_POSIX_SUCCESS(rc, "retrieve sysctl byname");
- if (T_RESULT == T_RESULT_FAIL) {
- return NULL;
- } else {
- *len = val_len;
- return (void *)val;
- }
-}
-
-static bool
-cs_enforcement_disabled(void)
-{
- int *cs_enforcement = NULL;
- size_t sysctl_val_len = 0;
- bool cs_enforcement_disable = false;
-
- cs_enforcement = (int *)get_sysctl_value_byname("vm.cs_process_enforcement", &sysctl_val_len);
- T_EXPECT_NOTNULL(cs_enforcement, "sysctl vm.cs_process_enforcement");
- if (T_RESULT == T_RESULT_FAIL) {
- goto bail;
- }
-
- cs_enforcement_disable = (*cs_enforcement == 0);
-
-bail:
- if (cs_enforcement) {
- free(cs_enforcement);
- }
-
- return cs_enforcement_disable;
-}
-
-static bool
-pmap_cs_enabled(void)
-{
- const char *unavailable_reason = "<unknown>";
- char *kern_version = NULL;
- char *bootargs = NULL;
- bool platform_arm64 = false;
- bool platform_macos = false;
- bool pmap_cs_enabled = false;
- size_t sysctl_val_len = 0;
- unsigned long i;
-
-#if TARGET_CPU_ARM64
- platform_arm64 = true;
-#endif
-
- if (platform_arm64 == false) {
- unavailable_reason = "not supported on Intel platform";
- goto exit;
- }
-
-#if TARGET_OS_OSX
- platform_macos = true;
-#endif
-
- if (platform_macos == true) {
- unavailable_reason = "not supported on macOS";
- goto exit;
- }
-
- /* PMAP_CS technology is not present on below SoCs */
- const char *pmap_cs_absent_platforms[] = {"T7000", "T7001", "S8000", "S8001", "S8003", "T8002", "T8004"};
-
- kern_version = (char *)get_sysctl_value_byname("kern.version", &sysctl_val_len);
- T_EXPECT_NOTNULL(kern_version, "sysctl kern.version(%s)", kern_version);
- if (T_RESULT == T_RESULT_FAIL) {
- unavailable_reason = "unable to query sysctl kern.version";
- goto exit;
- }
-
- for (i = 0; i < sizeof(pmap_cs_absent_platforms) / sizeof(pmap_cs_absent_platforms[0]); i++) {
- if (strstr(kern_version, pmap_cs_absent_platforms[i])) {
- unavailable_reason = "not supported on this SoC platform";
- goto exit;
- }
- }
-
- /*
- * If we reach this point, it means the platform kernel has PMAP_CS code present. However
- * the code is disabled by default on certain SoCs. Moreover, the code can be disabled
- * through an explicit boot-arg as well.
- */
-
- bootargs = (char *)get_sysctl_value_byname("kern.bootargs", &sysctl_val_len);
- T_EXPECT_NOTNULL(bootargs, "sysctl kern.bootargs(%s)", bootargs);
- if (T_RESULT == T_RESULT_FAIL) {
- unavailable_reason = "unable to query sysctl kern.bootargs";
- goto exit;
- }
-
- /* Disabled explicitly through boot-arg */
- if (strstr(bootargs, "pmap_cs=0")) {
- unavailable_reason = "disabled by explicit pmap_cs=0 boot-arg";
- goto exit;
- }
-
- /* PMAP_CS technology is disabled by default on below SoCs */
- const char *pmap_cs_disabled_platforms[] = {"T8010", "T8011", "T8012", "T8015"};
-
- for (i = 0; i < sizeof(pmap_cs_disabled_platforms) / sizeof(pmap_cs_disabled_platforms[0]); i++) {
- if (strstr(kern_version, pmap_cs_disabled_platforms[i]) && !strstr(bootargs, "pmap_cs=1")) {
- unavailable_reason = "disabled by default on this SoC platform";
- goto exit;
- }
- }
-
- /* If we reach here, it means PMAP_CS is enabled */
- pmap_cs_enabled = true;
-
-exit:
- if (bootargs) {
- free(bootargs);
- }
-
- if (kern_version) {
- free(kern_version);
- }
-
- if (pmap_cs_enabled == false) {
- T_LOG("INFO: PMAP_CS is either not available or is disabled on this platform: %s", unavailable_reason);
- }
- return pmap_cs_enabled;
-}
-
-static bool
-pmap_cs_unsigned_pages_allowed(void)
-{
- char *bootargs = NULL;
- bool pmap_cs_unsigned_pages_allow = false;
- size_t sysctl_val_len = 0;
-
- bootargs = (char *)get_sysctl_value_byname("kern.bootargs", &sysctl_val_len);
- T_EXPECT_NOTNULL(bootargs, "sysctl kern.bootargs(%s)", bootargs);
- if (T_RESULT == T_RESULT_FAIL) {
- goto exit;
- }
-
- /*
- * Checking for boot-args can be tricky, since `strstr` will return based on the
- * first match for the boot-arg.
- *
- * For example: boot-args="pmap_cs_unrestrict_pmap_cs_disable=1 pmap_cs_unrestrict_pmap_cs_disable=0"
- * The following code will only catch the first one, and believe the boot-arg is set, even though
- * the kernel will parse both, and consider the latter as the actual value.
- *
- * This can be potentially fixed with `strrstr`, but that isn't standard in the C library,
- * so we don't use it.
- */
-
- if (strstr(bootargs, "pmap_cs_unrestrict_pmap_cs_disable=1")) {
- pmap_cs_unsigned_pages_allow = true;
- goto exit;
- } else if (strstr(bootargs, "amfi=1") || strstr(bootargs, "amfi=3") || strstr(bootargs, "amfi=-1")) {
- /* Any of these boot-args enable pmap_cs_unrestrict_pmap_cs_disable, but it can be overridden */
- if (!strstr(bootargs, "pmap_cs_unrestrict_pmap_cs_disable=0")) {
- /* Boot-arg is NOT overridden, so PMAP_CS will allow unsigned pages */
- pmap_cs_unsigned_pages_allow = true;
- goto exit;
- }
- }
-
- if (strstr(bootargs, "pmap_cs_allow_modified_code_pages=1")) {
- pmap_cs_unsigned_pages_allow = true;
- goto exit;
- } else if (cs_enforcement_disabled()) {
- /* cs_enforcement_disable enables pmap_cs_allow_modified_code_pages, but it can be overridden */
- if (!strstr(bootargs, "pmap_cs_allow_modified_code_pages=0")) {
- /* Boot-arg is NOT overridden, so PMAP_CS will allow unsigned pages */
- pmap_cs_unsigned_pages_allow = true;
- goto exit;
- }
- }
-
-exit:
- if (bootargs) {
- free(bootargs);
- }
-
- return pmap_cs_unsigned_pages_allow;
-}
-
-static void
-pre_test(void)
-{
- bool end_test = false;
- int *panic_on_unsigned = NULL;
- size_t sysctl_val_len = 0;
-
- /* When the test helper executes unsigned code, it returns a 1 */
- expected_code = 1;
-
- if (pmap_cs_enabled()) {
- /*
- * When PMAP_CS is enabled, VM layer delegates all executable code signing enforcement
- * to it, and doesn't participate in executable code validation. If PMAP_CS isn't allowing
- * unsigned code pages to execute, then we expect a SIGBUS error from the helper.
- */
- if (!pmap_cs_unsigned_pages_allowed()) {
- expected_code = 10;
- } else {
- T_LOG("WANRING: PMAP_CS is present but allowing unsigned code pages");
- }
- } else {
- /*
- * When PMAP_CS isn't enabled, VM layer handles all code signing enforcement, including
- * that for executable code. If VM layer isn't allowing unsigned code pages to execute, then
- * we expect a SIGKILL error from the helper.
- */
- if (!cs_enforcement_disabled()) {
- expected_code = 9;
- } else {
- T_LOG("WANRING: unsigned code pages are allowed as code signing enforcement is disabled");
- }
- }
-
-#if defined(__arm64__)
- panic_on_unsigned = (int *)get_sysctl_value_byname("vm.panic_on_unsigned_execute",
- &sysctl_val_len);
- if (panic_on_unsigned) {
- if (*panic_on_unsigned == 1) {
- panic_on_unsigned_orig = 1;
- *panic_on_unsigned = 0;
- T_EXPECT_POSIX_SUCCESS(sysctlbyname("vm.panic_on_unsigned_execute", NULL, 0, panic_on_unsigned, sizeof(int)),
- "set sysctl vm.panic_on_unsigned_execute to 0");
- if (T_RESULT == T_RESULT_FAIL) {
- end_test = true;
- goto bail;
- }
- }
- }
-#endif /* defined(__arm64__) */
-
-bail:
- if (panic_on_unsigned) {
- free(panic_on_unsigned);
- }
-
- if (end_test) {
- T_END;
- }
-
- return;
-}
-
-static void
-post_test(void)
-{
-#if defined(__arm64__)
- if (panic_on_unsigned_orig == 1) {
- T_EXPECT_POSIX_SUCCESS(sysctlbyname("vm.panic_on_unsigned_execute", NULL, 0, &panic_on_unsigned_orig, sizeof(int)),
- "restore sysctl vm.panic_on_unsigned_execute to 1");
- }
-#endif
- return;
-}
-
-static void
-check_executable(char *exec_path)
-{
- int ret = -1;
- struct stat sb;
-
- ret = stat(exec_path, &sb);
- T_QUIET;
- T_ASSERT_POSIX_SUCCESS(ret, "check executable %s", exec_path);
- T_QUIET;
- T_ASSERT_BITS_SET(sb.st_mode, S_IXUSR, "check %s EXEC permission", exec_path);
-}
-
-T_DECL(code_signing, "testing code siging with unsigned syscall code - \
- rdar://problem/23770418", T_META_RUN_CONCURRENTLY(true),
- T_META_IGNORECRASHES(".*vm_test_code_signing_helper.*"),
- T_META_ENABLED(false) /* rdar://98779213 */, T_META_TAG_VM_NOT_ELIGIBLE)
-{
- int ret = 0;
- int exit_code = 0;
- int status = 0;
- int signal = 0;
- int timeout = 30;
-
- pid_t child_pid = 0;
- bool wait_ret = true;
-
- char binary_path[MAXPATHLEN], *binary_dir = NULL;
- uint32_t path_size = sizeof(binary_path);
-
- ret = _NSGetExecutablePath(binary_path, &path_size);
- T_QUIET;
- T_ASSERT_EQ(ret, 0, "_NSGetExecutablePath: %s, size: %d",
- binary_path, path_size);
- binary_dir = dirname(binary_path);
- T_QUIET;
- T_WITH_ERRNO;
- T_ASSERT_NOTNULL(binary_dir, "get binary directory: %s", binary_dir);
-
- char *helper_binary = "vm_test_code_signing_helper";
- snprintf(binary_path, MAXPATHLEN, "%s/%s", binary_dir, helper_binary);
- check_executable(binary_path);
-
- char *helper_args[] = {binary_path, NULL};
-
- pre_test();
- T_ATEND(post_test);
-
- ret = dt_launch_tool(&child_pid, helper_args, false, NULL, NULL);
- T_ASSERT_EQ(ret, 0, "launch helper: %s", helper_binary);
-
- wait_ret = dt_waitpid(child_pid, &status, &signal, timeout);
- if (wait_ret) {
- T_LOG("helper returned: %d", status);
- exit_code = status;
- } else {
- if (signal != 0) {
- T_LOG("signal terminated helper: %d", signal);
- exit_code = signal;
- }
-
- if (status != 0) {
- T_LOG("helper exited: %d", status);
- exit_code = status;
- }
- }
-
- T_ASSERT_EQ(exit_code, expected_code, "helper exits: %d, expected: %d",
- exit_code, expected_code);
-}