1 #ifdef T_NAMESPACE
2 #undef T_NAMESPACE
3 #endif
4
5 #include <darwintest.h>
6
7 #include <mach/host_priv.h>
8 #include <mach/mach.h>
9 #include <mach/mach_types.h>
10 #include <mach/mach_vm.h>
11 #include <mach/processor_set.h>
12 #include <mach/task.h>
13 #include <sys/sysctl.h>
14 #include <mach_debug/ipc_info.h>
15 #include <unistd.h>
16
17 T_GLOBAL_META(T_META_NAMESPACE("xnu.ipc"),
18 T_META_RADAR_COMPONENT_NAME("xnu"),
19 T_META_RADAR_COMPONENT_VERSION("IPC"),
20 T_META_RUN_CONCURRENTLY(true));
21
22 /*
23 * Attempt to inspect kernel_task using a task_inspect_t. Interact with the
24 * kernel in the same way top(1) and lsmp(1) do.
25 */
26
27 static int found_kernel_task = 0;
28
29 static void
check_secure_kernel(void)30 check_secure_kernel(void)
31 {
32 int secure_kern = 0;
33 size_t secure_kern_size = sizeof(secure_kern);
34
35 T_ASSERT_POSIX_SUCCESS(sysctlbyname("kern.secure_kernel", &secure_kern,
36 &secure_kern_size, NULL, 0), NULL);
37
38 if (secure_kern) {
39 T_SKIP("secure kernel: processor_set_tasks will not return kernel_task");
40 }
41 }
42
43 static void
attempt_kernel_inspection(task_t task)44 attempt_kernel_inspection(task_t task)
45 {
46 pid_t pid = (pid_t)-1;
47 mach_msg_type_number_t i, count, thcnt;
48 struct task_basic_info_64 ti;
49 thread_act_array_t threads;
50
51 if (pid_for_task(task, &pid)) {
52 return;
53 }
54
55 T_QUIET; T_LOG("Checking pid %d", pid);
56
57 if (pid != 0) {
58 return;
59 }
60
61 T_LOG("found kernel_task, attempting to inspect");
62 found_kernel_task++;
63
64 count = TASK_BASIC_INFO_64_COUNT;
65 T_EXPECT_MACH_SUCCESS(task_info(task, TASK_BASIC_INFO_64, (task_info_t)&ti,
66 &count), "task_info(... TASK_BASIC_INFO_64 ...)");
67
68 T_EXPECT_MACH_SUCCESS(task_threads(task, &threads, &thcnt), "task_threads");
69 T_LOG("Found %d kernel threads.", thcnt);
70 for (i = 0; i < thcnt; i++) {
71 kern_return_t kr;
72 thread_basic_info_data_t basic_info;
73 mach_msg_type_number_t bi_count = THREAD_BASIC_INFO_COUNT;
74
75 kr = thread_info(threads[i], THREAD_BASIC_INFO,
76 (thread_info_t)&basic_info, &bi_count);
77 /*
78 * Ignore threads that have gone away.
79 */
80 if (kr == MACH_SEND_INVALID_DEST) {
81 T_LOG("ignoring thread that has been destroyed");
82 continue;
83 }
84 T_QUIET; T_EXPECT_MACH_SUCCESS(kr, "thread_info(... THREAD_BASIC_INFO ...)");
85
86 /* Now try out READ (skip eval) interfaces on kernel thread */
87 mach_msg_type_number_t msk_count = EXC_TYPES_COUNT;
88 exception_mask_t masks[EXC_TYPES_COUNT];
89 ipc_info_port_t ports_info[EXC_TYPES_COUNT];
90 exception_behavior_t behaviors[EXC_TYPES_COUNT];
91 thread_state_flavor_t flavors[EXC_TYPES_COUNT];
92 kr = thread_get_exception_ports_info(threads[i], EXC_MASK_ALL, masks, &msk_count, ports_info, behaviors, flavors);
93 T_QUIET; T_EXPECT_MACH_SUCCESS(kr, "thread_get_exception_ports_info() on kernel thread: 0x%x", kr);
94
95 /* READ (with eval) interfaces should fail */
96 mach_port_t voucher;
97 kr = thread_get_mach_voucher(threads[i], 0, &voucher);
98 T_QUIET; T_EXPECT_EQ(kr, KERN_INVALID_ARGUMENT, "thread_get_mach_voucher() should fail with KERN_INVALID_ARGUMENT");
99
100 (void)mach_port_deallocate(mach_task_self(), threads[i]);
101 }
102 mach_vm_deallocate(mach_task_self(),
103 (mach_vm_address_t)(uintptr_t)threads,
104 thcnt * sizeof(*threads));
105
106 ipc_info_space_basic_t basic_info;
107 T_EXPECT_MACH_SUCCESS(mach_port_space_basic_info(task, &basic_info), "mach_port_space_basic_info");
108
109 ipc_info_space_t info_space;
110 ipc_info_name_array_t table;
111 ipc_info_tree_name_array_t tree;
112 mach_msg_type_number_t tblcnt = 0, treecnt = 0;
113 T_EXPECT_MACH_SUCCESS(mach_port_space_info(task, &info_space, &table,
114 &tblcnt, &tree, &treecnt), "mach_port_space_info");
115 if (tblcnt > 0) {
116 mach_vm_deallocate(mach_task_self(),
117 (mach_vm_address_t)(uintptr_t)table,
118 tblcnt * sizeof(*table));
119 }
120 if (treecnt > 0) {
121 mach_vm_deallocate(mach_task_self(),
122 (mach_vm_address_t)(uintptr_t)tree,
123 treecnt * sizeof(*tree));
124 }
125
126 /* Now try out READ (skip eval) interfaces on kernel task */
127 mach_msg_type_number_t msk_count = EXC_TYPES_COUNT;
128 exception_mask_t masks[EXC_TYPES_COUNT];
129 ipc_info_port_t ports_info[EXC_TYPES_COUNT];
130 exception_behavior_t behaviors[EXC_TYPES_COUNT];
131 thread_state_flavor_t flavors[EXC_TYPES_COUNT];
132 kern_return_t kr = task_get_exception_ports_info(task, EXC_MASK_ALL, masks, &msk_count, ports_info, behaviors, flavors);
133 T_EXPECT_MACH_SUCCESS(kr, "task_get_exception_ports_info() on kernel_task: 0x%x", kr);
134
135 /* READ (with eval) interfaces should fail */
136 vm_offset_t data;
137 mach_msg_type_number_t cnt;
138 mach_vm_address_t addr = 0x10000000; /* can be whatever, the call should fail before getting to VM */
139
140 kr = mach_vm_read(task, (mach_vm_address_t)addr, 8, &data, &cnt);
141 T_EXPECT_EQ(kr, KERN_INVALID_ARGUMENT, "mach_vm_read() should fail with KERN_INVALID_ARGUMENT");
142
143 mach_port_t voucher;
144 kr = task_get_mach_voucher(task, 0, &voucher);
145 T_EXPECT_EQ(kr, KERN_INVALID_TASK, "task_get_mach_voucher() should fail with KERN_INVALID_TASK");
146
147 /* Control interfaces should absolutely fail */
148 kr = task_set_mach_voucher(task, mach_task_self()); /* voucher arg is unused, can be whatever port */
149 T_EXPECT_EQ(kr, KERN_INVALID_TASK, "task_set_mach_voucher() should fail with KERN_INVALID_TASK");
150 }
151
152 T_DECL(inspect_kernel_task,
153 "ensure that kernel task can be inspected",
154 T_META_CHECK_LEAKS(false),
155 T_META_ASROOT(true))
156 {
157 processor_set_name_array_t psets;
158 processor_set_t pset;
159 task_array_t tasks;
160 mach_msg_type_number_t i, j, tcnt, pcnt = 0;
161 mach_port_t self = mach_host_self();
162
163 check_secure_kernel();
164
165 T_ASSERT_MACH_SUCCESS(host_processor_sets(self, &psets, &pcnt),
166 NULL);
167
168 for (i = 0; i < pcnt; i++) {
169 T_ASSERT_MACH_SUCCESS(host_processor_set_priv(self, psets[i], &pset), NULL);
170 T_LOG("Checking pset %d/%d", i, pcnt - 1);
171
172 tcnt = 0;
173 T_LOG("Attempting kernel inspection with control port...");
174 T_ASSERT_MACH_SUCCESS(processor_set_tasks(pset, &tasks, &tcnt), NULL);
175
176 for (j = 0; j < tcnt; j++) {
177 attempt_kernel_inspection(tasks[j]);
178 mach_port_deallocate(self, tasks[j]);
179 }
180
181 /* free tasks array */
182 mach_vm_deallocate(mach_task_self(),
183 (mach_vm_address_t)(uintptr_t)tasks,
184 tcnt * sizeof(*tasks));
185
186 T_LOG("Attempting kernel inspection with read port...");
187 T_ASSERT_MACH_SUCCESS(processor_set_tasks_with_flavor(pset, TASK_FLAVOR_READ, &tasks, &tcnt), NULL);
188
189 for (j = 0; j < tcnt; j++) {
190 attempt_kernel_inspection(tasks[j]);
191 mach_port_deallocate(self, tasks[j]);
192 }
193
194 mach_vm_deallocate(mach_task_self(),
195 (mach_vm_address_t)(uintptr_t)tasks,
196 tcnt * sizeof(*tasks));
197
198 mach_port_deallocate(mach_task_self(), pset);
199 mach_port_deallocate(mach_task_self(), psets[i]);
200 }
201 mach_vm_deallocate(mach_task_self(),
202 (mach_vm_address_t)(uintptr_t)psets,
203 pcnt * sizeof(*psets));
204
205 if (found_kernel_task != 2) {
206 /* One for kernel control port test, one for kernel read port test. */
207 T_FAIL("could not find kernel_task in list of tasks returned");
208 }
209 }
210