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