5 #include <darwintest.h>
7 #include <mach/host_priv.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>
17 T_GLOBAL_META(T_META_NAMESPACE("xnu.ipc"),
18 T_META_RUN_CONCURRENTLY(true));
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.
25 static int found_kernel_task
= 0;
28 check_secure_kernel(void)
31 size_t secure_kern_size
= sizeof(secure_kern
);
33 T_ASSERT_POSIX_SUCCESS(sysctlbyname("kern.secure_kernel", &secure_kern
,
34 &secure_kern_size
, NULL
, 0), NULL
);
37 T_SKIP("secure kernel: processor_set_tasks will not return kernel_task");
42 attempt_kernel_inspection(task_t task
)
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
;
49 if (pid_for_task(task
, &pid
)) {
53 T_QUIET
; T_LOG("Checking pid %d", pid
);
59 T_LOG("found kernel_task, attempting to inspect");
62 count
= TASK_BASIC_INFO_64_COUNT
;
63 T_EXPECT_MACH_SUCCESS(task_info(task
, TASK_BASIC_INFO_64
, (task_info_t
)&ti
,
64 &count
), "task_info(... TASK_BASIC_INFO_64 ...)");
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
++) {
70 thread_basic_info_data_t basic_info
;
71 mach_msg_type_number_t bi_count
= THREAD_BASIC_INFO_COUNT
;
73 kr
= thread_info(threads
[i
], THREAD_BASIC_INFO
,
74 (thread_info_t
)&basic_info
, &bi_count
);
76 * Ignore threads that have gone away.
78 if (kr
== MACH_SEND_INVALID_DEST
) {
79 T_LOG("ignoring thread that has been destroyed");
82 T_QUIET
; T_EXPECT_MACH_SUCCESS(kr
, "thread_info(... THREAD_BASIC_INFO ...)");
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
);
93 /* READ (with eval) interfaces should fail */
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");
98 (void)mach_port_deallocate(mach_task_self(), threads
[i
]);
100 mach_vm_deallocate(mach_task_self(),
101 (mach_vm_address_t
)(uintptr_t)threads
,
102 thcnt
* sizeof(*threads
));
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");
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
,
112 &tblcnt
, &tree
, &treecnt
), "mach_port_space_info");
114 mach_vm_deallocate(mach_task_self(),
115 (mach_vm_address_t
)(uintptr_t)table
,
116 tblcnt
* sizeof(*table
));
119 mach_vm_deallocate(mach_task_self(),
120 (mach_vm_address_t
)(uintptr_t)tree
,
121 treecnt
* sizeof(*tree
));
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
);
133 /* READ (with eval) interfaces should fail */
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 */
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");
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");
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");
150 T_DECL(inspect_kernel_task
,
151 "ensure that kernel task can be inspected",
152 T_META_CHECK_LEAKS(false),
155 processor_set_name_array_t psets
;
156 processor_set_t pset
;
158 mach_msg_type_number_t i
, j
, tcnt
, pcnt
= 0;
159 mach_port_t self
= mach_host_self();
161 check_secure_kernel();
163 T_ASSERT_MACH_SUCCESS(host_processor_sets(self
, &psets
, &pcnt
),
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);
171 T_LOG("Attempting kernel inspection with control port...");
172 T_ASSERT_MACH_SUCCESS(processor_set_tasks(pset
, &tasks
, &tcnt
), NULL
);
174 for (j
= 0; j
< tcnt
; j
++) {
175 attempt_kernel_inspection(tasks
[j
]);
176 mach_port_deallocate(self
, tasks
[j
]);
179 /* free tasks array */
180 mach_vm_deallocate(mach_task_self(),
181 (mach_vm_address_t
)(uintptr_t)tasks
,
182 tcnt
* sizeof(*tasks
));
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
);
187 for (j
= 0; j
< tcnt
; j
++) {
188 attempt_kernel_inspection(tasks
[j
]);
189 mach_port_deallocate(self
, tasks
[j
]);
192 mach_vm_deallocate(mach_task_self(),
193 (mach_vm_address_t
)(uintptr_t)tasks
,
194 tcnt
* sizeof(*tasks
));
196 mach_port_deallocate(mach_task_self(), pset
);
197 mach_port_deallocate(mach_task_self(), psets
[i
]);
199 mach_vm_deallocate(mach_task_self(),
200 (mach_vm_address_t
)(uintptr_t)psets
,
201 pcnt
* sizeof(*psets
));
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");