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