]> git.saurik.com Git - apple/xnu.git/blob - tools/tests/unit_tests/guarded_mach_port_tests_11178535_src/guarded_test_framework.c
15a7d6702419454e23943b6cde4253901ef3b5fd
[apple/xnu.git] / tools / tests / unit_tests / guarded_mach_port_tests_11178535_src / guarded_test_framework.c
1 /*
2 * Testing Framework for EXC_GUARD exceptions
3 *
4 * The framework tests for exception conditions for guarded mach ports.
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 <mach/port.h>
23 #include <mach/mach_port.h>
24 #include <mach/mach_init.h>
25 #include <spawn_private.h>
26 #include <libproc_internal.h>
27 #include <mach_exc.h>
28
29 #define MAX_TEST_ID_LEN 16
30 #define MAX_ARGV 8
31 #define EXC_CODE_SHIFT 32
32 #define EXC_GUARD_TYPE_SHIFT 29
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 a new case and routine in guarded_test.c to
40 * test the scenario
41 */
42
43 #define NUMTESTS 10
44
45 uint64_t test_exception_code[] = {
46 0,
47 (GUARD_TYPE_MACH_PORT << EXC_GUARD_TYPE_SHIFT) | kGUARD_EXC_DESTROY,
48 (GUARD_TYPE_MACH_PORT << EXC_GUARD_TYPE_SHIFT) | kGUARD_EXC_DESTROY,
49 (GUARD_TYPE_MACH_PORT << EXC_GUARD_TYPE_SHIFT) | kGUARD_EXC_MOD_REFS,
50 0,
51 (GUARD_TYPE_MACH_PORT << EXC_GUARD_TYPE_SHIFT) | kGUARD_EXC_INCORRECT_GUARD,
52 (GUARD_TYPE_MACH_PORT << EXC_GUARD_TYPE_SHIFT) | kGUARD_EXC_UNGUARDED,
53 0,
54 0,
55 (GUARD_TYPE_MACH_PORT << EXC_GUARD_TYPE_SHIFT) | kGUARD_EXC_SET_CONTEXT
56 };
57
58 mach_port_t exc_port;
59 uint64_t exception_code;
60 extern char **environ;
61
62 boolean_t mach_exc_server(
63 mach_msg_header_t *InHeadP,
64 mach_msg_header_t *OutHeadP);
65
66 kern_return_t catch_mach_exception_raise
67 (
68 mach_port_t exception_port,
69 mach_port_t thread,
70 mach_port_t task,
71 exception_type_t exception,
72 mach_exception_data_t code,
73 mach_msg_type_number_t codeCnt,
74 int *flavor,
75 thread_state_t old_state,
76 mach_msg_type_number_t old_stateCnt,
77 thread_state_t new_state,
78 mach_msg_type_number_t *new_stateCnt
79 )
80 {
81 if (exception == EXC_GUARD) {
82 /* Set global variable to indicate exception received */
83 exception_code = *((uint64_t *)code);
84 } else {
85 /* Terminate test on all other unexpected exceptions */
86 fprintf(stderr, "received unexpected exception type %#x\n", exception);
87 exit(1);
88 }
89
90 return (KERN_SUCCESS);
91 }
92
93 kern_return_t catch_mach_exception_raise_state
94 (
95 mach_port_t exception_port,
96 exception_type_t exception,
97 const mach_exception_data_t code,
98 mach_msg_type_number_t codeCnt,
99 int *flavor,
100 const thread_state_t old_state,
101 mach_msg_type_number_t old_stateCnt,
102 thread_state_t new_state,
103 mach_msg_type_number_t *new_stateCnt
104 )
105 {
106 fprintf(stderr, "Unexpected exception handler called\n");
107 exit(1);
108 return (KERN_FAILURE);
109 }
110
111
112 kern_return_t catch_mach_exception_raise_state_identity
113 (
114 mach_port_t exception_port,
115 mach_port_t thread,
116 mach_port_t task,
117 exception_type_t exception,
118 mach_exception_data_t code,
119 mach_msg_type_number_t codeCnt
120 )
121 {
122 fprintf(stderr, "Unexpected exception handler called\n");
123 exit(1);
124 return (KERN_FAILURE);
125 }
126
127
128 void *server_thread(void *arg)
129 {
130 kern_return_t kr;
131
132 while(1) {
133 /* Handle exceptions on exc_port */
134 if ((kr = mach_msg_server_once(mach_exc_server, 4096, exc_port, 0)) != KERN_SUCCESS) {
135 fprintf(stderr, "mach_msg_server_once: error %#x\n", kr);
136 exit(1);
137 }
138 }
139 return (NULL);
140 }
141
142 int main(int argc, char *argv[])
143 {
144 posix_spawnattr_t attrs;
145 kern_return_t kr;
146 mach_port_t task = mach_task_self();
147
148 mach_msg_type_number_t maskCount = 1;
149 exception_mask_t mask;
150 exception_handler_t handler;
151 exception_behavior_t behavior;
152 thread_state_flavor_t flavor;
153 pthread_t exception_thread;
154 uint64_t exc_id;
155 unsigned int exc_fd;
156
157 char *test_prog_name = "./guarded_mp_test";
158 char *child_args[MAX_ARGV];
159 char test_id[MAX_TEST_ID_LEN];
160 int i, err;
161 int child_status;
162 int test_status = 0;
163
164 /* Allocate and initialize new exception port */
165 if ((kr = mach_port_allocate(task, MACH_PORT_RIGHT_RECEIVE, &exc_port)) != KERN_SUCCESS) {
166 fprintf(stderr, "mach_port_allocate: %#x\n", kr);
167 exit(1);
168 }
169
170 if ((kr = mach_port_insert_right(task, exc_port,
171 exc_port, MACH_MSG_TYPE_MAKE_SEND)) != KERN_SUCCESS) {
172 fprintf(stderr, "mach_port_allocate: %#x\n", kr);
173 exit(1);
174 }
175
176 /* Get Current exception ports */
177 if ((kr = task_get_exception_ports(task, EXC_MASK_GUARD, &mask,
178 &maskCount, &handler, &behavior, &flavor)) != KERN_SUCCESS) {
179 fprintf(stderr,"task_get_exception_ports: %#x\n", kr);
180 exit(1);
181 }
182
183 /* Create exception serving thread */
184 if ((err = pthread_create(&exception_thread, NULL, server_thread, 0)) != 0) {
185 fprintf(stderr, "pthread_create server_thread: %s\n", strerror(err));
186 exit(1);
187 }
188
189 pthread_detach(exception_thread);
190
191 /* Initialize posix_spawn attributes */
192 posix_spawnattr_init(&attrs);
193
194 if ((err = posix_spawnattr_setflags(&attrs, POSIX_SPAWN_SETEXEC)) != 0) {
195 fprintf(stderr, "posix_spawnattr_setflags: %s\n", strerror(err));
196 exit(1);
197 }
198
199 /* Run Tests */
200 for(i=0; i<NUMTESTS; i++) {
201
202 exception_code = 0;
203 /* Set Exception Ports for Current Task */
204 if ((kr = task_set_exception_ports(task, EXC_MASK_GUARD, exc_port,
205 EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES, flavor)) != KERN_SUCCESS) {
206 fprintf(stderr, "task_set_exception_ports: %#x\n", kr);
207 exit(1);
208 }
209
210 child_args[0] = test_prog_name;
211 sprintf(&test_id[0], "%d", i);
212 child_args[1] = &test_id[0];
213 child_args[2] = NULL;
214
215 /* Fork and exec child */
216 if (fork() == 0) {
217 if ((err = posix_spawn(NULL, child_args[0], NULL, &attrs, &child_args[0], environ)) != 0) {
218 fprintf(stderr, "posix_spawn: %s\n", strerror(err));
219 exit(1);
220 }
221 }
222
223 /* Restore exception ports for parent */
224 if ((kr = task_set_exception_ports(task, EXC_MASK_GUARD, handler,
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 /* Wait for child and check for exception */
231 if (-1 == wait4(-1, &child_status, 0, NULL)) {
232 exit(1);
233 }
234
235 exc_id = (exception_code >> EXC_CODE_SHIFT);
236 printf("EXC_GUARD Received: ");
237 (exc_id != 0)?printf("Yes (Code 0x%llx)\n", exception_code):printf("No\n");
238 printf("Expected Exception Code: 0x%llx\n", test_exception_code[i]);
239 printf("Test Result: ");
240 if((WIFEXITED(child_status) && WEXITSTATUS(child_status)) ||
241 (exc_id != test_exception_code[i])) {
242 test_status = 1;
243 printf("FAILED\n");
244 }
245 else {
246 printf("PASSED\n");
247 }
248 printf("-------------------\n");
249
250 }
251
252 exit(test_status);
253 }
254
255