Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 | #include <darwintest.h> #include <signal.h> #include <spawn.h> #include <unistd.h> #include <stdlib.h> #include <sys/wait.h> #include <libproc.h> #include <sys/reason.h> #include <sys/sysctl.h> #include <TargetConditionals.h> T_GLOBAL_META( T_META_NAMESPACE("xnu.spawn"), T_META_RADAR_COMPONENT_NAME("xnu"), T_META_RADAR_COMPONENT_VERSION("spawn"), T_META_ENABLED(TARGET_OS_OSX)); static void __run_cmd(const char *cmd_prefix, const char *filename, const char *error) { char cmd[PATH_MAX]; strlcpy(cmd, cmd_prefix, sizeof(cmd)); strlcat(cmd, filename, sizeof(cmd)); FILE *file = popen(cmd, "r"); T_QUIET; T_WITH_ERRNO; T_ASSERT_NOTNULL(file, "%s (cmd = %s)", error, cmd); pclose(file); } static void __spawn_exec(const char *args[], short flags) { posix_spawnattr_t attr; int error; error = posix_spawnattr_init(&attr); T_QUIET; T_ASSERT_POSIX_SUCCESS(error, "spawn attributes initialized"); error = posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETEXEC | flags); T_QUIET; T_ASSERT_POSIX_SUCCESS(error, "spawn attributes flags set"); posix_spawnp(NULL, args[0], NULL, &attr, args, NULL); } static void invalid_code_signature_helper() { char filename[PATH_MAX]; sprintf(filename, "/tmp/echo-test-%ld", random()); T_LOG("temporary file created: %s", filename); __run_cmd("cp /bin/echo ", filename, "create a temporary copy"); __run_cmd("codesign --force --sign - --team-identifier 0 ", filename, "codesign the temporary copy with an invalid team ID"); /* Exec into the modified binary */ const char* args[] = { filename, NULL }; __spawn_exec(args, 0); } static void bad_spawnattr_helper() { const char* args[] = { "/bin/echo", NULL}; int error; error = setsid(); T_QUIET; T_ASSERT_POSIX_SUCCESS(error, "set SID before exec"); __spawn_exec(args, POSIX_SPAWN_SETSID); } static bool is_cs_enforcement_enabled() { static const size_t max_size = 4096; bool result; size_t args_size = max_size; char *bootargs = calloc(max_size, 1); int err = sysctlbyname("kern.bootargs", bootargs, &args_size, NULL, 0); if (err) { T_LOG("sysctlbyname failed. err=%d", errno); result = false; } else if (strnstr(bootargs, "cs_enforcement_disable=1", max_size)) { result = false; } else { result = true; } free(bootargs); return result; } static void setup_child_and_wait_for_exit( void (*do_exec)(void), uint64_t expected_reason_namespace, uint64_t expected_reason_code) { pid_t child = fork(); if (child > 0) { int status, ret; struct proc_exitreasonbasicinfo exit_reason; sleep(1); ret = proc_pidinfo(child, PROC_PIDEXITREASONBASICINFO, 1, &exit_reason, PROC_PIDEXITREASONBASICINFOSIZE); T_QUIET; T_ASSERT_EQ(ret, PROC_PIDEXITREASONBASICINFOSIZE, "retrive basic exit reason info"); waitpid(child, &status, 0); T_QUIET; T_EXPECT_FALSE(WIFEXITED(status), "process did not exit normally"); T_QUIET; T_EXPECT_TRUE(WIFSIGNALED(status), "process was terminated because of a signal"); T_EXPECT_EQ(WTERMSIG(status), SIGKILL, "process was SIGKILLed"); T_EXPECT_EQ(exit_reason.beri_namespace, expected_reason_namespace, "killed with reason EXEC"); T_EXPECT_EQ(exit_reason.beri_code, expected_reason_code, "reason code is %d", expected_reason_code); } else { do_exec(); T_FAIL("Shouldn't reach here!"); } } T_DECL(spawn_exec_double_set_sid, "exec fails upon trying to set SID twice") { setup_child_and_wait_for_exit(bad_spawnattr_helper, OS_REASON_EXEC, EXEC_EXIT_REASON_BAD_PSATTR); } T_DECL(spawn_exec_invalid_cs, "exec fails due to invalid code signature", T_META_ENABLED(false /* rdar://133462284 */) ) { if (!is_cs_enforcement_enabled()) { T_SKIP("cs enforcement is disabled."); } #if defined(__arm64__) setup_child_and_wait_for_exit(invalid_code_signature_helper, OS_REASON_EXEC, EXEC_EXIT_REASON_SECURITY_POLICY); #else /* __arm64__ */ setup_child_and_wait_for_exit(invalid_code_signature_helper, OS_REASON_CODESIGNING, CODESIGNING_EXIT_REASON_TASKGATED_INVALID_SIG); #endif /* __arm64__ */ } |