xref: /xnu-8020.101.4/tests/imm_pinned_control_port_crasher.c (revision e7776783b89a353188416a9a346c6cdb4928faad) !
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