]>
Commit | Line | Data |
---|---|---|
1 | #include <stdio.h> | |
2 | #include <stdlib.h> | |
3 | #include <unistd.h> | |
4 | #include <darwintest.h> | |
5 | #include <mach/mach.h> | |
6 | #include <mach/mach_vm.h> | |
7 | #include <sys/sysctl.h> | |
8 | #include <spawn.h> | |
9 | #include <signal.h> | |
10 | ||
11 | #define IKOT_TASK_CONTROL 2 | |
12 | ||
13 | T_GLOBAL_META( | |
14 | T_META_NAMESPACE("xnu.ipc"), | |
15 | T_META_RUN_CONCURRENTLY(TRUE)); | |
16 | ||
17 | static void | |
18 | test_extract_immovable_task_port(pid_t pid) | |
19 | { | |
20 | kern_return_t kr; | |
21 | mach_port_t tport = MACH_PORT_NULL; | |
22 | ipc_info_space_t space_info; | |
23 | ipc_info_name_array_t table; | |
24 | mach_msg_type_number_t tableCount; | |
25 | ipc_info_tree_name_array_t tree; /* unused */ | |
26 | mach_msg_type_number_t treeCount; /* unused */ | |
27 | ||
28 | mach_port_t extracted; | |
29 | mach_msg_type_name_t right; | |
30 | ||
31 | ||
32 | kr = task_for_pid(mach_task_self(), pid, &tport); | |
33 | T_EXPECT_MACH_SUCCESS(kr, "task_for_pid(), tport: 0x%x", tport); | |
34 | ||
35 | T_LOG("Target pid: %d", pid); | |
36 | ||
37 | if (pid == getpid()) { | |
38 | /* self extraction should succeed */ | |
39 | kr = mach_port_extract_right(mach_task_self(), mach_task_self(), MACH_MSG_TYPE_COPY_SEND, &extracted, &right); | |
40 | T_EXPECT_MACH_SUCCESS(kr, "mach_port_extract_right() on immovable port in current space should succeed"); | |
41 | } else { | |
42 | unsigned int kotype = 0, kobject = 0; | |
43 | mach_port_name_t tport_name = MACH_PORT_NULL; | |
44 | kr = mach_port_space_info(tport, &space_info, &table, &tableCount, &tree, &treeCount); | |
45 | T_EXPECT_MACH_SUCCESS(kr, "mach_port_space_info()"); | |
46 | ||
47 | for (int i = 0; i < tableCount; i++) { | |
48 | T_LOG("Searching for task port..name: 0x%x", table[i].iin_name); | |
49 | kr = mach_port_kernel_object(tport, table[i].iin_name, &kotype, &kobject); | |
50 | if (KERN_SUCCESS == kr && kotype == IKOT_TASK_CONTROL) { | |
51 | tport_name = table[i].iin_name; | |
52 | break; | |
53 | } else if (kr) { | |
54 | T_LOG("mach_port_kernel_object() failed on name 0x%x, kr: 0x%x", table[i].iin_name, kr); | |
55 | } | |
56 | } | |
57 | ||
58 | if (!tport_name) { | |
59 | T_FAIL("Did not find task port in child's space"); | |
60 | } | |
61 | T_LOG("Remote tport name: 0x%x", tport_name); | |
62 | kr = mach_port_extract_right(tport, tport_name, MACH_MSG_TYPE_COPY_SEND, &extracted, &right); | |
63 | T_EXPECT_EQ(kr, KERN_INVALID_CAPABILITY, "mach_port_extract_right() on immovable port in child's space should fail (no crash): 0x%x", kr); | |
64 | ||
65 | T_LOG("Still alive.."); | |
66 | } | |
67 | } | |
68 | ||
69 | T_DECL(extract_right_soft_fail, "Test mach_port_extract_right() fail on extracting child process's task port without crash", | |
70 | T_META_CHECK_LEAKS(false)) | |
71 | { | |
72 | uint32_t opts = 0; | |
73 | size_t size = sizeof(&opts); | |
74 | pid_t child_pid; | |
75 | kern_return_t ret; | |
76 | int status, fd[2]; | |
77 | ||
78 | T_LOG("Check if immovable control port has been enabled\n"); | |
79 | ret = sysctlbyname("kern.ipc_control_port_options", &opts, &size, NULL, 0); | |
80 | ||
81 | if (!ret && (opts & 0x20) == 0) { | |
82 | T_SKIP("immovable control port hard enforcement isn't enabled"); | |
83 | } | |
84 | ||
85 | /* extracting mach_task_self() should succeed */ | |
86 | test_extract_immovable_task_port(getpid()); | |
87 | ||
88 | ret = pipe(fd); | |
89 | T_EXPECT_NE(ret, -1, "pipe creation"); | |
90 | ||
91 | ||
92 | child_pid = fork(); | |
93 | ||
94 | if (child_pid < 0) { | |
95 | T_FAIL("fork failed()"); | |
96 | } | |
97 | ||
98 | if (child_pid == 0) { | |
99 | close(fd[0]); | |
100 | write(fd[1], "wakeup", 6); | |
101 | close(fd[1]); | |
102 | } else { | |
103 | close(fd[1]); | |
104 | char data[6]; | |
105 | read(fd[0], data, 6); /* blocks until data available */ | |
106 | close(fd[0]); | |
107 | ||
108 | /* extracting child's immovable task port should fail without crash */ | |
109 | test_extract_immovable_task_port(child_pid); | |
110 | ||
111 | kill(child_pid, SIGKILL); | |
112 | wait(&status); | |
113 | } | |
114 | } |