xref: /xnu-12377.61.12/tests/ipc/ipc_read_inspect.c (revision 4d495c6e23c53686cf65f45067f79024cf5dcee8)
1 #include <darwintest.h>
2 
3 #include <mach/host_priv.h>
4 #include <mach/mach.h>
5 #include <mach/mach_types.h>
6 #include <mach/mach_vm.h>
7 #include <mach_debug/ipc_info.h>
8 #include <mach/processor_set.h>
9 #include <mach/task.h>
10 #include <signal.h>
11 #include <sys/wait.h>
12 #include <sys/proc.h>
13 #include <sys/sysctl.h>
14 #include <unistd.h>
15 #include <TargetConditionals.h>
16 
17 /*
18  * This test verifies various security properties for task and thread
19  * read/inspect interfaces. Specifically, it checks and makes sure:
20  *
21  * 1. Task/thread can't get higher priv'ed ports from lower ones through
22  * {task, thread}_get_special_port()
23  * 2. Correct level of thread ports are returned from task_threads() with
24  * a given task port flavor
25  * 3. Correct level of task ports are returned from processor_set_tasks()
26  * 4. MIG intrans conversion and enforcement for task/thread port does not break.
27  * 5. task_{, read, inspect, name}_for_pid() works for self and other process
28  * 6. The new mach_vm_remap_new interface behaves correctly
29  */
30 
31 T_GLOBAL_META(
32 	T_META_NAMESPACE("xnu.ipc"),
33 	T_META_RADAR_COMPONENT_NAME("xnu"),
34 	T_META_RADAR_COMPONENT_VERSION("IPC"),
35 	T_META_RUN_CONCURRENTLY(TRUE),
36 	T_META_TAG_VM_PREFERRED);
37 
38 static void
RESULT_CHECK(kern_return_t kr,unsigned int flavor,unsigned int required,char * f_name)39 RESULT_CHECK(
40 	kern_return_t kr,
41 	unsigned int flavor,  /* task_flavor_t or thread_flavor_t */
42 	unsigned int required, /* task_flavor_t or thread_flavor_t */
43 	char *f_name)
44 {
45 	if (flavor <= required) {
46 		T_EXPECT_EQ(kr, KERN_SUCCESS, "%s should succeed with task/thread flavor %d, kr: 0x%x", f_name, flavor, kr);
47 	} else {
48 		T_EXPECT_NE(kr, KERN_SUCCESS, "%s should fail with task/thread flavor %d, kr: 0x%x", f_name, flavor, kr);
49 	}
50 }
51 
52 static void
test_task_get_special_port(task_t tport,task_flavor_t flavor)53 test_task_get_special_port(
54 	task_t  tport,
55 	task_flavor_t flavor)
56 {
57 	kern_return_t kr;
58 	mach_port_t special_port = MACH_PORT_NULL;
59 	mach_port_t tfp_port = MACH_PORT_NULL;
60 
61 	T_LOG("Testing task_get_special_port() with task flavor %d", flavor);
62 	/* gettable with at least control port */
63 	kr = task_get_special_port(tport, TASK_KERNEL_PORT, &special_port);
64 	RESULT_CHECK(kr, flavor, TASK_FLAVOR_CONTROL, "task_get_special_port(TASK_KERNEL_PORT)");
65 	mach_port_deallocate(mach_task_self(), special_port);
66 	special_port = MACH_PORT_NULL;
67 
68 	kr = task_get_special_port(tport, TASK_BOOTSTRAP_PORT, &special_port);
69 	RESULT_CHECK(kr, flavor, TASK_FLAVOR_CONTROL, "task_get_special_port(TASK_BOOTSTRAP_PORT)");
70 	mach_port_deallocate(mach_task_self(), special_port);
71 	special_port = MACH_PORT_NULL;
72 
73 	kr = task_get_special_port(tport, TASK_HOST_PORT, &special_port);
74 	RESULT_CHECK(kr, flavor, TASK_FLAVOR_CONTROL, "task_get_special_port(TASK_HOST_PORT)");
75 	mach_port_deallocate(mach_task_self(), special_port);
76 	special_port = MACH_PORT_NULL;
77 
78 	/* gettable with at least read port */
79 	kr = task_get_special_port(tport, TASK_READ_PORT, &special_port);
80 	RESULT_CHECK(kr, flavor, TASK_FLAVOR_READ, "task_get_special_port(TASK_READ_PORT)");
81 	if (KERN_SUCCESS == kr) {
82 		kr = task_read_for_pid(mach_task_self(), getpid(), &tfp_port);
83 		T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "task_read_for_pid()");
84 		T_QUIET; T_EXPECT_EQ(tfp_port, special_port, "task_read_for_pid() should match TASK_READ_PORT");
85 		mach_port_deallocate(mach_task_self(), tfp_port);
86 	}
87 	mach_port_deallocate(mach_task_self(), special_port);
88 	special_port = MACH_PORT_NULL;
89 
90 	/* gettable with at least inspect port */
91 	kr = task_get_special_port(tport, TASK_INSPECT_PORT, &special_port);
92 	RESULT_CHECK(kr, flavor, TASK_FLAVOR_INSPECT, "task_get_special_port(TASK_INSPECT_PORT)");
93 	if (KERN_SUCCESS == kr) {
94 		kr = task_inspect_for_pid(mach_task_self(), getpid(), &tfp_port);
95 		T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "task_inspect_for_pid()");
96 		T_QUIET; T_EXPECT_EQ(tfp_port, special_port, "task_inspect_for_pid() should match TASK_INSPECT_PORT");
97 		mach_port_deallocate(mach_task_self(), tfp_port);
98 	}
99 	mach_port_deallocate(mach_task_self(), special_port);
100 	special_port = MACH_PORT_NULL;
101 
102 	/* gettable with at least name port */
103 	kr = task_get_special_port(tport, TASK_NAME_PORT, &special_port);
104 	RESULT_CHECK(kr, flavor, TASK_FLAVOR_INSPECT, "task_get_special_port(TASK_NAME_PORT)");
105 	if (KERN_SUCCESS == kr) {
106 		kr = task_name_for_pid(mach_task_self(), getpid(), &tfp_port);
107 		T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "task_name_for_pid()");
108 		T_QUIET; T_EXPECT_EQ(tfp_port, special_port, "task_name_for_pid() should match TASK_NAME_PORT");
109 		mach_port_deallocate(mach_task_self(), tfp_port);
110 	}
111 	mach_port_deallocate(mach_task_self(), special_port);
112 	special_port = MACH_PORT_NULL;
113 }
114 
115 static void
test_thread_get_special_port(thread_t tport,thread_flavor_t flavor)116 test_thread_get_special_port(
117 	thread_t  tport,
118 	thread_flavor_t flavor)
119 {
120 	kern_return_t kr;
121 	mach_port_t special_port = MACH_PORT_NULL;
122 
123 	T_LOG("Testing thread_get_special_port() with thread flavor %d", flavor);
124 	/* gettable with at least control port */
125 	kr = thread_get_special_port(tport, THREAD_KERNEL_PORT, &special_port);
126 	RESULT_CHECK(kr, flavor, THREAD_FLAVOR_CONTROL, "thread_get_special_port(THREAD_KERNEL_PORT)");
127 	mach_port_deallocate(mach_task_self(), special_port);
128 	special_port = MACH_PORT_NULL;
129 
130 	/* gettable with at least read port */
131 	kr = thread_get_special_port(tport, THREAD_READ_PORT, &special_port);
132 	RESULT_CHECK(kr, flavor, THREAD_FLAVOR_READ, "thread_get_special_port(THREAD_READ_PORT)");
133 	mach_port_deallocate(mach_task_self(), special_port);
134 	special_port = MACH_PORT_NULL;
135 
136 	/* gettable with at least inspect port */
137 	kr = thread_get_special_port(tport, THREAD_INSPECT_PORT, &special_port);
138 	RESULT_CHECK(kr, flavor, THREAD_FLAVOR_INSPECT, "thread_get_special_port(THREAD_INSPECT_PORT)");
139 	mach_port_deallocate(mach_task_self(), special_port);
140 	special_port = MACH_PORT_NULL;
141 }
142 
143 static void
test_task_threads(task_t tport,task_flavor_t flavor)144 test_task_threads(
145 	task_t  tport,
146 	task_flavor_t flavor)
147 {
148 	kern_return_t kr;
149 	thread_array_t threadList;
150 	mach_msg_type_number_t threadCount = 0;
151 
152 	ipc_info_object_type_t kotype;
153 	unsigned int kaddr;
154 
155 	T_LOG("Testing task_threads() with task flavor %d", flavor);
156 
157 	kr = task_threads(tport, &threadList, &threadCount);
158 	RESULT_CHECK(kr, flavor, TASK_FLAVOR_INSPECT, "task_threads");
159 
160 	if (kr) {
161 		T_LOG("task_threads failed, skipping test_task_threads()");
162 		return;
163 	}
164 
165 	T_QUIET; T_ASSERT_GE(threadCount, 1, "threadCount should be at least 1");
166 
167 	/*
168 	 * TASK_FLAVOR_CONTROL -> THREAD_FLAVOR_CONTROL
169 	 * TASK_FLAVOR_READ    -> THREAD_FLAVOR_READ
170 	 * TASK_FLAVOR_INSPECT -> THREAD_FLAVOR_INSPECT
171 	 * TASK_FLAOVR_NAME    -> KERN_FAILURE
172 	 */
173 	for (size_t i = 0; i < threadCount; i++) {
174 		kr = mach_port_kernel_object(mach_task_self(), threadList[i], &kotype, &kaddr);
175 		if (kr == KERN_INVALID_RIGHT || kr == KERN_INVALID_NAME) {
176 			/* thread port is inactive */
177 			T_LOG("thread port name 0x%x is inactive", threadList[i]);
178 			continue;
179 		} else if (kr) {
180 			T_FAIL("mach_port_kernel_object() failed with kr: 0x%x", kr);
181 		}
182 		switch (flavor) {
183 		case TASK_FLAVOR_CONTROL:
184 			T_QUIET; T_EXPECT_EQ(kotype, IPC_OTYPE_THREAD_CONTROL, "Task control port should yield thread control port");
185 			break;
186 		case TASK_FLAVOR_READ:
187 			T_QUIET; T_EXPECT_EQ(kotype, IPC_OTYPE_THREAD_READ, "Task read port should yield thread read port");
188 			break;
189 		case TASK_FLAVOR_INSPECT:
190 			T_QUIET; T_EXPECT_EQ(kotype, IPC_OTYPE_THREAD_INSPECT, "Task inspect port should yield thread inspect port");
191 			break;
192 		default:
193 			T_FAIL("task_threads() returned thread ports with task name port??");
194 			break;
195 		}
196 	}
197 
198 	for (size_t i = 0; i < threadCount; i++) {
199 		mach_port_deallocate(mach_task_self(), threadList[i]);
200 	}
201 	vm_deallocate(mach_task_self(), (vm_address_t)threadList,
202 	    sizeof(threadList[0]) * threadCount);
203 }
204 
205 static void
test_processor_set_tasks(task_flavor_t flavor)206 test_processor_set_tasks(
207 	task_flavor_t flavor)
208 {
209 	kern_return_t kr;
210 	processor_set_name_array_t psets;
211 	processor_set_t        pset_priv;
212 	task_array_t taskList;
213 	mach_msg_type_number_t pcnt = 0, tcnt = 0;
214 	mach_port_t host = mach_host_self();
215 
216 	ipc_info_object_type_t kotype;
217 	unsigned int kaddr;
218 
219 	T_LOG("Testing processor_set_tasks() with task flavor %d", flavor);
220 
221 	kr = host_processor_sets(host, &psets, &pcnt);
222 	T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "host_processor_sets");
223 	T_QUIET; T_ASSERT_GE(pcnt, 1, "should have at least 1 processor set");
224 
225 	kr = host_processor_set_priv(host, psets[0], &pset_priv);
226 	T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "host_processor_set_priv");
227 	for (size_t i = 0; i < pcnt; i++) {
228 		mach_port_deallocate(mach_task_self(), psets[i]);
229 	}
230 	mach_port_deallocate(mach_task_self(), host);
231 
232 	kr = processor_set_tasks_with_flavor(pset_priv, flavor, &taskList, &tcnt);
233 	T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "processor_set_tasks_with_flavor");
234 	T_QUIET; T_ASSERT_GE(tcnt, 1, "should have at least 1 task");
235 	mach_port_deallocate(mach_task_self(), pset_priv);
236 
237 	for (size_t i = 0; i < tcnt; i++) {
238 		kr = mach_port_kernel_object(mach_task_self(), taskList[i], &kotype, &kaddr);
239 		if (kr == KERN_INVALID_RIGHT || kr == KERN_INVALID_NAME) {
240 			/* task port is inactive */
241 			T_LOG("task port name 0x%x is inactive", taskList[i]);
242 			continue;
243 		} else if (kr) {
244 			T_FAIL("mach_port_kernel_object() failed with kr: 0x%x", kr);
245 		}
246 		switch (flavor) {
247 		case TASK_FLAVOR_CONTROL:
248 			T_QUIET; T_EXPECT_EQ(kotype, IPC_OTYPE_TASK_CONTROL, "TASK_FLAVOR_CONTROL should yield control ports");
249 			break;
250 		case TASK_FLAVOR_READ:
251 			T_QUIET; T_EXPECT_EQ(kotype, IPC_OTYPE_TASK_READ, "TASK_FLAVOR_READ should yield read ports");
252 			break;
253 		case TASK_FLAVOR_INSPECT:
254 			T_QUIET; T_EXPECT_EQ(kotype, IPC_OTYPE_TASK_INSPECT, "TASK_FLAVOR_INSPECT should yield inspect ports");
255 			break;
256 		case TASK_FLAVOR_NAME:
257 			T_QUIET; T_EXPECT_EQ(kotype, IPC_OTYPE_TASK_NAME, "TASK_FLAVOR_NAME should yield name ports");
258 			break;
259 		default:
260 			T_FAIL("strange flavor");
261 			break;
262 		}
263 	}
264 
265 	for (size_t i = 0; i < tcnt; i++) {
266 		mach_port_deallocate(mach_task_self(), taskList[i]);
267 	}
268 }
269 
270 static void
test_task_port_mig_intrans(task_t tport,task_flavor_t flavor)271 test_task_port_mig_intrans(
272 	task_t  tport,
273 	task_flavor_t   flavor)
274 {
275 	kern_return_t kr;
276 
277 	T_LOG("Testing various MIG/manual intrans task interfaces with task flavor %d", flavor);
278 
279 	{
280 		/* 1. Test some control port interfaces */
281 		int data = 0x41;
282 		int new_value = 0x42;
283 		kr = mach_vm_write(tport,
284 		    (mach_vm_address_t)&data,
285 		    (vm_offset_t)&new_value,
286 		    (mach_msg_type_number_t)sizeof(int));
287 		RESULT_CHECK(kr, flavor, TASK_FLAVOR_CONTROL, "mach_vm_write");
288 
289 		/* mach_vm_remap_new with max_protection VM_PROT_WRITE | VM_PROT_READ */
290 		int *localAddress = 0;
291 		mach_vm_address_t localMachVMAddress = 0;
292 		vm_prot_t cur_protection = VM_PROT_WRITE | VM_PROT_READ;
293 		vm_prot_t max_protection = VM_PROT_WRITE | VM_PROT_READ;
294 		/* rdar://67706101 (mach_vm_remap flag that allows restricting protection of remapped region) */
295 		kr = mach_vm_remap_new(mach_task_self(),
296 		    &localMachVMAddress,
297 		    sizeof(int),
298 		    0,
299 		    VM_FLAGS_ANYWHERE,
300 		    tport, /* remote task, use self task port */
301 		    (mach_vm_address_t)&data,
302 		    false,
303 		    &cur_protection,
304 		    &max_protection,
305 		    VM_INHERIT_NONE);
306 		localAddress = (int *)(uintptr_t)localMachVMAddress;
307 
308 		RESULT_CHECK(kr, flavor, TASK_FLAVOR_CONTROL, "mach_vm_remap_new - VM_PROT_WRITE");
309 		if (KERN_SUCCESS == kr) {
310 			T_QUIET; T_EXPECT_EQ(max_protection, VM_PROT_READ | VM_PROT_WRITE, NULL);
311 			T_QUIET; T_EXPECT_EQ(cur_protection, VM_PROT_READ | VM_PROT_WRITE, NULL);
312 			T_QUIET; T_EXPECT_EQ(*localAddress, data, NULL); /* read */
313 			*localAddress = 0; /* write */
314 		}
315 
316 		exception_mask_t masks[EXC_TYPES_COUNT] = {};
317 		mach_msg_type_number_t nmasks = 0;
318 		exception_port_t ports[EXC_TYPES_COUNT] = {};
319 		exception_behavior_t behaviors[EXC_TYPES_COUNT] = {};
320 		thread_state_flavor_t flavors[EXC_TYPES_COUNT] = {};
321 		kr = task_get_exception_ports(tport, EXC_MASK_ALL,
322 		    masks, &nmasks, ports, behaviors, flavors);
323 		RESULT_CHECK(kr, flavor, TASK_FLAVOR_CONTROL, "task_get_exception_ports");
324 		for (size_t i = 0; i < EXC_TYPES_COUNT; i++) {
325 			mach_port_deallocate(mach_task_self(), ports[i]);
326 		}
327 	}
328 
329 	{
330 		/* 2. Test some read port interfaces */
331 		vm_offset_t read_value = 0;
332 		mach_msg_type_number_t read_cnt = 0;
333 		int data = 0x41;
334 		kr = mach_vm_read(tport,
335 		    (mach_vm_address_t)&data,
336 		    (mach_msg_type_number_t)sizeof(int),
337 		    &read_value,
338 		    &read_cnt);
339 		RESULT_CHECK(kr, flavor, TASK_FLAVOR_READ, "mach_vm_read");
340 
341 		/* mach_vm_remap_new with max_protection VM_PROT_READ */
342 		int *localAddress = 0;
343 		mach_vm_address_t localMachVMAddress = 0;
344 		vm_prot_t cur_protection = VM_PROT_READ;
345 		vm_prot_t max_protection = VM_PROT_READ;
346 		/* rdar://67706101 (mach_vm_remap flag that allows restricting protection of remapped region) */
347 		kr = mach_vm_remap_new(mach_task_self(),
348 		    &localMachVMAddress,
349 		    sizeof(int),
350 		    0,
351 		    VM_FLAGS_ANYWHERE,
352 		    tport, /* remote task, use self task port */
353 		    (mach_vm_address_t)&data,
354 		    false,
355 		    &cur_protection,
356 		    &max_protection,
357 		    VM_INHERIT_NONE);
358 		localAddress = (int *)(uintptr_t)localMachVMAddress;
359 
360 		RESULT_CHECK(kr, flavor, TASK_FLAVOR_READ, "mach_vm_remap_new - VM_PROT_READ");
361 		if (KERN_SUCCESS == kr) {
362 			T_QUIET; T_EXPECT_EQ(max_protection, VM_PROT_READ, NULL);
363 			T_QUIET; T_EXPECT_EQ(cur_protection, VM_PROT_READ, NULL);
364 			T_QUIET; T_EXPECT_EQ(*localAddress, data, NULL); /* read */
365 		}
366 
367 		/* mach_vm_remap_new with copy == TRUE */
368 		int data2 = 0x42;
369 		localAddress = 0;
370 		localMachVMAddress = 0;
371 		cur_protection = VM_PROT_WRITE | VM_PROT_READ;
372 		max_protection = VM_PROT_WRITE | VM_PROT_READ;
373 
374 		kr = mach_vm_remap_new(mach_task_self(),
375 		    &localMachVMAddress,
376 		    sizeof(int),
377 		    0,
378 		    VM_FLAGS_ANYWHERE,
379 		    tport, /* remote task, use self task port */
380 		    (mach_vm_address_t)&data2,
381 		    true,
382 		    &cur_protection,
383 		    &max_protection,
384 		    VM_INHERIT_NONE);
385 		localAddress = (int *)(uintptr_t)localMachVMAddress;
386 
387 		RESULT_CHECK(kr, flavor, TASK_FLAVOR_READ, "mach_vm_remap_new - copy==TRUE");
388 		if (KERN_SUCCESS == kr) {
389 			T_QUIET; T_EXPECT_EQ(max_protection, VM_PROT_READ | VM_PROT_WRITE, NULL);
390 			T_QUIET; T_EXPECT_EQ(cur_protection, VM_PROT_READ | VM_PROT_WRITE, NULL);
391 			/* Following is causing bus error tracked by rdar://71616700 (Unexpected BUS ERROR in mach_vm_remap_new()) */
392 			// T_QUIET; T_EXPECT_EQ(*localAddress, data2, NULL); /* read */
393 			// *localAddress = 0; /* write */
394 		}
395 
396 		/* */
397 		mach_port_t voucher = MACH_PORT_NULL;
398 		kr = task_get_mach_voucher(tport, 0, &voucher);
399 		RESULT_CHECK(kr, flavor, TASK_FLAVOR_READ, "task_get_mach_voucher");
400 		mach_port_deallocate(mach_task_self(), voucher);
401 
402 		/* */
403 		ipc_info_space_t space_info;
404 		ipc_info_name_array_t table;
405 		mach_msg_type_number_t tableCount;
406 		ipc_info_tree_name_array_t tree; /* unused */
407 		mach_msg_type_number_t treeCount; /* unused */
408 		kr = mach_port_space_info(tport, &space_info, &table, &tableCount, &tree, &treeCount);
409 		RESULT_CHECK(kr, flavor, TASK_FLAVOR_READ, "mach_port_space_info");
410 	}
411 
412 	{
413 		/* 3. Test some inspect port interfaces */
414 		task_exc_guard_behavior_t exc_behavior;
415 		kr = task_get_exc_guard_behavior(tport, &exc_behavior);
416 		RESULT_CHECK(kr, flavor, TASK_FLAVOR_INSPECT, "task_get_exc_guard_behavior");
417 	}
418 
419 	{
420 		/* 4. Test some name port interfaces */
421 		struct task_basic_info info;
422 		mach_msg_type_number_t size = sizeof(info);
423 		kr = task_info(tport,
424 		    TASK_BASIC_INFO,
425 		    (task_info_t)&info,
426 		    &size);
427 		RESULT_CHECK(kr, flavor, TASK_FLAVOR_NAME, "task_info");
428 	}
429 }
430 
431 static void
test_thread_port_mig_intrans(thread_t tport,thread_flavor_t flavor)432 test_thread_port_mig_intrans(
433 	thread_t  tport,
434 	thread_flavor_t   flavor)
435 {
436 	kern_return_t kr;
437 
438 	T_LOG("Testing various MIG/manual intrans thread interfaces with thread flavor %d", flavor);
439 
440 	{
441 		/* 1. Test some control port interfaces */
442 		exception_mask_t masks[EXC_TYPES_COUNT] = {};
443 		mach_msg_type_number_t nmasks = 0;
444 		exception_port_t ports[EXC_TYPES_COUNT] = {};
445 		exception_behavior_t behaviors[EXC_TYPES_COUNT] = {};;
446 		thread_state_flavor_t flavors[EXC_TYPES_COUNT] = {};;
447 		kr = thread_get_exception_ports(tport, EXC_MASK_ALL,
448 		    masks, &nmasks, ports, behaviors, flavors);
449 		RESULT_CHECK(kr, flavor, THREAD_FLAVOR_CONTROL, "thread_get_exception_ports");
450 		for (size_t i = 0; i < EXC_TYPES_COUNT; i++) {
451 			mach_port_deallocate(mach_task_self(), ports[i]);
452 		}
453 	}
454 
455 	{
456 		/* 2. Test some read port interfaces */
457 		mach_voucher_t voucher = MACH_PORT_NULL;
458 		kr = thread_get_mach_voucher(tport, 0, &voucher);
459 		RESULT_CHECK(kr, flavor, THREAD_FLAVOR_READ, "thread_get_mach_voucher");
460 		mach_port_deallocate(mach_task_self(), voucher);
461 	}
462 
463 	{
464 		/* 3. Test some inspect port interfaces */
465 		thread_qos_policy_t info;
466 		mach_msg_type_number_t count = THREAD_QOS_POLICY_COUNT;
467 		boolean_t get_default = FALSE;
468 
469 		kr = thread_policy_get(tport, THREAD_QOS_POLICY,
470 		    (thread_policy_t)&info, &count, &get_default);
471 		RESULT_CHECK(kr, flavor, THREAD_FLAVOR_INSPECT, "thread_policy_get");
472 	}
473 }
474 
475 static void
test_get_child_task_port(void)476 test_get_child_task_port(void)
477 {
478 	pid_t child_pid;
479 	kern_return_t kr;
480 	mach_port_name_t tr, ti, tp, tn;
481 
482 	child_pid = fork();
483 
484 	T_LOG("Testing get child task ports");
485 
486 	if (child_pid < 0) {
487 		T_FAIL("fork failed in test_get_child_port.");
488 	}
489 
490 	if (child_pid == 0) {
491 		/* hang the child */
492 		while (1) {
493 			sleep(10);
494 		}
495 	}
496 
497 	kr = task_for_pid(mach_task_self(), child_pid, &tp);
498 	T_QUIET; T_EXPECT_MACH_SUCCESS(kr, "task_for_pid for child %u", child_pid);
499 
500 	kr = task_read_for_pid(mach_task_self(), child_pid, &tr);
501 	T_QUIET; T_EXPECT_MACH_SUCCESS(kr, "task_read_for_pid for child %u", child_pid);
502 
503 	kr = task_inspect_for_pid(mach_task_self(), child_pid, &ti);
504 	T_QUIET; T_EXPECT_MACH_SUCCESS(kr, "task_inspect_for_pid for child %u", child_pid);
505 
506 	kr = task_name_for_pid(mach_task_self(), child_pid, &tn);
507 	T_QUIET; T_EXPECT_MACH_SUCCESS(kr, "task_name_for_pid for child %u", child_pid);
508 
509 	mach_port_deallocate(mach_task_self(), tp);
510 	mach_port_deallocate(mach_task_self(), tr);
511 	mach_port_deallocate(mach_task_self(), ti);
512 	mach_port_deallocate(mach_task_self(), tn);
513 
514 	kill(child_pid, SIGKILL);
515 	int status;
516 	wait(&status);
517 }
518 
519 T_DECL(read_inspect, "Test critical read and inspect port interfaces")
520 {
521 	mach_port_t control_port, movable_port, read_port, inspect_port, name_port;
522 	mach_port_t th_control_port, th_movable_port, th_read_port, th_inspect_port;
523 #define TASK_PORT_COUNT 5
524 #define THREAD_PORT_COUNT 4
525 	mach_port_t task_ports[TASK_PORT_COUNT];
526 	task_flavor_t task_flavors[TASK_PORT_COUNT];
527 	mach_port_t thread_ports[THREAD_PORT_COUNT];
528 	thread_flavor_t thread_flavors[THREAD_PORT_COUNT];
529 	kern_return_t kr;
530 
531 	/* first, try getting all flavors of task port for self */
532 	kr = task_for_pid(mach_task_self(), getpid(), &control_port);
533 	T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "task_for_pid()");
534 	task_ports[0] = control_port;
535 	task_flavors[0] = TASK_FLAVOR_CONTROL;
536 
537 	kr = task_get_special_port(mach_task_self(), TASK_KERNEL_PORT, &movable_port);
538 	T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "task_get_special_port(..TASK_KERNEL_PORT..)");
539 	task_ports[1] = movable_port;
540 	task_flavors[1] = TASK_FLAVOR_CONTROL;
541 
542 	kr = task_read_for_pid(mach_task_self(), getpid(), &read_port);
543 	T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "task_read_for_pid()");
544 	task_ports[2] = read_port;
545 	task_flavors[2] = TASK_FLAVOR_READ;
546 
547 	kr = task_inspect_for_pid(mach_task_self(), getpid(), &inspect_port);
548 	T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "task_inspect_for_pid()");
549 	task_ports[3] = inspect_port;
550 	task_flavors[3] = TASK_FLAVOR_INSPECT;
551 
552 	kr = task_name_for_pid(mach_task_self(), getpid(), &name_port);
553 	T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "task_name_for_pid()");
554 	task_ports[4] = name_port;
555 	task_flavors[4] = TASK_FLAVOR_NAME;
556 
557 
558 	for (size_t i = 0; i < TASK_PORT_COUNT; i++) {
559 		/*
560 		 * 1. Make sure can't get higher priv'ed ports from lower ones through
561 		 * task_get_special_port()
562 		 */
563 		test_task_get_special_port(task_ports[i], task_flavors[i]);
564 
565 		/*
566 		 * 2. Make sure correct level of thread ports are returned from task_threads
567 		 */
568 		test_task_threads(task_ports[i], task_flavors[i]);
569 
570 		/*
571 		 * 3. Make sure correct level of task ports are returned from processor_set_tasks
572 		 */
573 		if (i >= 1) {
574 			test_processor_set_tasks(task_flavors[i]);
575 		}
576 
577 		/*
578 		 * 4. Make sure our MIG intrans enforcement for tasks does not break.
579 		 */
580 		test_task_port_mig_intrans(task_ports[i], task_flavors[i]);
581 	}
582 
583 
584 	for (size_t i = 0; i < TASK_PORT_COUNT; i++) {
585 		mach_port_deallocate(mach_task_self(), task_ports[i]);
586 	}
587 
588 	/* 4. Try spawning a child an get its task ports */
589 	test_get_child_task_port();
590 
591 	/* Now, test thread read/inspect ports */
592 	th_control_port = mach_thread_self();
593 	thread_ports[0] = th_control_port;
594 	thread_flavors[0] = THREAD_FLAVOR_CONTROL;
595 
596 	kr = thread_get_special_port(th_control_port, THREAD_KERNEL_PORT, &th_movable_port);
597 	T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "thread_get_special_port(..THREAD_KERNEL_PORT..)");
598 	thread_ports[1] = th_movable_port;
599 	thread_flavors[1] = THREAD_FLAVOR_CONTROL;
600 
601 	kr = thread_get_special_port(th_control_port, THREAD_READ_PORT, &th_read_port);
602 	T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "thread_get_special_port(..THREAD_READ_PORT..)");
603 	thread_ports[2] = th_read_port;
604 	thread_flavors[2] = THREAD_FLAVOR_READ;
605 
606 	kr = thread_get_special_port(th_control_port, THREAD_INSPECT_PORT, &th_inspect_port);
607 	T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "thread_get_special_port(..THREAD_INSPECT_PORT..)");
608 	thread_ports[3] = th_inspect_port;
609 	thread_flavors[3] = THREAD_FLAVOR_INSPECT;
610 
611 
612 	for (size_t i = 0; i < THREAD_PORT_COUNT; i++) {
613 		/*
614 		 * 1. Make sure can't get higher priv'ed ports from lower ones through
615 		 * thread_get_special_port()
616 		 */
617 		test_thread_get_special_port(thread_ports[i], thread_flavors[i]);
618 
619 		/*
620 		 * 2. Make sure our MIG intrans enforcement for threads does not break.
621 		 */
622 		test_thread_port_mig_intrans(thread_ports[i], thread_flavors[i]);
623 	}
624 
625 	for (size_t i = 0; i < THREAD_PORT_COUNT; i++) {
626 		mach_port_deallocate(mach_task_self(), thread_ports[i]);
627 	}
628 }
629