]> git.saurik.com Git - apple/xnu.git/blob - tools/tests/unit_tests/guarded_fd_tests_11746236_src/guarded_test_framework.c
9fdc2d770989f48904fc22e3f887e29c59e7d419
[apple/xnu.git] / tools / tests / unit_tests / guarded_fd_tests_11746236_src / guarded_test_framework.c
1 /*
2 * Testing Framework for EXC_GUARD exceptions
3 *
4 * The framework tests for exception conditions for guarded fds.
5 * It creates a new exception port and an associated handling thread.
6 * For each test case, the framework sets its own exception port to the
7 * newly allocated port, execs a new child (which inherits the new
8 * exception port) and restores the parent's exception port to the
9 * original handler. The child process is invoked with a different
10 * test case identifier and invokes the corresponding test case.
11 *
12 */
13
14 #include <stdio.h>
15 #include <spawn.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <unistd.h>
19 #include <signal.h>
20 #include <pthread.h>
21 #include <mach/mach.h>
22 #include <sys/guarded.h>
23 #include <spawn_private.h>
24 #include <libproc_internal.h>
25 #include "guarded_test_common.h"
26 #include <mach_exc.h>
27
28 #define MAX_TEST_ID_LEN 16
29 #define MAX_ARGV 8
30 #define EXC_GUARD_FLAVOR_SHIFT 32
31 #define EXC_GUARD_TYPE_SHIFT 61
32 #define EXC_GUARD_FD_MASK 0xFFFFFFFF
33
34 /*
35 * To add a new test case to this framework:
36 * - Increment the NUMTESTS value
37 * - Add (Guard Type | flavor) to "test_exception_code" if the
38 * test case generates an exception; 0 otherwise
39 * - Add CHK_TEST_FD/IGN_TEST_FD depending on whether
40 * framework should look for TEST_FD in the exception message
41 * - Add a new case and routine in guarded_test.c to
42 * test the scenario
43 */
44
45 #define NUMTESTS 11
46
47 uint64_t test_exception_code[] = {
48 (((uint64_t)GUARD_TYPE_FD) << EXC_GUARD_TYPE_SHIFT) | (((uint64_t)kGUARD_EXC_CLOSE) << EXC_GUARD_FLAVOR_SHIFT),
49 (((uint64_t)GUARD_TYPE_FD) << EXC_GUARD_TYPE_SHIFT) | (((uint64_t)kGUARD_EXC_DUP) << EXC_GUARD_FLAVOR_SHIFT),
50 (((uint64_t)GUARD_TYPE_FD) << EXC_GUARD_TYPE_SHIFT) | (((uint64_t)kGUARD_EXC_NOCLOEXEC) << EXC_GUARD_FLAVOR_SHIFT),
51 0,
52 0,
53 0,
54 (((uint64_t)GUARD_TYPE_FD) << EXC_GUARD_TYPE_SHIFT) | (((uint64_t)kGUARD_EXC_FILEPORT) << EXC_GUARD_FLAVOR_SHIFT),
55 (((uint64_t)GUARD_TYPE_FD) << EXC_GUARD_TYPE_SHIFT) | (((uint64_t)kGUARD_EXC_SOCKET_IPC) << EXC_GUARD_FLAVOR_SHIFT),
56 0,
57 (((uint64_t)GUARD_TYPE_FD) << EXC_GUARD_TYPE_SHIFT) | (((uint64_t)kGUARD_EXC_CLOSE) << EXC_GUARD_FLAVOR_SHIFT),
58 (((uint64_t)GUARD_TYPE_FD) << EXC_GUARD_TYPE_SHIFT) | (((uint64_t)kGUARD_EXC_CLOSE) << EXC_GUARD_FLAVOR_SHIFT)
59 };
60
61 #define CHK_TEST_FD 1
62 #define IGN_TEST_FD 0
63
64 uint64_t test_fd[] = {
65 CHK_TEST_FD,
66 IGN_TEST_FD,
67 IGN_TEST_FD,
68 IGN_TEST_FD,
69 IGN_TEST_FD,
70 IGN_TEST_FD,
71 IGN_TEST_FD,
72 IGN_TEST_FD,
73 IGN_TEST_FD,
74 IGN_TEST_FD,
75 IGN_TEST_FD
76 };
77
78 mach_port_t exc_port;
79 uint64_t exception_code;
80 extern char **environ;
81
82 boolean_t mach_exc_server(
83 mach_msg_header_t *InHeadP,
84 mach_msg_header_t *OutHeadP);
85
86 kern_return_t catch_mach_exception_raise
87 (
88 mach_port_t exception_port,
89 mach_port_t thread,
90 mach_port_t task,
91 exception_type_t exception,
92 mach_exception_data_t code,
93 mach_msg_type_number_t codeCnt,
94 int *flavor,
95 thread_state_t old_state,
96 mach_msg_type_number_t old_stateCnt,
97 thread_state_t new_state,
98 mach_msg_type_number_t *new_stateCnt
99 )
100 {
101 if (exception == EXC_GUARD) {
102 /* Set global variable to indicate exception received */
103 exception_code = *((uint64_t *)code);
104 } else {
105 /* Terminate test on all other unexpected exceptions */
106 fprintf(stderr, "received unexpected exception type %#x\n", exception);
107 exit(1);
108 }
109
110 return (KERN_SUCCESS);
111 }
112
113 kern_return_t catch_mach_exception_raise_state
114 (
115 mach_port_t exception_port,
116 exception_type_t exception,
117 const mach_exception_data_t code,
118 mach_msg_type_number_t codeCnt,
119 int *flavor,
120 const thread_state_t old_state,
121 mach_msg_type_number_t old_stateCnt,
122 thread_state_t new_state,
123 mach_msg_type_number_t *new_stateCnt
124 )
125 {
126 fprintf(stderr, "Unexpected exception handler called\n");
127 exit(1);
128 return (KERN_FAILURE);
129 }
130
131
132 kern_return_t catch_mach_exception_raise_state_identity
133 (
134 mach_port_t exception_port,
135 mach_port_t thread,
136 mach_port_t task,
137 exception_type_t exception,
138 mach_exception_data_t code,
139 mach_msg_type_number_t codeCnt
140 )
141 {
142 fprintf(stderr, "Unexpected exception handler called\n");
143 exit(1);
144 return (KERN_FAILURE);
145 }
146
147
148 void *server_thread(void *arg)
149 {
150 kern_return_t kr;
151
152 while(1) {
153 /* Handle exceptions on exc_port */
154 if ((kr = mach_msg_server_once(mach_exc_server, 4096, exc_port, 0)) != KERN_SUCCESS) {
155 fprintf(stderr, "mach_msg_server_once: error %#x\n", kr);
156 exit(1);
157 }
158 }
159 return (NULL);
160 }
161
162 int main(int argc, char *argv[])
163 {
164 posix_spawnattr_t attrs;
165 kern_return_t kr;
166 mach_port_t task = mach_task_self();
167
168 mach_msg_type_number_t maskCount = 1;
169 exception_mask_t mask;
170 exception_handler_t handler;
171 exception_behavior_t behavior;
172 thread_state_flavor_t flavor;
173 pthread_t exception_thread;
174 uint64_t exc_id;
175 unsigned int exc_fd;
176
177 char *test_prog_name = "./guarded_test";
178 char *child_args[MAX_ARGV];
179 char test_id[MAX_TEST_ID_LEN];
180 int i, err;
181 int child_status;
182 int test_status = 0;
183
184 /* Allocate and initialize new exception port */
185 if ((kr = mach_port_allocate(task, MACH_PORT_RIGHT_RECEIVE, &exc_port)) != KERN_SUCCESS) {
186 fprintf(stderr, "mach_port_allocate: %#x\n", kr);
187 exit(1);
188 }
189
190 if ((kr = mach_port_insert_right(task, exc_port,
191 exc_port, MACH_MSG_TYPE_MAKE_SEND)) != KERN_SUCCESS) {
192 fprintf(stderr, "mach_port_allocate: %#x\n", kr);
193 exit(1);
194 }
195
196 /* Get Current exception ports */
197 if ((kr = task_get_exception_ports(task, EXC_MASK_GUARD, &mask,
198 &maskCount, &handler, &behavior, &flavor)) != KERN_SUCCESS) {
199 fprintf(stderr,"task_get_exception_ports: %#x\n", kr);
200 exit(1);
201 }
202
203 /* Create exception serving thread */
204 if ((err = pthread_create(&exception_thread, NULL, server_thread, 0)) != 0) {
205 fprintf(stderr, "pthread_create server_thread: %s\n", strerror(err));
206 exit(1);
207 }
208
209 pthread_detach(exception_thread);
210
211 /* Initialize posix_spawn attributes */
212 posix_spawnattr_init(&attrs);
213
214 if ((err = posix_spawnattr_setflags(&attrs, POSIX_SPAWN_SETEXEC)) != 0) {
215 fprintf(stderr, "posix_spawnattr_setflags: %s\n", strerror(err));
216 exit(1);
217 }
218
219 /* Run Tests */
220 for(i=0; i<NUMTESTS; i++) {
221
222 exception_code = 0;
223 /* Set Exception Ports for Current Task */
224 if ((kr = task_set_exception_ports(task, EXC_MASK_GUARD, exc_port,
225 EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES, flavor)) != KERN_SUCCESS) {
226 fprintf(stderr, "task_set_exception_ports: %#x\n", kr);
227 exit(1);
228 }
229
230 child_args[0] = test_prog_name;
231 sprintf(&test_id[0], "%d", i);
232 child_args[1] = &test_id[0];
233 child_args[2] = NULL;
234
235 /* Fork and exec child */
236 if (fork() == 0) {
237 if ((err = posix_spawn(NULL, child_args[0], NULL, &attrs, &child_args[0], environ)) != 0) {
238 fprintf(stderr, "posix_spawn: %s\n", strerror(err));
239 exit(1);
240 }
241 }
242
243 /* Restore exception ports for parent */
244 if ((kr = task_set_exception_ports(task, EXC_MASK_GUARD, handler,
245 EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES, flavor)) != KERN_SUCCESS) {
246 fprintf(stderr, "task_set_exception_ports: %#x\n", kr);
247 exit(1);
248 }
249
250 /* Wait for child and check for exception */
251 if (-1 == wait4(-1, &child_status, 0, NULL)) {
252 exit(1);
253 }
254
255 exc_fd = (unsigned int) (exception_code & (uint64_t)EXC_GUARD_FD_MASK);
256 exc_id = exception_code & ~((uint64_t)EXC_GUARD_FD_MASK);
257 printf("EXC_GUARD Received: ");
258 (exception_code != 0)?printf("Yes (Code 0x%llx)\n", exception_code):printf("No\n");
259 printf("Test Result: ");
260 if((WIFEXITED(child_status) && WEXITSTATUS(child_status)) ||
261 (exc_id != test_exception_code[i]) ||
262 (test_fd[i] && exc_fd != (unsigned int)TEST_FD)) {
263 test_status = 1;
264 printf("FAILED\n");
265 }
266 else {
267 printf("PASSED\n");
268 }
269 printf("-------------------\n");
270
271 }
272
273 exit(test_status);
274 }
275
276