xref: /xnu-8019.80.24/tests/imm_pinned_control_port_crasher.c (revision a325d9c4a84054e40bbe985afedcb50ab80993ea)
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