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