1 #include <mach/mach.h>
2 #include <stdlib.h>
3 #include <pthread.h>
4 #include <unistd.h>
5 #include <stdio.h>
6 #include <assert.h>
7 #include <mach/task.h>
8
9 /*
10 * DO NOT run this test file by itself.
11 * This test is meant to be invoked by control_port_options darwintest.
12 *
13 * If hard enforcement for pinned control port is on, pinned tests are
14 * expected to generate fatal EXC_GUARD.
15 *
16 * If hard enforcement for immovable control port is on, immovable tests are
17 * expected to generate fatal EXC_GUARD.
18 *
19 * The type of exception raised (if any) is checked on control_port_options side.
20 */
21 #define MAX_TEST_NUM 17
22
23 static int
attempt_send_immovable_port(mach_port_name_t port,mach_msg_type_name_t disp)24 attempt_send_immovable_port(mach_port_name_t port, mach_msg_type_name_t disp)
25 {
26 mach_port_t server;
27 kern_return_t kr;
28 kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &server);
29 assert(kr == 0);
30
31 kr = mach_port_insert_right(mach_task_self(), server, server, MACH_MSG_TYPE_MAKE_SEND);
32 assert(kr == 0);
33
34 struct {
35 mach_msg_header_t header;
36 mach_msg_body_t body;
37 mach_msg_port_descriptor_t desc;
38 } msg;
39
40 msg.header.msgh_remote_port = server;
41 msg.header.msgh_local_port = MACH_PORT_NULL;
42 msg.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0) | MACH_MSGH_BITS_COMPLEX;
43 msg.header.msgh_size = sizeof msg;
44
45 msg.body.msgh_descriptor_count = 1;
46
47 msg.desc.name = port;
48 msg.desc.disposition = disp;
49 msg.desc.type = MACH_MSG_PORT_DESCRIPTOR;
50
51 return mach_msg_send(&msg.header);
52 }
53
54 static void
pinned_test_main_thread_mod_ref(void)55 pinned_test_main_thread_mod_ref(void)
56 {
57 printf("[Crasher]: Mod refs main thread's self port to 0\n");
58 mach_port_t thread_self = mach_thread_self();
59 kern_return_t kr = mach_port_mod_refs(mach_task_self(), thread_self, MACH_PORT_RIGHT_SEND, -2);
60
61 printf("[Crasher pinned_test_main_thread_mod_ref] mach_port_mod_refs returned %s \n.", mach_error_string(kr));
62 }
63
64 static void*
pthread_run(void)65 pthread_run(void)
66 {
67 printf("[Crasher]: Deallocate pthread_self\n");
68 mach_port_t th_self = pthread_mach_thread_np(pthread_self());
69 kern_return_t kr = mach_port_deallocate(mach_task_self(), th_self);
70
71 printf("[Crasher pinned_test_pthread_dealloc] mach_port_deallocate returned %s \n.", mach_error_string(kr));
72 return NULL;
73 }
74
75 static void
pinned_test_pthread_dealloc(void)76 pinned_test_pthread_dealloc(void)
77 {
78 printf("[Crasher]: Create a pthread and deallocate its self port\n");
79 pthread_t thread;
80 int ret = pthread_create(&thread, NULL, pthread_run, NULL);
81 assert(ret == 0);
82 ret = pthread_join(thread, NULL);
83 assert(ret == 0);
84 }
85
86 static void
pinned_test_task_self_dealloc(void)87 pinned_test_task_self_dealloc(void)
88 {
89 printf("[Crasher]: Deallocate mach_task_self twice\n");
90 mach_port_t task_self = mach_task_self();
91 kern_return_t kr = mach_port_deallocate(task_self, task_self);
92 assert(kr == 0);
93 kr = mach_port_deallocate(task_self, task_self);
94
95 printf("[Crasher pinned_test_task_self_dealloc] mach_port_deallocate returned %s \n.", mach_error_string(kr));
96 }
97
98 static void
pinned_test_task_self_mod_ref(void)99 pinned_test_task_self_mod_ref(void)
100 {
101 printf("[Crasher]: Mod refs mach_task_self() to 0\n");
102 kern_return_t kr = mach_port_mod_refs(mach_task_self(), mach_task_self(), MACH_PORT_RIGHT_SEND, -2);
103
104 printf("[Crasher pinned_test_task_self_mod_ref] mach_port_mod_refs returned %s \n.", mach_error_string(kr));
105 }
106
107 static void
pinned_test_task_threads_mod_ref(void)108 pinned_test_task_threads_mod_ref(void)
109 {
110 printf("[Crasher]: task_threads should return pinned thread ports. Mod refs them to 0\n");
111 thread_array_t th_list;
112 mach_msg_type_number_t th_cnt;
113 kern_return_t kr;
114 mach_port_t th_kp = mach_thread_self();
115 mach_port_deallocate(mach_task_self(), th_kp);
116
117 kr = task_threads(mach_task_self(), &th_list, &th_cnt);
118 mach_port_deallocate(mach_task_self(), th_list[0]);
119
120 kr = mach_port_mod_refs(mach_task_self(), th_list[0], MACH_PORT_RIGHT_SEND, -1);
121
122 printf("[Crasher pinned_test_task_threads_mod_ref] mach_port_mod_refs returned %s \n.", mach_error_string(kr));
123 }
124
125 static void
pinned_test_mach_port_destroy(void)126 pinned_test_mach_port_destroy(void)
127 {
128 kern_return_t kr = mach_port_destroy(mach_task_self(), mach_task_self());
129 printf("[Crasher pinned_test_mach_port_destroy] mach_port_destroy returned %s \n.", mach_error_string(kr));
130 }
131
132 static void
pinned_test_move_send_as_remote_port(void)133 pinned_test_move_send_as_remote_port(void)
134 {
135 struct {
136 mach_msg_header_t header;
137 } msg;
138
139 kern_return_t kr = mach_port_deallocate(mach_task_self(), mach_task_self());
140 assert(kr == 0);
141
142 /*
143 * We allow move send on remote kobject port but this should trip on pinning on last ref.
144 * See: IPC_OBJECT_COPYIN_FLAGS_ALLOW_IMMOVABLE_SEND.
145 */
146 msg.header.msgh_remote_port = mach_task_self();
147 msg.header.msgh_local_port = MACH_PORT_NULL;
148 msg.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MOVE_SEND, 0);
149 msg.header.msgh_id = 2000;
150 msg.header.msgh_size = sizeof msg;
151
152 kr = mach_msg_send(&msg.header);
153
154 printf("[Crasher pinned_test_move_send_as_remote_port] mach_msg_send returned %s \n.", mach_error_string(kr));
155 }
156
157 static void
immovable_test_move_send_as_remote_port(void)158 immovable_test_move_send_as_remote_port(void)
159 {
160 struct {
161 mach_msg_header_t header;
162 } msg;
163
164 /* Local port cannot be immovable. See: ipc_right_copyin_check_reply() */
165 msg.header.msgh_remote_port = mach_task_self();
166 msg.header.msgh_local_port = mach_task_self();
167 msg.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MOVE_SEND, MACH_MSG_TYPE_MOVE_SEND);
168 msg.header.msgh_id = 2000;
169 msg.header.msgh_size = sizeof msg;
170
171 kern_return_t kr = mach_msg_send(&msg.header);
172
173 printf("[Crasher immovable_test_move_send_as_remote_port] mach_msg_send returned %s \n.", mach_error_string(kr));
174 }
175
176 static void
immovable_test_move_send_task_self(void)177 immovable_test_move_send_task_self(void)
178 {
179 kern_return_t kr;
180 printf("[Crasher]: Move send mach_task_self_\n");
181 kr = attempt_send_immovable_port(mach_task_self(), MACH_MSG_TYPE_MOVE_SEND);
182
183 printf("[Crasher immovable_test_move_send_task_self] attempt_send_immovable_port returned %s \n.", mach_error_string(kr));
184 }
185
186 static void
immovable_test_copy_send_task_self(void)187 immovable_test_copy_send_task_self(void)
188 {
189 kern_return_t kr;
190 printf("[Crasher]: Copy send mach_task_self_\n");
191 kr = attempt_send_immovable_port(mach_task_self(), MACH_MSG_TYPE_COPY_SEND);
192
193 printf("[Crasher immovable_test_copy_send_task_self] attempt_send_immovable_port returned %s \n.", mach_error_string(kr));
194 }
195
196 static void
immovable_test_move_send_thread_self(void)197 immovable_test_move_send_thread_self(void)
198 {
199 kern_return_t kr;
200 printf("[Crasher]: Move send main thread's self port\n");
201 kr = attempt_send_immovable_port(mach_thread_self(), MACH_MSG_TYPE_MOVE_SEND);
202
203 printf("[Crasher immovable_test_move_send_thread_self] attempt_send_immovable_port returned %s \n.", mach_error_string(kr));
204 }
205
206 static void
immovable_test_copy_send_thread_self(void)207 immovable_test_copy_send_thread_self(void)
208 {
209 kern_return_t kr;
210 mach_port_t port;
211 printf("[Crasher]: Copy send main thread's self port\n");
212 port = mach_thread_self();
213 kr = attempt_send_immovable_port(port, MACH_MSG_TYPE_COPY_SEND);
214 printf("[Crasher immovable_test_copy_send_thread_self] attempt_send_immovable_port returned %s \n.", mach_error_string(kr));
215
216 mach_port_deallocate(mach_task_self(), port);
217 }
218
219 static void
immovable_test_copy_send_task_read(void)220 immovable_test_copy_send_task_read(void)
221 {
222 kern_return_t kr;
223 mach_port_t port;
224 printf("[Crasher]: Copy send task read port\n");
225 kr = task_get_special_port(mach_task_self(), TASK_READ_PORT, &port);
226 assert(kr == 0);
227 kr = attempt_send_immovable_port(port, MACH_MSG_TYPE_COPY_SEND);
228 printf("[Crasher immovable_test_copy_send_task_read] attempt_send_immovable_port returned %s \n.", mach_error_string(kr));
229
230 mach_port_deallocate(mach_task_self(), port);
231 }
232
233 static void
immovable_test_copy_send_task_inspect(void)234 immovable_test_copy_send_task_inspect(void)
235 {
236 kern_return_t kr;
237 mach_port_t port;
238 printf("[Crasher]: Move send task inspect port\n");
239 kr = task_get_special_port(mach_task_self(), TASK_INSPECT_PORT, &port);
240 assert(kr == 0);
241 kr = attempt_send_immovable_port(port, MACH_MSG_TYPE_MOVE_SEND);
242 printf("[Crasher immovable_test_copy_send_task_inspect] attempt_send_immovable_port returned %s \n.", mach_error_string(kr));
243 }
244
245 static void
immovable_test_move_send_thread_inspect(void)246 immovable_test_move_send_thread_inspect(void)
247 {
248 kern_return_t kr;
249 mach_port_t port;
250 mach_port_t th_port = mach_thread_self();
251
252 printf("[Crasher]: Move send thread inspect port\n");
253 kr = thread_get_special_port(th_port, THREAD_INSPECT_PORT, &port);
254 assert(kr == 0);
255 kr = attempt_send_immovable_port(port, MACH_MSG_TYPE_MOVE_SEND);
256 printf("[Crasher immovable_test_move_send_thread_inspect] attempt_send_immovable_port returned %s \n.", mach_error_string(kr));
257
258 mach_port_deallocate(mach_task_self(), th_port);
259 }
260
261 static void
immovable_test_move_send_raw_thread(void)262 immovable_test_move_send_raw_thread(void)
263 {
264 kern_return_t kr;
265 mach_port_t port;
266
267 kr = thread_create(mach_task_self(), &port);
268 assert(kr == 0);
269 kr = mach_port_deallocate(mach_task_self(), port); /* not pinned, should not crash */
270
271 kr = thread_create(mach_task_self(), &port);
272 assert(kr == 0);
273 kr = attempt_send_immovable_port(port, MACH_MSG_TYPE_MOVE_SEND); /* immovable, should crash here */
274 printf("[Crasher immovable_test_move_send_raw_thread] attempt_send_immovable_port returned %s \n.", mach_error_string(kr));
275
276 kr = thread_terminate(port);
277 assert(kr == 0);
278 }
279
280 static void
immovable_test_copy_send_thread_read(void)281 immovable_test_copy_send_thread_read(void)
282 {
283 kern_return_t kr;
284 mach_port_t port;
285 mach_port_t th_port = mach_thread_self();
286
287 printf("[Crasher]: Copy send thread read port\n");
288 kr = thread_get_special_port(th_port, THREAD_READ_PORT, &port);
289 assert(kr == 0);
290 kr = attempt_send_immovable_port(port, MACH_MSG_TYPE_COPY_SEND);
291 printf("[Crasher immovable_test_copy_send_thread_read] attempt_send_immovable_port returned %s \n.", mach_error_string(kr));
292
293 mach_port_deallocate(mach_task_self(), port);
294 mach_port_deallocate(mach_task_self(), th_port);
295 }
296
297 int
main(int argc,char * argv[])298 main(int argc, char *argv[])
299 {
300 void (*tests[MAX_TEST_NUM])(void) = {
301 pinned_test_main_thread_mod_ref,
302 pinned_test_pthread_dealloc,
303 pinned_test_task_self_dealloc,
304 pinned_test_task_self_mod_ref,
305 pinned_test_task_threads_mod_ref,
306 pinned_test_mach_port_destroy,
307 pinned_test_move_send_as_remote_port,
308
309 immovable_test_move_send_task_self,
310 immovable_test_copy_send_task_self,
311 immovable_test_move_send_thread_self,
312 immovable_test_copy_send_thread_self,
313 immovable_test_copy_send_task_read,
314 immovable_test_copy_send_task_inspect,
315 immovable_test_move_send_thread_inspect,
316 immovable_test_copy_send_thread_read,
317 immovable_test_move_send_as_remote_port,
318 immovable_test_move_send_raw_thread
319 };
320 printf("[Crasher]: My Pid: %d\n", getpid());
321
322 if (argc < 2) {
323 printf("[Crasher]: Specify a test to run.");
324 exit(-1);
325 }
326
327 int test_num = atoi(argv[1]);
328
329 if (test_num >= 0 && test_num < MAX_TEST_NUM) {
330 (*tests[test_num])();
331 } else {
332 printf("[Crasher]: Invalid test num. Exiting...\n");
333 exit(-1);
334 }
335
336 exit(0);
337 }
338