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