xref: /xnu-10002.81.5/tests/posix_spawnattr_set_crash_behavior_np.c (revision 5e3eaea39dcf651e66cb99ba7d70e32cc4a99587)
1 #include <stdio.h>
2 #include <sys/sysctl.h>
3 #include <spawn_private.h>
4 #include <signal.h>
5 #include <sys/reason.h>
6 
7 #ifdef T_NAMESPACE
8 #undef T_NAMESPACE
9 #endif
10 #include <darwintest.h>
11 #include <darwintest_utils.h>
12 
13 T_GLOBAL_META(
14 	T_META_RADAR_COMPONENT_NAME("xnu"),
15 	T_META_RADAR_COMPONENT_VERSION("spawn"),
16 	T_META_NAMESPACE("xnu.spawn"));
17 
18 extern char **environ;
19 
20 #define SYSCTL_CRASH_BEHAVIOR_TEST_MODE "kern.crash_behavior_test_mode=1"
21 #define SYSCTL_CRASH_BEHAVIOR_WOULD_PANIC "kern.crash_behavior_test_would_panic"
22 
23 #define TEST_REASON_CODE 5
24 
25 static void
_do_set_crash_behavior_test(char * child_mode,int signal,uint32_t flags,bool expect_panic)26 _do_set_crash_behavior_test(char *child_mode, int signal, uint32_t flags, bool expect_panic)
27 {
28 	bool should_wait = (strcmp(child_mode, "wait") == 0);
29 	bool reason = (strcmp(child_mode, "reason") == 0);
30 	bool reason_signal = (strcmp(child_mode, "reason_signal") == 0);
31 	bool dirty = (strcmp(child_mode, "dirty") == 0);
32 	bool shutdown = (strcmp(child_mode, "clean") == 0) || dirty;
33 	uint64_t deadline = mach_continuous_time();
34 
35 	// 0. clear SYSCTL_CRASH_BEHAVIOR_WOULD_PANIC
36 	int would_panic = 0;
37 	size_t length = sizeof(would_panic);
38 	int ret = sysctlbyname(SYSCTL_CRASH_BEHAVIOR_WOULD_PANIC, NULL, 0, &would_panic, length);
39 	T_ASSERT_POSIX_SUCCESS(ret, "Clearing SYSCTL_CRASH_BEHAVIOR_WOULD_PANIC");
40 
41 	// 1. posix_spawn a child process
42 	char *test_program = "./posix_spawnattr_set_crash_behavior_np_child";
43 	char *child_args[3];
44 
45 	posix_spawnattr_t attrs;
46 	posix_spawnattr_init(&attrs);
47 
48 	ret = posix_spawnattr_set_crash_behavior_np(&attrs, flags);
49 	T_ASSERT_POSIX_ZERO(ret, "posix_spawnattr_set_crash_behavior_np");
50 
51 
52 	if (should_wait) {
53 		// For the purpose of the test we set the deadline to be now to avoid
54 		// making the test wait
55 		ret = posix_spawnattr_set_crash_behavior_deadline_np(&attrs, deadline, flags);
56 		T_ASSERT_POSIX_ZERO(ret, "posix_spawnattr_set_crash_behavior_deadline_np: %lld", deadline);
57 	}
58 
59 	child_args[0] = test_program;
60 	child_args[1] = child_mode;
61 	child_args[2] = NULL;
62 
63 	pid_t child_pid = 0;
64 	ret = posix_spawn(&child_pid, child_args[0], NULL, &attrs, &child_args[0], environ);
65 	T_ASSERT_POSIX_ZERO(ret, "posix_spawn");
66 	posix_spawnattr_destroy(&attrs);
67 
68 	if (should_wait) {
69 		while (mach_continuous_time() <= deadline) {
70 			usleep(1);
71 		}
72 	}
73 
74 	if (signal != 0) {
75 		ret = kill(child_pid, signal);
76 		T_ASSERT_POSIX_SUCCESS(ret, "kill(%d, %d)", child_pid, signal);
77 	}
78 
79 	if (reason) {
80 		ret = terminate_with_reason(child_pid, OS_REASON_TEST, TEST_REASON_CODE,
81 		    "Test forcing crash", OS_REASON_FLAG_CONSISTENT_FAILURE | OS_REASON_FLAG_NO_CRASH_REPORT);
82 		T_ASSERT_POSIX_SUCCESS(ret, "terminate_with_reason(%d)", child_pid);
83 	} else if (reason_signal) {
84 		ret = terminate_with_reason(child_pid, OS_REASON_SIGNAL, SIGABRT,
85 		    "Test forcing crash with signal", OS_REASON_FLAG_CONSISTENT_FAILURE | OS_REASON_FLAG_NO_CRASH_REPORT);
86 		T_ASSERT_POSIX_SUCCESS(ret, "terminate_with_reason_signal(%d)", child_pid);
87 	}
88 
89 	if (dirty) {
90 		ret = proc_set_dirty(child_pid, true);
91 		T_ASSERT_POSIX_SUCCESS(ret, "proc_set_dirty(%d)", child_pid);
92 	}
93 
94 	if (shutdown) {
95 		ret = proc_terminate(child_pid, &signal);
96 		T_ASSERT_POSIX_SUCCESS(ret, "proc_terminate(%d, %d)", child_pid, signal);
97 	}
98 
99 	// 2. Wait for the child to exit
100 	int child_status;
101 	ret = wait4(-1, &child_status, 0, NULL);
102 	T_ASSERT_POSIX_SUCCESS(ret, "wait4");
103 
104 	// 3. Check if we would have panic'ed
105 	would_panic = 0;
106 	length = sizeof(would_panic);
107 	ret = sysctlbyname(SYSCTL_CRASH_BEHAVIOR_WOULD_PANIC, &would_panic, &length, NULL, 0);
108 	T_ASSERT_POSIX_SUCCESS(ret, "SYSCTL_CRASH_BEHAVIOR_WOULD_PANIC");
109 
110 	T_EXPECT_EQ(would_panic, expect_panic, NULL);
111 }
112 
113 T_DECL(set_crash_behavior_panic_on_crash_with_crash,
114     "set_crash_behavior_panic_on_crash_with_crash",
115     T_META_SYSCTL_INT(SYSCTL_CRASH_BEHAVIOR_TEST_MODE),
116     T_META_REQUIRES_SYSCTL_EQ("kern.development", 1)) {
117 	_do_set_crash_behavior_test("crash", 0, POSIX_SPAWN_PANIC_ON_CRASH, true);
118 }
119 
120 T_DECL(set_crash_behavior_panic_on_crash_with_exit,
121     "set_crash_behavior_panic_on_crash_with_exit",
122     T_META_SYSCTL_INT(SYSCTL_CRASH_BEHAVIOR_TEST_MODE),
123     T_META_REQUIRES_SYSCTL_EQ("kern.development", 1)) {
124 	_do_set_crash_behavior_test("exit", 0, POSIX_SPAWN_PANIC_ON_CRASH, false);
125 }
126 
127 T_DECL(set_crash_behavior_panic_on_crash_with_success,
128     "set_crash_behavior_panic_on_crash_with_success",
129     T_META_SYSCTL_INT(SYSCTL_CRASH_BEHAVIOR_TEST_MODE),
130     T_META_REQUIRES_SYSCTL_EQ("kern.development", 1)) {
131 	_do_set_crash_behavior_test("success", 0, POSIX_SPAWN_PANIC_ON_CRASH, false);
132 }
133 
134 T_DECL(set_crash_behavior_panic_on_nonzero_with_crash,
135     "set_crash_behavior_panic_on_nonzero_with_crash",
136     T_META_SYSCTL_INT(SYSCTL_CRASH_BEHAVIOR_TEST_MODE),
137     T_META_REQUIRES_SYSCTL_EQ("kern.development", 1)) {
138 	_do_set_crash_behavior_test("crash", 0, POSIX_SPAWN_PANIC_ON_NON_ZERO_EXIT, false);
139 }
140 
141 T_DECL(set_crash_behavior_panic_on_nonzero_with_exit,
142     "set_crash_behavior_panic_on_nonzero_with_exit",
143     T_META_SYSCTL_INT(SYSCTL_CRASH_BEHAVIOR_TEST_MODE),
144     T_META_REQUIRES_SYSCTL_EQ("kern.development", 1)) {
145 	_do_set_crash_behavior_test("exit", 0, POSIX_SPAWN_PANIC_ON_NON_ZERO_EXIT, true);
146 }
147 
148 T_DECL(set_crash_behavior_panic_on_nonzero_with_success,
149     "set_crash_behavior_panic_on_nonzero_with_success",
150     T_META_SYSCTL_INT(SYSCTL_CRASH_BEHAVIOR_TEST_MODE),
151     T_META_REQUIRES_SYSCTL_EQ("kern.development", 1)) {
152 	_do_set_crash_behavior_test("success", 0, POSIX_SPAWN_PANIC_ON_NON_ZERO_EXIT, false);
153 }
154 
155 T_DECL(set_crash_behavior_panic_on_crash_cancelled,
156     "set_crash_behavior_panic_on_crash_cancelled",
157     T_META_SYSCTL_INT(SYSCTL_CRASH_BEHAVIOR_TEST_MODE),
158     T_META_REQUIRES_SYSCTL_EQ("kern.development", 1)) {
159 	_do_set_crash_behavior_test("wait", SIGUSR1, POSIX_SPAWN_PANIC_ON_CRASH, false);
160 }
161 
162 T_DECL(set_crash_behavior_panic_on_crash_sigterm,
163     "set_crash_behavior_panic_on_crash_sigterm",
164     T_META_SYSCTL_INT(SYSCTL_CRASH_BEHAVIOR_TEST_MODE),
165     T_META_REQUIRES_SYSCTL_EQ("kern.development", 1)) {
166 	_do_set_crash_behavior_test("spin", SIGTERM, POSIX_SPAWN_PANIC_ON_CRASH, false);
167 }
168 
169 T_DECL(set_crash_behavior_panic_on_crash_sigkill,
170     "set_crash_behavior_panic_on_crash_sigkill",
171     T_META_SYSCTL_INT(SYSCTL_CRASH_BEHAVIOR_TEST_MODE),
172     T_META_REQUIRES_SYSCTL_EQ("kern.development", 1)) {
173 	_do_set_crash_behavior_test("spin", SIGKILL, POSIX_SPAWN_PANIC_ON_CRASH, false);
174 }
175 
176 T_DECL(set_crash_behavior_panic_on_crash_terminate_with_reason,
177     "set_crash_behavior_panic_on_crash_terminate_with_reason",
178     T_META_SYSCTL_INT(SYSCTL_CRASH_BEHAVIOR_TEST_MODE),
179     T_META_REQUIRES_SYSCTL_EQ("kern.development", 1)) {
180 	_do_set_crash_behavior_test("reason", 0, POSIX_SPAWN_PANIC_ON_CRASH, true);
181 }
182 
183 T_DECL(set_crash_behavior_panic_on_crash_terminate_with_reason_signal,
184     "set_crash_behavior_panic_on_crash_terminate_with_reason_signal",
185     T_META_SYSCTL_INT(SYSCTL_CRASH_BEHAVIOR_TEST_MODE),
186     T_META_REQUIRES_SYSCTL_EQ("kern.development", 1)) {
187 	_do_set_crash_behavior_test("reason_signal", 0, POSIX_SPAWN_PANIC_ON_CRASH, true);
188 }
189 
190 T_DECL(set_crash_behavior_panic_on_crash_proc_terminate_clean,
191     "set_crash_behavior_panic_on_crash_proc_terminate_clean",
192     T_META_SYSCTL_INT(SYSCTL_CRASH_BEHAVIOR_TEST_MODE),
193     T_META_REQUIRES_SYSCTL_EQ("kern.development", 1)) {
194 	_do_set_crash_behavior_test("clean", 0, POSIX_SPAWN_PANIC_ON_CRASH, false);
195 }
196 
197 T_DECL(set_crash_behavior_panic_on_crash_proc_terminate_dirty,
198     "set_crash_behavior_panic_on_crash_proc_terminate_dirty",
199     T_META_SYSCTL_INT(SYSCTL_CRASH_BEHAVIOR_TEST_MODE),
200     T_META_REQUIRES_SYSCTL_EQ("kern.development", 1)) {
201 	_do_set_crash_behavior_test("dirty", 0, POSIX_SPAWN_PANIC_ON_CRASH, false);
202 }
203