xref: /xnu-10063.121.3/osfmk/kern/exclaves_tests.c (revision 2c2f96dc2b9a4408a43d3150ae9c105355ca3daa)
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
exclaves_hello_exclave_test(__unused int64_t in,int64_t * out)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
exclaves_panic_exclave_test(__unused int64_t in,int64_t * out)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
exclaves_hello_tightbeam_test(__unused int64_t in,int64_t * out)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
exclaves_sensor_kpi_test(int64_t in,int64_t * out)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
exclaves_check_mem_usage_test(__unused int64_t in,int64_t * out)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