1 | /* |
2 | * Copyright (c) 2023 Apple Inc. All rights reserved. |
3 | * |
4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ |
5 | * |
6 | * This file contains Original Code and/or Modifications of Original Code |
7 | * as defined in and that are subject to the Apple Public Source License |
8 | * Version 2.0 (the 'License'). You may not use this file except in |
9 | * compliance with the License. The rights granted to you under the License |
10 | * may not be used to create, or enable the creation or redistribution of, |
11 | * unlawful or unlicensed copies of an Apple operating system, or to |
12 | * circumvent, violate, or enable the circumvention or violation of, any |
13 | * terms of an Apple operating system software license agreement. |
14 | * |
15 | * Please obtain a copy of the License at |
16 | * http://www.opensource.apple.com/apsl/ and read it before using this file. |
17 | * |
18 | * The Original Code and all software distributed under the License are |
19 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER |
20 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
21 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, |
22 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. |
23 | * Please see the License for the specific language governing rights and |
24 | * limitations under the License. |
25 | * |
26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ |
27 | */ |
28 | |
29 | #if CONFIG_EXCLAVES |
30 | |
31 | #if DEVELOPMENT || DEBUG |
32 | |
33 | #include <kern/kalloc.h> |
34 | #include <kern/locks.h> |
35 | |
36 | #include <mach/exclaves_l4.h> |
37 | |
38 | #include <Tightbeam/tightbeam.h> |
39 | #include <Tightbeam/tightbeam_private.h> |
40 | #include "kern/exclaves.tightbeam.h" |
41 | #include "exclaves_debug.h" |
42 | |
43 | /* External & generated headers */ |
44 | #include <xrt_hosted_types/types.h> |
45 | #include <xnuproxy/messages.h> |
46 | #include "exclaves_resource.h" |
47 | |
48 | #if __has_include(<Tightbeam/tightbeam.h>) |
49 | |
50 | #define EXCLAVES_ID_HELLO_EXCLAVE_EP \ |
51 | (exclaves_service_lookup(EXCLAVES_DOMAIN_KERNEL, \ |
52 | "com.apple.service.HelloExclave")) |
53 | |
54 | static int |
55 | exclaves_hello_exclave_test(__unused int64_t in, int64_t *out) |
56 | { |
57 | kern_return_t kr = KERN_SUCCESS; |
58 | |
59 | if (exclaves_get_status() != EXCLAVES_STATUS_AVAILABLE) { |
60 | exclaves_debug_printf(show_test_output, |
61 | "%s: SKIPPED: Exclaves not available\n" , __func__); |
62 | *out = -1; |
63 | return 0; |
64 | } |
65 | |
66 | exclaves_debug_printf(show_test_output, "%s: STARTING\n" , __func__); |
67 | |
68 | Exclaves_L4_IpcBuffer_t *ipcb; |
69 | kr = exclaves_allocate_ipc_buffer((void**)&ipcb); |
70 | assert(kr == KERN_SUCCESS); |
71 | assert(ipcb != NULL); |
72 | |
73 | exclaves_tag_t tag = Exclaves_L4_MessageTag(0, 0, 0x1338ul, |
74 | Exclaves_L4_False); |
75 | |
76 | exclaves_debug_printf(show_test_output, |
77 | "exclaves: exclaves_endpoint_call() sending tag 0x%llx, " |
78 | "label 0x%lx\n" , tag, Exclaves_L4_MessageTag_Label(tag)); |
79 | |
80 | exclaves_error_t error; |
81 | kr = exclaves_endpoint_call(IPC_PORT_NULL, EXCLAVES_ID_HELLO_EXCLAVE_EP, |
82 | &tag, &error); |
83 | assert(kr == KERN_SUCCESS); |
84 | |
85 | exclaves_debug_printf(show_test_output, |
86 | "exclaves: exclaves_endpoint_call() returned tag 0x%llx, " |
87 | "label 0x%lx, error 0x%llx\n" , tag, Exclaves_L4_MessageTag_Label(tag), |
88 | error); |
89 | |
90 | assert(error == Exclaves_L4_Success); |
91 | assert(Exclaves_L4_MessageTag_Mrs(tag) == 0); |
92 | assert((uint16_t)Exclaves_L4_MessageTag_Label(tag) == (uint16_t)0x1339ul); |
93 | |
94 | kr = exclaves_free_ipc_buffer(); |
95 | assert(kr == KERN_SUCCESS); |
96 | |
97 | exclaves_debug_printf(show_test_output, "%s: SUCCESS\n" , __func__); |
98 | *out = 1; |
99 | |
100 | return 0; |
101 | } |
102 | SYSCTL_TEST_REGISTER(exclaves_hello_exclave_test, exclaves_hello_exclave_test); |
103 | |
104 | static int |
105 | exclaves_panic_exclave_test(__unused int64_t in, int64_t *out) |
106 | { |
107 | kern_return_t kr = KERN_SUCCESS; |
108 | |
109 | if (exclaves_get_status() != EXCLAVES_STATUS_AVAILABLE) { |
110 | exclaves_debug_printf(show_test_output, |
111 | "%s: SKIPPED: Exclaves not available\n" , __func__); |
112 | *out = -1; |
113 | return 0; |
114 | } |
115 | |
116 | printf("%s: STARTING\n" , __func__); |
117 | |
118 | Exclaves_L4_IpcBuffer_t *ipcb; |
119 | kr = exclaves_allocate_ipc_buffer((void**)&ipcb); |
120 | assert(kr == KERN_SUCCESS); |
121 | assert(ipcb != NULL); |
122 | |
123 | // 0x9 tag will panic the HELLO C Exclave example |
124 | exclaves_tag_t tag = Exclaves_L4_MessageTag(0, 0, 0x9ul, |
125 | Exclaves_L4_False); |
126 | |
127 | exclaves_debug_printf(show_test_output, |
128 | "exclaves: exclaves_endpoint_call() sending tag 0x%llx, " |
129 | "label 0x%lx\n" , tag, Exclaves_L4_MessageTag_Label(tag)); |
130 | |
131 | exclaves_error_t error; |
132 | kr = exclaves_endpoint_call(IPC_PORT_NULL, EXCLAVES_ID_HELLO_EXCLAVE_EP, |
133 | &tag, &error); |
134 | |
135 | /* Should never reach here */ |
136 | assert(kr == KERN_SUCCESS); |
137 | |
138 | exclaves_debug_printf(show_test_output, |
139 | "exclaves: exclaves_endpoint_call() returned tag 0x%llx, " |
140 | "label 0x%lx, error 0x%llx\n" , tag, Exclaves_L4_MessageTag_Label(tag), |
141 | error); |
142 | |
143 | assert(error == Exclaves_L4_Success); |
144 | |
145 | kr = exclaves_free_ipc_buffer(); |
146 | assert(kr == KERN_SUCCESS); |
147 | |
148 | /* This should not be reachable. Hence, failed. */ |
149 | exclaves_debug_printf(show_errors, "%s: FAILED\n" , __func__); |
150 | *out = 1; |
151 | |
152 | return 0; |
153 | } |
154 | SYSCTL_TEST_REGISTER(exclaves_panic_exclave_test, exclaves_panic_exclave_test); |
155 | |
156 | #define EXCLAVES_ID_SWIFT_HELLO_EXCLAVE_EP \ |
157 | (exclaves_service_lookup(EXCLAVES_DOMAIN_KERNEL, \ |
158 | "com.apple.service.HelloTightbeam")) |
159 | |
160 | static int |
161 | exclaves_hello_tightbeam_test(__unused int64_t in, int64_t *out) |
162 | { |
163 | if (exclaves_get_status() != EXCLAVES_STATUS_AVAILABLE) { |
164 | exclaves_debug_printf(show_test_output, |
165 | "%s: SKIPPED: Exclaves not available\n" , __func__); |
166 | *out = -1; |
167 | return 0; |
168 | } |
169 | |
170 | exclaves_debug_printf(show_test_output, "%s: STARTING\n" , __func__); |
171 | tb_endpoint_t ep = tb_endpoint_create_with_value( |
172 | TB_TRANSPORT_TYPE_XNU, EXCLAVES_ID_SWIFT_HELLO_EXCLAVE_EP, 0); |
173 | |
174 | tb_client_connection_t client = |
175 | tb_client_connection_create_with_endpoint(ep); |
176 | |
177 | tb_client_connection_activate(client); |
178 | |
179 | tb_message_t message = NULL; |
180 | tb_transport_message_buffer_t tpt_buf = NULL; |
181 | |
182 | message = kalloc_type(struct tb_message_s, Z_WAITOK | Z_ZERO | Z_NOFAIL); |
183 | tpt_buf = kalloc_type(struct tb_transport_message_buffer_s, |
184 | Z_WAITOK | Z_ZERO | Z_NOFAIL); |
185 | |
186 | const char *hello_tb = "Hello!" ; |
187 | const char *hello = hello_tb; |
188 | const char *goodbye = "Goodbye!" ; |
189 | |
190 | tb_error_t err = TB_ERROR_SUCCESS; |
191 | err = tb_client_connection_message_construct(client, message, |
192 | tpt_buf, strlen(hello), 0); |
193 | if (err != TB_ERROR_SUCCESS) { |
194 | exclaves_debug_printf(show_errors, |
195 | "%s: FAILURE -- Failed to construct message\n" , __func__); |
196 | *out = 0; |
197 | goto out; |
198 | } |
199 | exclaves_debug_printf(show_test_output, |
200 | "%s: Tightbeam constructing message: " , __func__); |
201 | for (const char *c = hello; *c; c++) { |
202 | exclaves_debug_printf(show_test_output, "%c" , (uint8_t)*c); |
203 | tb_message_encode_u8(message, (uint8_t)*c); |
204 | } |
205 | exclaves_debug_printf(show_test_output, "\n" ); |
206 | tb_message_complete(message); |
207 | exclaves_debug_printf(show_test_output, |
208 | "%s: Tightbeam message completed\n" , __func__); |
209 | |
210 | tb_message_t response = NULL; |
211 | |
212 | err = tb_connection_send_query(client, message, &response, |
213 | TB_CONNECTION_WAIT_FOR_REPLY); |
214 | if (err != TB_ERROR_SUCCESS) { |
215 | exclaves_debug_printf(show_errors, |
216 | "%s: FAILURE -- Failed to send message\n" , __func__); |
217 | goto out; |
218 | } |
219 | exclaves_debug_printf(show_test_output, |
220 | "%s: Tightbeam message send success, reply: " , __func__); |
221 | |
222 | bool mismatch = false; |
223 | uint8_t val = 0; |
224 | for (const char *c = goodbye; *c; c++) { |
225 | tb_message_decode_u8(response, &val); |
226 | exclaves_debug_printf(show_test_output, "%c" , val); |
227 | if (val != (uint8_t)*c) { |
228 | mismatch = true; |
229 | } |
230 | } |
231 | exclaves_debug_printf(show_test_output, "\n" ); |
232 | if (mismatch) { |
233 | exclaves_debug_printf(show_errors, |
234 | "%s: FAILURE -- Mismatched reply message\n" , __func__); |
235 | *out = 0; |
236 | goto out; |
237 | } |
238 | tb_client_connection_message_destruct(client, message); |
239 | |
240 | exclaves_debug_printf(show_test_output, "%s: SUCCESS\n" , __func__); |
241 | *out = 1; |
242 | |
243 | out: |
244 | kfree_type(struct tb_message_s, message); |
245 | kfree_type(struct tb_transport_message_buffer_s, tpt_buf); |
246 | return 0; |
247 | } |
248 | |
249 | SYSCTL_TEST_REGISTER(exclaves_hello_tightbeam_test, |
250 | exclaves_hello_tightbeam_test); |
251 | |
252 | #endif /* __has_include(<Tightbeam/tightbeam.h>) */ |
253 | |
254 | static int |
255 | exclaves_sensor_kpi_test(int64_t in, int64_t *out) |
256 | { |
257 | #pragma unused(in) |
258 | #define SENSOR_TEST(x) \ |
259 | if (!(x)) { \ |
260 | exclaves_debug_printf(show_errors, \ |
261 | "%s: FAILURE -- %s:%d\n", __func__, __FILE__, __LINE__); \ |
262 | success = false; \ |
263 | goto out; \ |
264 | } |
265 | |
266 | bool success = true; |
267 | exclaves_debug_printf(show_test_output, "%s: STARTING\n" , __func__); |
268 | |
269 | exclaves_sensor_type_t sensors[] = { |
270 | EXCLAVES_SENSOR_CAM, |
271 | EXCLAVES_SENSOR_MIC, |
272 | EXCLAVES_SENSOR_CAM_ALT_FACEID, |
273 | }; |
274 | unsigned num_sensors = sizeof(sensors) / sizeof(sensors[0]); |
275 | exclaves_sensor_status_t sensor_status = EXCLAVES_SENSOR_STATUS_DENIED; |
276 | exclaves_sensor_type_t bad = |
277 | (exclaves_sensor_type_t) (unsigned) (EXCLAVES_SENSOR_MAX + 1); |
278 | kern_return_t kr; |
279 | |
280 | /* invalid sensor */ |
281 | kr = exclaves_sensor_stop(bad, 0, &sensor_status); |
282 | SENSOR_TEST(kr == KERN_INVALID_ARGUMENT); |
283 | |
284 | kr = exclaves_sensor_start(bad, 0, &sensor_status); |
285 | SENSOR_TEST(kr == KERN_INVALID_ARGUMENT); |
286 | |
287 | kr = exclaves_sensor_status(bad, 0, &sensor_status); |
288 | SENSOR_TEST(kr == KERN_INVALID_ARGUMENT); |
289 | |
290 | /* stop before start */ |
291 | for (unsigned i = 0; i < num_sensors; i++) { |
292 | kr = exclaves_sensor_stop(sensors[i], 0, &sensor_status); |
293 | SENSOR_TEST(kr == KERN_INVALID_ARGUMENT); |
294 | } |
295 | |
296 | /* start status is denied */ |
297 | for (unsigned i = 0; i < num_sensors; i++) { |
298 | kr = exclaves_sensor_status(sensors[i], 0, &sensor_status); |
299 | SENSOR_TEST(kr == KERN_SUCCESS); |
300 | SENSOR_TEST(sensor_status == EXCLAVES_SENSOR_STATUS_ALLOWED); /* Not enforced */ |
301 | } |
302 | |
303 | /* ALLOWED after at least 1 start */ |
304 | unsigned const n = 5; |
305 | for (unsigned i = 0; i < num_sensors; i++) { |
306 | for (unsigned j = 0; j < n; j++) { |
307 | kr = exclaves_sensor_start(sensors[i], 0, &sensor_status); |
308 | SENSOR_TEST(kr == KERN_SUCCESS); |
309 | SENSOR_TEST(sensor_status == EXCLAVES_SENSOR_STATUS_ALLOWED); |
310 | kr = exclaves_sensor_status(sensors[i], 0, &sensor_status); |
311 | SENSOR_TEST(kr == KERN_SUCCESS); |
312 | SENSOR_TEST(sensor_status == EXCLAVES_SENSOR_STATUS_ALLOWED); |
313 | } |
314 | } |
315 | |
316 | /* ALLOWED after n-1 stops */ |
317 | for (unsigned i = 0; i < num_sensors; i++) { |
318 | for (unsigned j = 0; j < n - 1; j++) { |
319 | kr = exclaves_sensor_stop(sensors[i], 0, &sensor_status); |
320 | SENSOR_TEST(kr == KERN_SUCCESS); |
321 | SENSOR_TEST(sensor_status == EXCLAVES_SENSOR_STATUS_ALLOWED); |
322 | kr = exclaves_sensor_status(sensors[i], 0, &sensor_status); |
323 | SENSOR_TEST(kr == KERN_SUCCESS); |
324 | SENSOR_TEST(sensor_status == EXCLAVES_SENSOR_STATUS_ALLOWED); |
325 | } |
326 | } |
327 | |
328 | /* DENIED after final stop */ |
329 | for (unsigned i = 0; i < num_sensors; i++) { |
330 | kr = exclaves_sensor_stop(sensors[i], 0, &sensor_status); |
331 | SENSOR_TEST(kr == KERN_SUCCESS); |
332 | SENSOR_TEST(sensor_status == EXCLAVES_SENSOR_STATUS_ALLOWED); /* Not enforced */ |
333 | } |
334 | |
335 | /* exclaves_display_healthcheck_rate does something */ |
336 | kr = exclaves_display_healthcheck_rate(NSEC_PER_SEC / 60); |
337 | SENSOR_TEST(kr == KERN_SUCCESS); |
338 | |
339 | #undef SENSOR_TEST |
340 | out: |
341 | if (success) { |
342 | exclaves_debug_printf(show_test_output, |
343 | "%s: SUCCESS\n" , __func__); |
344 | *out = 1; |
345 | } else { |
346 | exclaves_debug_printf(show_errors, "%s: FAILED\n" , __func__); |
347 | *out = 0; |
348 | } |
349 | return 0; |
350 | } |
351 | SYSCTL_TEST_REGISTER(exclaves_sensor_kpi_test, |
352 | exclaves_sensor_kpi_test); |
353 | |
354 | static int |
355 | exclaves_check_mem_usage_test(__unused int64_t in, int64_t *out) |
356 | { |
357 | if (exclaves_get_status() != EXCLAVES_STATUS_AVAILABLE) { |
358 | exclaves_debug_printf(show_test_output, |
359 | "%s: SKIPPED: Exclaves not available\n" , __func__); |
360 | *out = -1; |
361 | return 0; |
362 | } |
363 | |
364 | exclaves_debug_printf(show_test_output, "%s: STARTING\n" , __func__); |
365 | |
366 | kern_return_t r = exclaves_xnu_proxy_check_mem_usage(); |
367 | if (r == KERN_FAILURE) { |
368 | exclaves_debug_printf(show_errors, |
369 | "Exclave Check Memory Usage failed: Kernel Failure\n" ); |
370 | return 0; |
371 | } |
372 | |
373 | exclaves_debug_printf(show_test_output, "%s: SUCCESS\n" , __func__); |
374 | *out = 1; |
375 | |
376 | return 0; |
377 | } |
378 | SYSCTL_TEST_REGISTER(exclaves_check_mem_usage_test, exclaves_check_mem_usage_test); |
379 | |
380 | |
381 | #endif /* DEVELOPMENT || DEBUG */ |
382 | |
383 | #endif /* CONFIG_EXCLAVES */ |
384 | |