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