xref: /xnu-10063.121.3/osfmk/kern/exclaves_conclave.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 #include <mach/kern_return.h>
32 #include <kern/assert.h>
33 #include <stdint.h>
34 #include <kern/startup.h>
35 #include <kern/locks.h>
36 #include <kern/kalloc.h>
37 #include <kern/task.h>
38 
39 #include <Tightbeam/tightbeam.h>
40 
41 #include "kern/exclaves.tightbeam.h"
42 
43 #include "exclaves_debug.h"
44 #include "exclaves_conclave.h"
45 #include "exclaves_resource.h"
46 
47 /* -------------------------------------------------------------------------- */
48 #pragma mark Conclave Launcher
49 
50 kern_return_t
exclaves_conclave_launcher_init(uint64_t id,tb_client_connection_t * connection)51 exclaves_conclave_launcher_init(uint64_t id, tb_client_connection_t *connection)
52 {
53 	assert3p(connection, !=, NULL);
54 
55 	tb_error_t tb_result = TB_ERROR_SUCCESS;
56 
57 	conclave_launcher_conclavecontrol_s control = {};
58 
59 	tb_endpoint_t conclave_control_endpoint =
60 	    tb_endpoint_create_with_value(TB_TRANSPORT_TYPE_XNU, id,
61 	    TB_ENDPOINT_OPTIONS_NONE);
62 
63 	tb_result = conclave_launcher_conclavecontrol__init(&control,
64 	    conclave_control_endpoint);
65 	if (tb_result != TB_ERROR_SUCCESS) {
66 		exclaves_debug_printf(show_errors,
67 		    "conclave init failure: %llu\n", id);
68 		return KERN_FAILURE;
69 	}
70 
71 	*connection = control.connection;
72 
73 	return KERN_SUCCESS;
74 }
75 
76 kern_return_t
exclaves_conclave_launcher_launch(const tb_client_connection_t connection)77 exclaves_conclave_launcher_launch(const tb_client_connection_t connection)
78 {
79 	assert3p(connection, !=, NULL);
80 
81 	tb_error_t tb_result = TB_ERROR_SUCCESS;
82 
83 	const conclave_launcher_conclavecontrol_s control = {
84 		.connection = connection,
85 	};
86 
87 	__block bool success = false;
88 
89 	/* BEGIN IGNORE CODESTYLE */
90 	tb_result = conclave_launcher_conclavecontrol_launch(&control,
91 	    ^(conclave_launcher_conclavecontrol_launch__result_s result) {
92 		conclave_launcher_conclavestatus_s *status = NULL;
93 		status = conclave_launcher_conclavecontrol_launch__result_get_success(&result);
94 		if (status != NULL) {
95 		        success = true;
96 		        return;
97 		}
98 
99 		conclave_launcher_conclavelauncherfailure_s *failure = NULL;
100 		failure = conclave_launcher_conclavecontrol_launch__result_get_failure(&result);
101 		assert3p(failure, !=, NULL);
102 		exclaves_debug_printf(show_errors,
103 		    "conclave launch failure: failure %u\n", *failure);
104 	});
105 	/* END IGNORE CODESTYLE */
106 
107 	if (tb_result != TB_ERROR_SUCCESS || !success) {
108 		return KERN_FAILURE;
109 	}
110 
111 	return KERN_SUCCESS;
112 }
113 
114 kern_return_t
exclaves_conclave_launcher_stop(const tb_client_connection_t connection,uint32_t stop_reason)115 exclaves_conclave_launcher_stop(const tb_client_connection_t connection,
116     uint32_t stop_reason)
117 {
118 	assert3p(connection, !=, NULL);
119 
120 	tb_error_t tb_result = TB_ERROR_SUCCESS;
121 
122 	const conclave_launcher_conclavecontrol_s control = {
123 		.connection = connection,
124 	};
125 
126 	__block bool success = false;
127 
128 	/* BEGIN IGNORE CODESTYLE */
129 	tb_result = conclave_launcher_conclavecontrol_stop(
130 	    &control, stop_reason, true,
131 	    ^(conclave_launcher_conclavecontrol_stop__result_s result) {
132 		conclave_launcher_conclavestatus_s *status = NULL;
133 		status = conclave_launcher_conclavecontrol_stop__result_get_success(&result);
134 		if (status != NULL) {
135 		        success = true;
136 		        return;
137 		}
138 
139 		conclave_launcher_conclavelauncherfailure_s *failure = NULL;
140 		failure = conclave_launcher_conclavecontrol_stop__result_get_failure(&result);
141 		assert3p(failure, !=, NULL);
142 
143 		exclaves_debug_printf(show_errors,
144 		    "conclave stop failure: failure %u\n", *failure);
145 	});
146 	/* END IGNORE CODESTYLE */
147 
148 	if (tb_result != TB_ERROR_SUCCESS || !success) {
149 		return KERN_FAILURE;
150 	}
151 
152 	return KERN_SUCCESS;
153 }
154 
155 
156 /* -------------------------------------------------------------------------- */
157 #pragma mark Conclave Upcalls
158 
159 tb_error_t
160 exclaves_conclave_upcall_suspend(const uint32_t flags,
161     tb_error_t (^completion)(xnuupcalls_xnuupcalls_conclave_suspend__result_s))
162 {
163 	xnuupcalls_conclavescidlist_s scid_list = {};
164 
165 	exclaves_debug_printf(show_lifecycle_upcalls,
166 	    "[lifecycle_upcalls] conclave_suspend flags %x\n", flags);
167 
168 	kern_return_t kret = task_suspend_conclave_upcall(scid_list.scid,
169 	    ARRAY_COUNT(scid_list.scid));
170 
171 	exclaves_debug_printf(show_lifecycle_upcalls,
172 	    "[lifecycle_upcalls] task_suspend_conclave_upcall returned %x\n", kret);
173 
174 	xnuupcalls_xnuupcalls_conclave_suspend__result_s result = {};
175 
176 	switch (kret) {
177 	case KERN_SUCCESS:
178 		xnuupcalls_xnuupcalls_conclave_suspend__result_init_success(&result, scid_list);
179 		break;
180 
181 	case KERN_INVALID_TASK:
182 	case KERN_INVALID_ARGUMENT:
183 		xnuupcalls_xnuupcalls_conclave_suspend__result_init_failure(&result,
184 		    XNUUPCALLS_LIFECYCLEERROR_INVALIDTASK);
185 		break;
186 
187 	default:
188 		xnuupcalls_xnuupcalls_conclave_suspend__result_init_failure(&result,
189 		    XNUUPCALLS_LIFECYCLEERROR_FAILURE);
190 		break;
191 	}
192 
193 	return completion(result);
194 }
195 
196 tb_error_t
197 exclaves_conclave_upcall_stop(const uint32_t flags,
198     tb_error_t (^completion)(xnuupcalls_xnuupcalls_conclave_stop__result_s))
199 {
200 	exclaves_debug_printf(show_lifecycle_upcalls,
201 	    "[lifecycle_upcalls] conclave_stop flags %x\n", flags);
202 
203 	kern_return_t kret = task_stop_conclave_upcall();
204 
205 	exclaves_debug_printf(show_lifecycle_upcalls,
206 	    "[lifecycle_upcalls] task_stop_conclave_upcall returned %x\n", kret);
207 
208 	xnuupcalls_xnuupcalls_conclave_stop__result_s result = {};
209 
210 	switch (kret) {
211 	case KERN_SUCCESS:
212 		xnuupcalls_xnuupcalls_conclave_stop__result_init_success(&result);
213 		break;
214 
215 	case KERN_INVALID_TASK:
216 	case KERN_INVALID_ARGUMENT:
217 		xnuupcalls_xnuupcalls_conclave_stop__result_init_failure(&result,
218 		    XNUUPCALLS_LIFECYCLEERROR_INVALIDTASK);
219 		break;
220 
221 	default:
222 		xnuupcalls_xnuupcalls_conclave_stop__result_init_failure(&result,
223 		    XNUUPCALLS_LIFECYCLEERROR_FAILURE);
224 		break;
225 	}
226 
227 	return completion(result);
228 }
229 
230 tb_error_t
231 exclaves_conclave_upcall_crash_info(const xnuupcalls_conclavesharedbuffer_s *shared_buf,
232     const uint32_t length,
233     tb_error_t (^completion)(xnuupcalls_xnuupcalls_conclave_crash_info__result_s ))
234 {
235 	task_t task;
236 
237 	/* Check if the thread was calling conclave stop on another task */
238 	task = current_thread()->conclave_stop_task;
239 	if (task == TASK_NULL) {
240 		task = current_task();
241 	}
242 
243 	exclaves_debug_printf(show_lifecycle_upcalls,
244 	    "[lifecycle_upcalls] conclave_crash_info\n");
245 
246 	kern_return_t kret = task_crash_info_conclave_upcall(task, shared_buf, length);
247 
248 	exclaves_debug_printf(show_lifecycle_upcalls,
249 	    "[lifecycle_upcalls] task_crash_info_conclave_upcall returned 0x%x\n", kret);
250 
251 	xnuupcalls_xnuupcalls_conclave_crash_info__result_s result = {};
252 
253 	switch (kret) {
254 	case KERN_SUCCESS:
255 		xnuupcalls_xnuupcalls_conclave_crash_info__result_init_success(&result);
256 		break;
257 
258 	case KERN_INVALID_TASK:
259 	case KERN_INVALID_ARGUMENT:
260 		xnuupcalls_xnuupcalls_conclave_crash_info__result_init_failure(&result,
261 		    XNUUPCALLS_LIFECYCLEERROR_INVALIDTASK);
262 		break;
263 
264 	default:
265 		xnuupcalls_xnuupcalls_conclave_crash_info__result_init_failure(&result,
266 		    XNUUPCALLS_LIFECYCLEERROR_FAILURE);
267 		break;
268 	}
269 
270 	return completion(result);
271 }
272 
273 #if DEVELOPMENT || DEBUG
274 
275 /* -------------------------------------------------------------------------- */
276 #pragma mark Testing
277 
278 typedef struct conclave_test_context {
279 	tb_endpoint_t conclave_control_endpoint;
280 	conclave_launcher_conclavecontrol_s conclave_control;
281 	tb_endpoint_t conclave_debug_endpoint;
282 	conclave_launcher_conclavedebug_s conclave_debug;
283 } conclave_test_context_t;
284 
285 extern lck_grp_t exclaves_lck_grp;
286 
287 LCK_MTX_DECLARE(exclaves_conclave_lock, &exclaves_lck_grp);
288 
289 static conclave_test_context_t *conclave_context = NULL;
290 
291 #define EXCLAVES_ID_CONCLAVECONTROL_EP               \
292     (exclaves_service_lookup(EXCLAVES_DOMAIN_KERNEL, \
293     "com.apple.service.ConclaveLauncherControl"))
294 
295 #define EXCLAVES_ID_CONCLAVEDEBUG_EP \
296     (exclaves_service_lookup(EXCLAVES_DOMAIN_KERNEL, \
297     "com.apple.service.ConclaveLauncherDebug"))
298 
299 static TUNABLE(bool, enable_hello_conclaves, "enable_hello_conclaves", false);
300 
301 static int
exclaves_hello_conclaves_test(int64_t in,int64_t * out)302 exclaves_hello_conclaves_test(int64_t in, int64_t *out)
303 {
304 	tb_error_t tb_result = TB_ERROR_SUCCESS;
305 	if (!enable_hello_conclaves) {
306 		exclaves_debug_printf(show_test_output,
307 		    "%s: SKIPPED: enable_hello_conclaves not set\n", __func__);
308 		*out = -1;
309 		return 0;
310 	}
311 
312 	if (exclaves_get_status() != EXCLAVES_STATUS_AVAILABLE) {
313 		exclaves_debug_printf(show_test_output,
314 		    "%s: SKIPPED: Exclaves not available\n", __func__);
315 		*out = -1;
316 		return 0;
317 	}
318 	lck_mtx_lock(&exclaves_conclave_lock);
319 	switch (in) {
320 	case 0: {         /* init */
321 		if (conclave_context != NULL) {
322 			break;
323 		}
324 
325 		conclave_context = kalloc_type(conclave_test_context_t, Z_WAITOK);
326 		assert(conclave_context != NULL);
327 
328 		/* BEGIN IGNORE CODESTYLE */
329 		conclave_context->conclave_control_endpoint =
330 		    tb_endpoint_create_with_value(TB_TRANSPORT_TYPE_XNU,
331 		    EXCLAVES_ID_CONCLAVECONTROL_EP, TB_ENDPOINT_OPTIONS_NONE);
332 		tb_result = conclave_launcher_conclavecontrol__init(
333 		    &conclave_context->conclave_control,
334 		    conclave_context->conclave_control_endpoint);
335 		assert(tb_result == TB_ERROR_SUCCESS);
336 
337 		conclave_context->conclave_debug_endpoint =
338 		    tb_endpoint_create_with_value(TB_TRANSPORT_TYPE_XNU,
339 		    EXCLAVES_ID_CONCLAVEDEBUG_EP, TB_ENDPOINT_OPTIONS_NONE);
340 		tb_result = conclave_launcher_conclavedebug__init(
341 		    &conclave_context->conclave_debug,
342 		    conclave_context->conclave_debug_endpoint);
343 		assert(tb_result == TB_ERROR_SUCCESS);
344 		/* END IGNORE CODESTYLE */
345 
346 		break;
347 	}
348 	case 1: {         /* launch conclave */
349 		assert(conclave_context != NULL);
350 
351 		/* BEGIN IGNORE CODESTYLE */
352 		tb_result = conclave_launcher_conclavecontrol_launch(
353 		    &conclave_context->conclave_control,
354 		    ^(conclave_launcher_conclavecontrol_launch__result_s result) {
355 			conclave_launcher_conclavestatus_s *status = NULL;
356 			status = conclave_launcher_conclavecontrol_launch__result_get_success(&result);
357 			if (status != NULL) {
358 			        exclaves_debug_printf(show_test_output,
359 			            "%s:%d conclave launch success: status %u\n",
360 			            __func__, __LINE__, *status);
361 			        return;
362 			}
363 
364 			conclave_launcher_conclavelauncherfailure_s *failure = NULL;
365 			failure = conclave_launcher_conclavecontrol_launch__result_get_failure(&result);
366 			assert3p(failure, !=, NULL);
367 			exclaves_debug_printf(show_errors,
368 			    "%s:%d conclave launch failure: failure %u\n",
369 			    __func__, __LINE__, *failure);
370 		});
371 		/* END IGNORE CODESTYLE */
372 
373 		if (tb_result != TB_ERROR_SUCCESS) {
374 			exclaves_debug_printf(show_errors,
375 			    "%s:%d conclave launch failure: tightbeam error %u\n",
376 			    __func__, __LINE__, tb_result);
377 		}
378 		break;
379 	}
380 	case 2: {         /* status */
381 		assert(conclave_context != NULL);
382 
383 		/* BEGIN IGNORE CODESTYLE */
384 		tb_result = conclave_launcher_conclavecontrol_status(
385 		    &conclave_context->conclave_control,
386 		    ^(conclave_launcher_conclavecontrol_status__result_s result) {
387 			conclave_launcher_conclavestatus_s *status = NULL;
388 			status = conclave_launcher_conclavecontrol_status__result_get_success(&result);
389 			if (status != NULL) {
390 			        exclaves_debug_printf(show_test_output,
391 			            "%s:%d conclave status success: status %u\n",
392 			            __func__, __LINE__, *status);
393 			        return;
394 			}
395 
396 			conclave_launcher_conclavelauncherfailure_s *failure = NULL;
397 			failure = conclave_launcher_conclavecontrol_status__result_get_failure(&result);
398 			assert3p(failure, !=, NULL);
399 			exclaves_debug_printf(show_errors,
400 			    "%s:%d conclave status failure: failure %u\n",
401 			    __func__, __LINE__, *failure);
402 		});
403 		/* END IGNORE CODESTYLE */
404 
405 		if (tb_result != TB_ERROR_SUCCESS) {
406 			exclaves_debug_printf(show_errors,
407 			    "%s:%d conclave status failure: tightbeam error %u\n",
408 			    __func__, __LINE__, tb_result);
409 		}
410 		break;
411 	}
412 	case 3: {         /* stop conclave */
413 		conclave_launcher_conclavestopreason_s stop_reason =
414 		    CONCLAVE_LAUNCHER_CONCLAVESTOPREASON_EXIT;
415 		assert(conclave_context != NULL);
416 
417 		/* BEGIN IGNORE CODESTYLE */
418 		tb_result = conclave_launcher_conclavecontrol_stop(
419 		    &conclave_context->conclave_control, stop_reason, true,
420 		    ^(conclave_launcher_conclavecontrol_stop__result_s result) {
421 			conclave_launcher_conclavestatus_s *status = NULL;
422 			status = conclave_launcher_conclavecontrol_stop__result_get_success(&result);
423 			if (status != NULL) {
424 				exclaves_debug_printf(show_test_output,
425 				    "%s:%d conclave stop success: status %u\n",
426 				    __func__, __LINE__, *status);
427 			        return;
428 			}
429 
430 			conclave_launcher_conclavelauncherfailure_s *failure = NULL;
431 			failure = conclave_launcher_conclavecontrol_stop__result_get_failure(&result);
432 			assert3p(failure, !=, NULL);
433 			exclaves_debug_printf(show_errors,
434 			    "%s:%d conclave stop failure: failure %u\n",
435 			    __func__, __LINE__, *failure);
436 		});
437 		/* END IGNORE CODESTYLE */
438 
439 		if (tb_result != TB_ERROR_SUCCESS) {
440 			exclaves_debug_printf(show_errors,
441 			    "%s:%d conclave stop failure: tightbeam error %u\n",
442 			    __func__, __LINE__, tb_result);
443 		}
444 		break;
445 	}
446 	case 4: {         /* debug info */
447 		assert(conclave_context != NULL);
448 
449 		/* BEGIN IGNORE CODESTYLE */
450 		tb_result = conclave_launcher_conclavedebug_debuginfo(
451 		    &conclave_context->conclave_debug,
452 		    ^(conclave_launcher_conclavedebug_debuginfo__result_s result) {
453 			conclave_launcher_conclavedebuginfo_s *debuginfo = NULL;
454 			debuginfo = conclave_launcher_conclavedebug_debuginfo__result_get_success(&result);
455 			if (debuginfo != NULL) {
456 				uuid_string_t uuid_string;
457 				uuid_unparse(debuginfo->conclaveuuid, uuid_string);
458 				exclaves_debug_printf(show_test_output,
459 				    "%s:%d conclave debuginfo success: result %s\n",
460 				    __func__, __LINE__, uuid_string);
461 			        return;
462 			}
463 
464 			conclave_launcher_conclavelauncherfailure_s *failure = NULL;
465 			failure = conclave_launcher_conclavedebug_debuginfo__result_get_failure(&result);
466 			assert3p(failure, !=, NULL);
467 			exclaves_debug_printf(show_errors,
468 			    "%s:%d conclave debuginfo failure: failure %u\n",
469 			    __func__, __LINE__, *failure);
470 		});
471 		/* END IGNORE CODESTYLE */
472 
473 		if (tb_result != TB_ERROR_SUCCESS) {
474 			exclaves_debug_printf(show_errors,
475 			    "%s:%d conclave debug info failure: tightbeam error %u\n",
476 			    __func__, __LINE__, tb_result);
477 		}
478 		break;
479 	}
480 	}
481 	lck_mtx_unlock(&exclaves_conclave_lock);
482 	*out = tb_result == TB_ERROR_SUCCESS ? 1 : 0;
483 	return tb_result == TB_ERROR_SUCCESS ? KERN_SUCCESS : KERN_FAILURE;
484 }
485 
486 SYSCTL_TEST_REGISTER(exclaves_hello_conclaves_test,
487     exclaves_hello_conclaves_test);
488 
489 #endif /* DEVELOPMENT || DEBUG */
490 
491 #endif /* CONFIG_EXCLAVES */
492