xref: /xnu-10063.121.3/bsd/kern/code_signing/txm.c (revision 2c2f96dc2b9a4408a43d3150ae9c105355ca3daa)
1 /*
2  * Copyright (c) 2022 Apple Computer, Inc. All rights reserved.
3  *
4  * @APPLE_LICENSE_HEADER_START@
5  *
6  * The contents of this file constitute Original Code as defined in and
7  * are subject to the Apple Public Source License Version 1.1 (the
8  * "License").  You may not use this file except in compliance with the
9  * License.  Please obtain a copy of the License at
10  * http://www.apple.com/publicsource and read it before using this file.
11  *
12  * This Original Code and all software distributed under the License are
13  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
17  * License for the specific language governing rights and limitations
18  * under the License.
19  *
20  * @APPLE_LICENSE_HEADER_END@
21  */
22 
23 #include <stdarg.h>
24 #include <stdatomic.h>
25 #include <os/overflow.h>
26 #include <machine/atomic.h>
27 #include <mach/vm_param.h>
28 #include <mach/vm_map.h>
29 #include <mach/shared_region.h>
30 #include <vm/vm_kern.h>
31 #include <kern/zalloc.h>
32 #include <kern/kalloc.h>
33 #include <kern/assert.h>
34 #include <kern/locks.h>
35 #include <kern/recount.h>
36 #include <kern/sched_prim.h>
37 #include <kern/lock_rw.h>
38 #include <libkern/libkern.h>
39 #include <libkern/section_keywords.h>
40 #include <libkern/coretrust/coretrust.h>
41 #include <libkern/amfi/amfi.h>
42 #include <pexpert/pexpert.h>
43 #include <sys/vm.h>
44 #include <sys/proc.h>
45 #include <sys/codesign.h>
46 #include <sys/code_signing.h>
47 #include <uuid/uuid.h>
48 #include <IOKit/IOBSD.h>
49 
50 #if CONFIG_SPTM
51 /*
52  * The TrustedExecutionMonitor environment works in tandem with the SPTM to provide code
53  * signing and memory isolation enforcement for data structures critical to ensuring that
54  * all code executed on the system is authorized to do so.
55  *
56  * Unless the data is managed by TXM itself, XNU needs to page-align everything, make the
57  * relevant type transfer, and then reference the memory as read-only.
58  *
59  * TXM enforces concurrency on its side, but through the use of try-locks. Upon a failure
60  * in acquiring the lock, TXM will panic. As a result, in order to ensure single-threaded
61  * behavior, the kernel also has to take some locks on its side befor calling into TXM.
62  */
63 #include <sys/trusted_execution_monitor.h>
64 #include <pexpert/arm64/board_config.h>
65 
66 /* Lock group used for all locks within the kernel for TXM */
67 LCK_GRP_DECLARE(txm_lck_grp, "txm_code_signing_lck_grp");
68 
69 #pragma mark Utilities
70 
71 /* Number of thread stacks is known at build-time */
72 #define NUM_TXM_THREAD_STACKS (MAX_CPUS)
73 txm_thread_stack_t thread_stacks[NUM_TXM_THREAD_STACKS] = {0};
74 
75 /* Singly-linked-list head for thread stacks */
76 SLIST_HEAD(thread_stack_head, _txm_thread_stack) thread_stacks_head =
77     SLIST_HEAD_INITIALIZER(thread_stacks_head);
78 
79 static decl_lck_mtx_data(, thread_stacks_lock);
80 static void *thread_stack_event = NULL;
81 
82 static void
setup_thread_stacks(void)83 setup_thread_stacks(void)
84 {
85 	extern const sptm_bootstrap_args_xnu_t *SPTMArgs;
86 	txm_thread_stack_t *thread_stack = NULL;
87 
88 	/* Initialize each thread stack and add it to the list */
89 	for (uint32_t i = 0; i < NUM_TXM_THREAD_STACKS; i++) {
90 		thread_stack = &thread_stacks[i];
91 
92 		/* Acquire the thread stack virtual mapping */
93 		thread_stack->thread_stack_papt = SPTMArgs->txm_thread_stacks[i];
94 
95 		/* Acquire the thread stack physical page */
96 		thread_stack->thread_stack_phys = (uintptr_t)kvtophys_nofail(
97 			thread_stack->thread_stack_papt);
98 
99 		/* Resolve the pointer to the thread stack data */
100 		thread_stack->thread_stack_data =
101 		    (TXMThreadStack_t*)(thread_stack->thread_stack_papt + (PAGE_SIZE - 1024));
102 
103 		/* Add thread stack to the list head */
104 		SLIST_INSERT_HEAD(&thread_stacks_head, thread_stack, link);
105 	}
106 
107 	/* Initialize the thread stacks lock */
108 	lck_mtx_init(&thread_stacks_lock, &txm_lck_grp, 0);
109 }
110 
111 static txm_thread_stack_t*
acquire_thread_stack(void)112 acquire_thread_stack(void)
113 {
114 	txm_thread_stack_t *thread_stack = NULL;
115 
116 	/* Lock the thread stack list */
117 	lck_mtx_lock(&thread_stacks_lock);
118 
119 	while (SLIST_EMPTY(&thread_stacks_head) == true) {
120 		lck_mtx_sleep(
121 			&thread_stacks_lock,
122 			LCK_SLEEP_DEFAULT,
123 			&thread_stack_event,
124 			THREAD_UNINT);
125 	}
126 
127 	if (SLIST_EMPTY(&thread_stacks_head) == true) {
128 		panic("unable to acquire a thread stack for TXM");
129 	}
130 
131 	/* Use the first available thread stack */
132 	thread_stack = SLIST_FIRST(&thread_stacks_head);
133 
134 	/* Remove the thread stack from the list */
135 	SLIST_REMOVE_HEAD(&thread_stacks_head, link);
136 
137 	/* Unlock the thread stack list */
138 	lck_mtx_unlock(&thread_stacks_lock);
139 
140 	/* Associate the thread stack with the current thread */
141 	thread_associate_txm_thread_stack(thread_stack->thread_stack_phys);
142 
143 	return thread_stack;
144 }
145 
146 static void
release_thread_stack(txm_thread_stack_t * thread_stack)147 release_thread_stack(
148 	txm_thread_stack_t* thread_stack)
149 {
150 	/* Remove the TXM thread stack association with the current thread */
151 	thread_disassociate_txm_thread_stack(thread_stack->thread_stack_phys);
152 
153 	/* Lock the thread stack list */
154 	lck_mtx_lock(&thread_stacks_lock);
155 
156 	/* Add the thread stack at the list head */
157 	SLIST_INSERT_HEAD(&thread_stacks_head, thread_stack, link);
158 
159 	/* Unlock the thread stack list */
160 	lck_mtx_unlock(&thread_stacks_lock);
161 
162 	/* Wake up any threads waiting to acquire a thread stack */
163 	thread_wakeup(&thread_stack_event);
164 }
165 
166 static kern_return_t
txm_parse_return(TXMReturn_t txm_ret)167 txm_parse_return(
168 	TXMReturn_t txm_ret)
169 {
170 	switch (txm_ret.returnCode) {
171 	case kTXMSuccess:
172 		return KERN_SUCCESS;
173 
174 	case kTXMReturnOutOfMemory:
175 		return KERN_RESOURCE_SHORTAGE;
176 
177 	case kTXMReturnNotFound:
178 		return KERN_NOT_FOUND;
179 
180 	default:
181 		return KERN_FAILURE;
182 	}
183 }
184 
185 static void
txm_print_return(TXMKernelSelector_t selector,TXMReturn_t txm_ret)186 txm_print_return(
187 	TXMKernelSelector_t selector,
188 	TXMReturn_t txm_ret)
189 {
190 	if (txm_ret.returnCode == kTXMSuccess) {
191 		return;
192 	} else if (txm_ret.returnCode == kTXMReturnTrustCache) {
193 		printf("TXM [Error]: TrustCache: selector: %u | 0x%02X | 0x%02X | %u\n",
194 		    selector, txm_ret.tcRet.component, txm_ret.tcRet.error, txm_ret.tcRet.uniqueError);
195 	} else if (txm_ret.returnCode == kTXMReturnCodeSignature) {
196 		printf("TXM [Error]: CodeSignature: selector: %u | 0x%02X | 0x%02X | %u\n",
197 		    selector, txm_ret.csRet.component, txm_ret.csRet.error, txm_ret.csRet.uniqueError);
198 	} else if (txm_ret.returnCode == kTXMReturnCodeErrno) {
199 		printf("TXM [Error]: Errno: selector: %u | %d\n",
200 		    selector, txm_ret.errnoRet);
201 	} else {
202 		printf("TXM [Error]: selector: %u | %u\n",
203 		    selector, txm_ret.returnCode);
204 	}
205 }
206 
207 #pragma mark Page Allocation
208 
209 static void
txm_add_page(void)210 txm_add_page(void)
211 {
212 	txm_call_t txm_call = {
213 		.selector = kTXMKernelSelectorAddFreeListPage,
214 		.failure_fatal = true,
215 		.num_input_args = 1
216 	};
217 
218 	/* Allocate a page from the VM -- transfers page to TXM internally */
219 	vm_map_address_t phys_addr = pmap_txm_allocate_page();
220 
221 	/* Add this page to the TXM free list */
222 	txm_kernel_call(&txm_call, phys_addr);
223 }
224 
225 #pragma mark Calls
226 
227 static void
txm_kernel_call_registers_setup(txm_call_t * parameters,sptm_call_regs_t * registers,va_list args)228 txm_kernel_call_registers_setup(
229 	txm_call_t *parameters,
230 	sptm_call_regs_t *registers,
231 	va_list args)
232 {
233 	/*
234 	 * We are only ever allowed a maximum of 7 arguments for calling into TXM.
235 	 * This is because the SPTM dispatch only sets up registers x0-x7 for the
236 	 * call, and x0 is always reserved for passing in a thread stack for TXM
237 	 * to operate on.
238 	 */
239 
240 	switch (parameters->num_input_args) {
241 	case 7:
242 		registers->x1 = va_arg(args, uintptr_t);
243 		registers->x2 = va_arg(args, uintptr_t);
244 		registers->x3 = va_arg(args, uintptr_t);
245 		registers->x4 = va_arg(args, uintptr_t);
246 		registers->x5 = va_arg(args, uintptr_t);
247 		registers->x6 = va_arg(args, uintptr_t);
248 		registers->x7 = va_arg(args, uintptr_t);
249 		break;
250 
251 	case 6:
252 		registers->x1 = va_arg(args, uintptr_t);
253 		registers->x2 = va_arg(args, uintptr_t);
254 		registers->x3 = va_arg(args, uintptr_t);
255 		registers->x4 = va_arg(args, uintptr_t);
256 		registers->x5 = va_arg(args, uintptr_t);
257 		registers->x6 = va_arg(args, uintptr_t);
258 		break;
259 
260 	case 5:
261 		registers->x1 = va_arg(args, uintptr_t);
262 		registers->x2 = va_arg(args, uintptr_t);
263 		registers->x3 = va_arg(args, uintptr_t);
264 		registers->x4 = va_arg(args, uintptr_t);
265 		registers->x5 = va_arg(args, uintptr_t);
266 		break;
267 
268 	case 4:
269 		registers->x1 = va_arg(args, uintptr_t);
270 		registers->x2 = va_arg(args, uintptr_t);
271 		registers->x3 = va_arg(args, uintptr_t);
272 		registers->x4 = va_arg(args, uintptr_t);
273 		break;
274 
275 	case 3:
276 		registers->x1 = va_arg(args, uintptr_t);
277 		registers->x2 = va_arg(args, uintptr_t);
278 		registers->x3 = va_arg(args, uintptr_t);
279 		break;
280 
281 	case 2:
282 		registers->x1 = va_arg(args, uintptr_t);
283 		registers->x2 = va_arg(args, uintptr_t);
284 		break;
285 
286 	case 1:
287 		registers->x1 = va_arg(args, uintptr_t);
288 		break;
289 
290 	case 0:
291 		break;
292 
293 	default:
294 		panic("invalid number of arguments to TXM: selector: %u | %u",
295 		    parameters->selector, parameters->num_input_args);
296 	}
297 }
298 
299 static TXMReturn_t
txm_kernel_call_internal(txm_call_t * parameters,va_list args)300 txm_kernel_call_internal(
301 	txm_call_t *parameters,
302 	va_list args)
303 {
304 	TXMReturn_t txm_ret = (TXMReturn_t){.returnCode = kTXMReturnGeneric};
305 	sptm_call_regs_t txm_registers = {0};
306 	txm_thread_stack_t *thread_stack = NULL;
307 	const TXMThreadStack_t *thread_stack_data = NULL;
308 	const TXMSharedContextData_t *shared_context_data = NULL;
309 
310 	/* Obtain a stack for this call */
311 	thread_stack = acquire_thread_stack();
312 	thread_stack_data = thread_stack->thread_stack_data;
313 	shared_context_data = &thread_stack_data->sharedData;
314 
315 	/* Setup argument registers */
316 	txm_registers.x0 = thread_stack->thread_stack_phys;
317 	txm_kernel_call_registers_setup(parameters, &txm_registers, args);
318 
319 	/* Track resource usage */
320 	recount_enter_secure();
321 
322 	/* Call into TXM */
323 	txm_enter(parameters->selector, &txm_registers);
324 
325 	recount_leave_secure();
326 
327 	txm_ret = (TXMReturn_t){.rawValue = shared_context_data->txmReturnCode};
328 	parameters->txm_ret = txm_ret;
329 
330 	if (parameters->txm_ret.returnCode == kTXMSuccess) {
331 		parameters->num_return_words = shared_context_data->txmNumReturnWords;
332 		if (parameters->num_return_words > kTXMStackReturnWords) {
333 			panic("received excessive return words from TXM: selector: %u | %llu",
334 			    parameters->selector, parameters->num_return_words);
335 		}
336 
337 		for (uint64_t i = 0; i < parameters->num_return_words; i++) {
338 			parameters->return_words[i] = shared_context_data->txmReturnWords[i];
339 		}
340 	}
341 
342 	/* Release the thread stack as it is no longer needed */
343 	release_thread_stack(thread_stack);
344 	thread_stack_data = NULL;
345 	shared_context_data = NULL;
346 
347 	return txm_ret;
348 }
349 
350 kern_return_t
txm_kernel_call(txm_call_t * parameters,...)351 txm_kernel_call(
352 	txm_call_t *parameters, ...)
353 {
354 	TXMReturn_t txm_ret = (TXMReturn_t){.returnCode = kTXMReturnGeneric};
355 	kern_return_t ret = KERN_DENIED;
356 	va_list args;
357 
358 	/* Start the variadic arguments list */
359 	va_start(args, parameters);
360 
361 	do {
362 		txm_ret = txm_kernel_call_internal(parameters, args);
363 		if (txm_ret.returnCode == kTXMReturnOutOfMemory) {
364 			if (parameters->selector == kTXMKernelSelectorAddFreeListPage) {
365 				panic("received out-of-memory error when adding a free page to TXM");
366 			}
367 			txm_add_page();
368 		}
369 	} while (txm_ret.returnCode == kTXMReturnOutOfMemory);
370 
371 	/* Clean up the variadic arguments list */
372 	va_end(args);
373 
374 	/* Print all TXM logs from the log buffer */
375 	if (parameters->skip_logs == false) {
376 		txm_print_logs();
377 	}
378 
379 	/* Print the return code from TXM -- only prints for an error */
380 	if (parameters->failure_silent != true) {
381 		if (parameters->failure_code_silent != txm_ret.returnCode) {
382 			txm_print_return(parameters->selector, txm_ret);
383 		}
384 	}
385 
386 	/*
387 	 * To ease the process of calling into TXM, and to also reduce the number of
388 	 * lines of code for each call site, the txm_call_t offers some properties
389 	 * we can enforce over here. Go through these, and panic in case they aren't
390 	 * honored.
391 	 *
392 	 * NOTE: We check for "<" instead of "!=" for the number of return words we
393 	 * get back from TXM since this helps in forward development. If the kernel
394 	 * and TXM are proceeding at different project cadences, we do not want to
395 	 * gate adding more return words from TXM on the kernel first adopting the
396 	 * new number of return words.
397 	 */
398 	ret = txm_parse_return(txm_ret);
399 
400 	if (parameters->failure_fatal && (ret != KERN_SUCCESS)) {
401 		panic("received fatal error for a selector from TXM: selector: %u | 0x%0llX",
402 		    parameters->selector, txm_ret.rawValue);
403 	} else if (parameters->num_return_words < parameters->num_output_args) {
404 		/* Only panic if return was a success */
405 		if (ret == KERN_SUCCESS) {
406 			panic("received fewer than expected return words from TXM: selector: %u | %llu",
407 			    parameters->selector, parameters->num_return_words);
408 		}
409 	}
410 
411 	return ret;
412 }
413 
414 void
txm_transfer_region(vm_address_t addr,vm_size_t size)415 txm_transfer_region(
416 	vm_address_t addr,
417 	vm_size_t size)
418 {
419 	vm_address_t addr_end = 0;
420 	vm_size_t size_aligned = round_page(size);
421 
422 	if ((addr & PAGE_MASK) != 0) {
423 		panic("attempted to transfer non-page-aligned memory to TXM: %p", (void*)addr);
424 	} else if (os_add_overflow(addr, size_aligned, &addr_end)) {
425 		panic("overflow on range to be transferred to TXM: %p | %lu",
426 		    (void*)addr, size);
427 	}
428 
429 	/* Make the memory read-only first (transfer will panic otherwise) */
430 	vm_protect(kernel_map, addr, size_aligned, false, VM_PROT_READ);
431 
432 	/* Transfer each physical page to be TXM_DEFAULT */
433 	for (vm_address_t page = addr; page < addr_end; page += PAGE_SIZE) {
434 		pmap_txm_transfer_page(page);
435 	}
436 }
437 
438 void
txm_reclaim_region(vm_address_t addr,vm_size_t size)439 txm_reclaim_region(
440 	vm_address_t addr,
441 	vm_size_t size)
442 {
443 	vm_address_t addr_end = 0;
444 	vm_size_t size_aligned = round_page(size);
445 
446 	if ((addr & PAGE_MASK) != 0) {
447 		panic("attempted to reclaim non-page-aligned memory from TXM: %p", (void*)addr);
448 	} else if (os_add_overflow(addr, size_aligned, &addr_end)) {
449 		panic("overflow on range to be reclaimed from TXM: %p | %lu",
450 		    (void*)addr, size);
451 	}
452 
453 	/*
454 	 * We can only reclaim once TXM has transferred the memory range back to the
455 	 * kernel. Hence, we simply try and switch permissions to read-write. If TXM
456 	 * hasn't transferred pages, this then should panic.
457 	 */
458 	vm_protect(kernel_map, addr, size_aligned, false, VM_PROT_READ | VM_PROT_WRITE);
459 }
460 
461 static SECURITY_READ_ONLY_LATE(const char*) txm_log_page = NULL;
462 static SECURITY_READ_ONLY_LATE(const uint32_t*) txm_log_head = NULL;
463 static SECURITY_READ_ONLY_LATE(const uint32_t*) txm_log_sync = NULL;
464 
465 static decl_lck_mtx_data(, log_lock);
466 static uint32_t log_head = 0;
467 
468 void
txm_print_logs(void)469 txm_print_logs(void)
470 {
471 	uint32_t start_index = 0;
472 	uint32_t end_index = 0;
473 
474 	/*
475 	 * The design here is very simple. TXM keeps adding slots to its circular buffer
476 	 * and the kernel attempts to read each one and print it, maintaining its own head
477 	 * for the log.
478 	 *
479 	 * This design is by nature lazy. TXM doesn't know or care if the kernel has gone
480 	 * through and printed any of the logs, so it'll just keep writing into its buffer
481 	 * and then circle around when it becomes full.
482 	 *
483 	 * This is fine most of the time since there are a decent amount of slots in the
484 	 * log buffer. We mostly have an issue when TXM is adding so many logs so quickly
485 	 * such that it wraps around and starts overwriting logs which haven't been seen
486 	 * by the kernel. If this were to happen, TXM's log head may circle around the
487 	 * head maintained by the kernel, causing a lot of logs to be missed, since the
488 	 * kernel only attempts the number of logs in-between the two heads.
489 	 *
490 	 * The fix for that is complicated, and until we see an actual impact, we're going
491 	 * to keep the simpler design in place.
492 	 */
493 
494 	/* Return if the logging hasn't been setup yet */
495 	if (txm_log_sync == NULL) {
496 		return;
497 	}
498 
499 	/*
500 	 * Holding the log lock and printing can cause lots of issues since printing can
501 	 * be rather slow. While we make it a point to keep the logging buffer quiet, some
502 	 * actions (such as loading trust caches) are still very chatty.
503 	 *
504 	 * As a result, we optimize this routine to ensure that the lock itself isn't held
505 	 * for very long. All we need to do within the critical section is calculate the
506 	 * starting and ending index of the log buffer. The actual printing doesn't need
507 	 * to be done with the lock held.
508 	 */
509 	lck_mtx_lock(&log_lock);
510 
511 	start_index = log_head;
512 	end_index = os_atomic_load(txm_log_head, relaxed) % kTXMLogSlots;
513 
514 	/* Update the log head with the new index */
515 	log_head = end_index;
516 
517 	/* Release the log lock */
518 	lck_mtx_unlock(&log_lock);
519 
520 	if (start_index != end_index) {
521 		/* Use load acquire here to sync up with all writes to the buffer */
522 		os_atomic_load(txm_log_sync, acquire);
523 
524 		while (start_index != end_index) {
525 			const char *slot = txm_log_page + (start_index * kTXMLogSlotSize);
526 
527 			/* We add newlines after each log statement since TXM does not */
528 			printf("%s\n", slot);
529 
530 			start_index = (start_index + 1) % kTXMLogSlots;
531 		}
532 	}
533 }
534 
535 #pragma mark Initialization
536 
537 SECURITY_READ_ONLY_LATE(const TXMReadOnlyData_t*) txm_ro_data = NULL;
538 SECURITY_READ_ONLY_LATE(const TXMStatistics_t*) txm_stats = NULL;
539 SECURITY_READ_ONLY_LATE(const CSConfig_t*) txm_cs_config = NULL;
540 
541 SECURITY_READ_ONLY_LATE(bool*) developer_mode_enabled = NULL;
542 static SECURITY_READ_ONLY_LATE(bool) code_signing_enabled = true;
543 static SECURITY_READ_ONLY_LATE(uint32_t) managed_signature_size = 0;
544 
545 static decl_lck_mtx_data(, compilation_service_lock);
546 static decl_lck_mtx_data(, unregister_sync_lock);
547 
548 static void
get_logging_info(void)549 get_logging_info(void)
550 {
551 	txm_call_t txm_call = {
552 		.selector = kTXMKernelSelectorGetLogInfo,
553 		.failure_fatal = true,
554 		.num_output_args = 3
555 	};
556 	txm_kernel_call(&txm_call);
557 
558 	txm_log_page = (const char*)txm_call.return_words[0];
559 	txm_log_head = (const uint32_t*)txm_call.return_words[1];
560 	txm_log_sync = (const uint32_t*)txm_call.return_words[2];
561 }
562 
563 static void
get_code_signing_info(void)564 get_code_signing_info(void)
565 {
566 	txm_call_t txm_call = {
567 		.selector = kTXMKernelSelectorGetCodeSigningInfo,
568 		.failure_fatal = true,
569 		.num_output_args = 6
570 	};
571 	txm_kernel_call(&txm_call);
572 
573 	/*
574 	 * Not using txm_call.return_words[0] for now. This was previously the
575 	 * code_signing_enabled field, but we've since switched to acquiring that
576 	 * value from TXM's read-only data.
577 	 *
578 	 * Not using txm_call.return_words[4] for now. This was previously the
579 	 * txm_cs_config field, but we've since switched to acquiring that value
580 	 * from TXM's read-only data.
581 	 */
582 
583 	developer_mode_enabled = (bool*)txm_call.return_words[1];
584 	txm_stats = (TXMStatistics_t*)txm_call.return_words[2];
585 	managed_signature_size = (uint32_t)txm_call.return_words[3];
586 	txm_ro_data = (TXMReadOnlyData_t*)txm_call.return_words[5];
587 
588 	/* Set code_signing_disabled based on read-only data */
589 	code_signing_enabled = txm_ro_data->codeSigningDisabled == false;
590 
591 	/* Set txm_cs_config based on read-only data */
592 	txm_cs_config = &txm_ro_data->CSConfiguration;
593 }
594 
595 static void
set_shared_region_base_address(void)596 set_shared_region_base_address(void)
597 {
598 	txm_call_t txm_call = {
599 		.selector = kTXMKernelSelectorSetSharedRegionBaseAddress,
600 		.failure_fatal = true,
601 		.num_input_args = 2,
602 	};
603 
604 	txm_kernel_call(&txm_call,
605 	    SHARED_REGION_BASE,
606 	    SHARED_REGION_SIZE);
607 }
608 
609 void
code_signing_init(void)610 code_signing_init(void)
611 {
612 	/* Setup the thread stacks used by TXM */
613 	setup_thread_stacks();
614 
615 	/* Setup the logging lock */
616 	lck_mtx_init(&log_lock, &txm_lck_grp, 0);
617 
618 	/* Setup TXM logging information */
619 	get_logging_info();
620 
621 	/* Setup code signing configuration */
622 	get_code_signing_info();
623 
624 	/* Setup all the other locks we need */
625 	lck_mtx_init(&compilation_service_lock, &txm_lck_grp, 0);
626 	lck_mtx_init(&unregister_sync_lock, &txm_lck_grp, 0);
627 
628 	/*
629 	 * We need to let TXM know what the shared region base address is going
630 	 * to be for this boot.
631 	 */
632 	set_shared_region_base_address();
633 
634 	/* Require signed code when monitor is enabled */
635 	if (code_signing_enabled == true) {
636 		cs_debug_fail_on_unsigned_code = 1;
637 	}
638 }
639 
640 void
txm_enter_lockdown_mode(void)641 txm_enter_lockdown_mode(void)
642 {
643 #if kTXMKernelAPIVersion >= 3
644 	txm_call_t txm_call = {
645 		.selector = kTXMKernelSelectorEnterLockdownMode,
646 		.failure_fatal = true,
647 	};
648 
649 	txm_kernel_call(&txm_call);
650 #endif
651 }
652 
653 #pragma mark Developer Mode
654 
655 void
txm_toggle_developer_mode(bool state)656 txm_toggle_developer_mode(bool state)
657 {
658 	txm_call_t txm_call = {
659 		.selector = kTXMKernelSelectorDeveloperModeToggle,
660 		.failure_fatal = true,
661 		.num_input_args = 1
662 	};
663 
664 	txm_kernel_call(&txm_call, state);
665 }
666 
667 #pragma mark Code Signing and Provisioning Profiles
668 
669 bool
txm_code_signing_enabled(void)670 txm_code_signing_enabled(void)
671 {
672 	return code_signing_enabled;
673 }
674 
675 vm_size_t
txm_managed_code_signature_size(void)676 txm_managed_code_signature_size(void)
677 {
678 	return managed_signature_size;
679 }
680 
681 kern_return_t
txm_register_provisioning_profile(const void * profile_blob,const size_t profile_blob_size,void ** profile_obj)682 txm_register_provisioning_profile(
683 	const void *profile_blob,
684 	const size_t profile_blob_size,
685 	void **profile_obj)
686 {
687 	txm_call_t txm_call = {
688 		.selector = kTXMKernelSelectorRegisterProvisioningProfile,
689 		.num_input_args = 2,
690 		.num_output_args = 1
691 	};
692 	vm_address_t payload_addr = 0;
693 	kern_return_t ret = KERN_DENIED;
694 
695 	/* We need to allocate page-wise in order to transfer the range to TXM */
696 	ret = kmem_alloc(kernel_map, &payload_addr, profile_blob_size,
697 	    KMA_KOBJECT | KMA_DATA, VM_KERN_MEMORY_SECURITY);
698 	if (ret != KERN_SUCCESS) {
699 		printf("unable to allocate memory for profile payload: %d\n", ret);
700 		goto exit;
701 	}
702 
703 	/* Copy the contents into the allocation */
704 	memcpy((void*)payload_addr, profile_blob, profile_blob_size);
705 
706 	/* Transfer the memory range to TXM */
707 	txm_transfer_region(payload_addr, profile_blob_size);
708 
709 	ret = txm_kernel_call(&txm_call, payload_addr, profile_blob_size);
710 	if (ret == KERN_SUCCESS) {
711 		*profile_obj = (void*)txm_call.return_words[0];
712 	}
713 
714 exit:
715 	if ((ret != KERN_SUCCESS) && (payload_addr != 0)) {
716 		/* Reclaim this memory range */
717 		txm_reclaim_region(payload_addr, profile_blob_size);
718 
719 		/* Free the memory range */
720 		kmem_free(kernel_map, payload_addr, profile_blob_size);
721 		payload_addr = 0;
722 	}
723 
724 	return ret;
725 }
726 
727 kern_return_t
txm_unregister_provisioning_profile(void * profile_obj)728 txm_unregister_provisioning_profile(
729 	void *profile_obj)
730 {
731 	txm_call_t txm_call = {
732 		.selector = kTXMKernelSelectorUnregisterProvisioningProfile,
733 		.num_input_args = 1,
734 		.num_output_args = 2
735 	};
736 	vm_address_t profile_addr = 0;
737 	vm_size_t profile_size = 0;
738 	kern_return_t ret = KERN_DENIED;
739 
740 	ret = txm_kernel_call(&txm_call, profile_obj);
741 	if (ret != KERN_SUCCESS) {
742 		return ret;
743 	}
744 
745 	profile_addr = txm_call.return_words[0];
746 	profile_size = txm_call.return_words[1];
747 
748 	/* Reclaim this memory range */
749 	txm_reclaim_region(profile_addr, profile_size);
750 
751 	/* Free the memory range */
752 	kmem_free(kernel_map, profile_addr, profile_size);
753 
754 	return KERN_SUCCESS;
755 }
756 
757 kern_return_t
txm_associate_provisioning_profile(void * sig_obj,void * profile_obj)758 txm_associate_provisioning_profile(
759 	void *sig_obj,
760 	void *profile_obj)
761 {
762 	txm_call_t txm_call = {
763 		.selector = kTXMKernelSelectorAssociateProvisioningProfile,
764 		.num_input_args = 2,
765 	};
766 
767 	return txm_kernel_call(&txm_call, sig_obj, profile_obj);
768 }
769 
770 kern_return_t
txm_disassociate_provisioning_profile(void * sig_obj)771 txm_disassociate_provisioning_profile(
772 	void *sig_obj)
773 {
774 	txm_call_t txm_call = {
775 		.selector = kTXMKernelSelectorDisassociateProvisioningProfile,
776 		.num_input_args = 1,
777 	};
778 
779 	/*
780 	 * Take the unregistration sync lock.
781 	 * For more information: rdar://99205627.
782 	 */
783 	lck_mtx_lock(&unregister_sync_lock);
784 
785 	/* Disassociate the profile from the signature */
786 	kern_return_t ret = txm_kernel_call(&txm_call, sig_obj);
787 
788 	/* Release the unregistration sync lock */
789 	lck_mtx_unlock(&unregister_sync_lock);
790 
791 	return ret;
792 }
793 
794 void
txm_set_compilation_service_cdhash(const uint8_t cdhash[CS_CDHASH_LEN])795 txm_set_compilation_service_cdhash(
796 	const uint8_t cdhash[CS_CDHASH_LEN])
797 {
798 	txm_call_t txm_call = {
799 		.selector = kTXMKernelSelectorAuthorizeCompilationServiceCDHash,
800 		.num_input_args = 1,
801 	};
802 
803 	lck_mtx_lock(&compilation_service_lock);
804 	txm_kernel_call(&txm_call, cdhash);
805 	lck_mtx_unlock(&compilation_service_lock);
806 }
807 
808 bool
txm_match_compilation_service_cdhash(const uint8_t cdhash[CS_CDHASH_LEN])809 txm_match_compilation_service_cdhash(
810 	const uint8_t cdhash[CS_CDHASH_LEN])
811 {
812 	txm_call_t txm_call = {
813 		.selector = kTXMKernelSelectorMatchCompilationServiceCDHash,
814 		.failure_silent = true,
815 		.num_input_args = 1,
816 		.num_output_args = 1,
817 	};
818 	kern_return_t ret = KERN_DENIED;
819 
820 	/* Be safe and take the lock (avoid thread collisions) */
821 	lck_mtx_lock(&compilation_service_lock);
822 	ret = txm_kernel_call(&txm_call, cdhash);
823 	lck_mtx_unlock(&compilation_service_lock);
824 
825 	if (ret == KERN_SUCCESS) {
826 		return true;
827 	}
828 	return false;
829 }
830 
831 void
txm_set_local_signing_public_key(const uint8_t public_key[XNU_LOCAL_SIGNING_KEY_SIZE])832 txm_set_local_signing_public_key(
833 	const uint8_t public_key[XNU_LOCAL_SIGNING_KEY_SIZE])
834 {
835 	txm_call_t txm_call = {
836 		.selector = kTXMKernelSelectorSetLocalSigningPublicKey,
837 		.num_input_args = 1,
838 	};
839 
840 	txm_kernel_call(&txm_call, public_key);
841 }
842 
843 uint8_t*
txm_get_local_signing_public_key(void)844 txm_get_local_signing_public_key(void)
845 {
846 	txm_call_t txm_call = {
847 		.selector = kTXMKernelSelectorGetLocalSigningPublicKey,
848 		.num_output_args = 1,
849 	};
850 	kern_return_t ret = KERN_DENIED;
851 
852 	ret = txm_kernel_call(&txm_call);
853 	if (ret != KERN_SUCCESS) {
854 		return NULL;
855 	}
856 
857 	return (uint8_t*)txm_call.return_words[0];
858 }
859 
860 void
txm_unrestrict_local_signing_cdhash(const uint8_t cdhash[CS_CDHASH_LEN])861 txm_unrestrict_local_signing_cdhash(
862 	const uint8_t cdhash[CS_CDHASH_LEN])
863 {
864 	txm_call_t txm_call = {
865 		.selector = kTXMKernelSelectorAuthorizeLocalSigningCDHash,
866 		.num_input_args = 1,
867 	};
868 
869 	txm_kernel_call(&txm_call, cdhash);
870 }
871 
872 kern_return_t
txm_register_code_signature(const vm_address_t signature_addr,const vm_size_t signature_size,const vm_offset_t code_directory_offset,const char * signature_path,void ** sig_obj,vm_address_t * txm_signature_addr)873 txm_register_code_signature(
874 	const vm_address_t signature_addr,
875 	const vm_size_t signature_size,
876 	const vm_offset_t code_directory_offset,
877 	const char *signature_path,
878 	void **sig_obj,
879 	vm_address_t *txm_signature_addr)
880 {
881 	txm_call_t txm_call = {
882 		.selector = kTXMKernelSelectorRegisterCodeSignature,
883 		.num_input_args = 3,
884 		.num_output_args = 2,
885 	};
886 	kern_return_t ret = KERN_DENIED;
887 
888 	/*
889 	 * TXM performs more exhaustive validation of the code signature and figures
890 	 * out the best code directory to use on its own. As a result, this offset here
891 	 * is not used.
892 	 */
893 	(void)code_directory_offset;
894 
895 	/*
896 	 * If the signature is large enough to not fit within TXM's managed signature
897 	 * size, then we need to transfer it over so it is owned by TXM.
898 	 */
899 	if (signature_size > txm_managed_code_signature_size()) {
900 		txm_transfer_region(signature_addr, signature_size);
901 	}
902 
903 	ret = txm_kernel_call(
904 		&txm_call,
905 		signature_addr,
906 		signature_size,
907 		signature_path);
908 
909 	if (ret != KERN_SUCCESS) {
910 		goto exit;
911 	}
912 
913 	*sig_obj = (void*)txm_call.return_words[0];
914 	*txm_signature_addr = txm_call.return_words[1];
915 
916 exit:
917 	if ((ret != KERN_SUCCESS) && (signature_size > txm_managed_code_signature_size())) {
918 		txm_reclaim_region(signature_addr, signature_size);
919 	}
920 
921 	return ret;
922 }
923 
924 kern_return_t
txm_unregister_code_signature(void * sig_obj)925 txm_unregister_code_signature(
926 	void *sig_obj)
927 {
928 	txm_call_t txm_call = {
929 		.selector = kTXMKernelSelectorUnregisterCodeSignature,
930 		.failure_fatal = true,
931 		.num_input_args = 1,
932 		.num_output_args = 2,
933 	};
934 	TXMCodeSignature_t *cs_obj = sig_obj;
935 	vm_address_t signature_addr = 0;
936 	vm_size_t signature_size = 0;
937 	bool txm_managed = false;
938 
939 	/* Check if the signature memory is TXM managed */
940 	txm_managed = cs_obj->sptmType != TXM_BULK_DATA;
941 
942 	/*
943 	 * Take the unregistration sync lock.
944 	 * For more information: rdar://99205627.
945 	 */
946 	lck_mtx_lock(&unregister_sync_lock);
947 
948 	/* Unregister the signature from TXM -- cannot fail */
949 	txm_kernel_call(&txm_call, sig_obj);
950 
951 	/* Release the unregistration sync lock */
952 	lck_mtx_unlock(&unregister_sync_lock);
953 
954 	signature_addr = txm_call.return_words[0];
955 	signature_size = txm_call.return_words[1];
956 
957 	/* Reclaim the memory range in case we need to */
958 	if (txm_managed == false) {
959 		txm_reclaim_region(signature_addr, signature_size);
960 	}
961 
962 	return KERN_SUCCESS;
963 }
964 
965 kern_return_t
txm_verify_code_signature(void * sig_obj)966 txm_verify_code_signature(
967 	void *sig_obj)
968 {
969 	txm_call_t txm_call = {
970 		.selector = kTXMKernelSelectorValidateCodeSignature,
971 		.num_input_args = 1,
972 	};
973 	kern_return_t ret = KERN_DENIED;
974 
975 	/*
976 	 * Verification of the code signature may perform a trust cache look up.
977 	 * In order to avoid any collisions with threads which may be loading a
978 	 * trust cache, we take a reader lock on the trust cache runtime.
979 	 */
980 
981 	lck_rw_lock_shared(&txm_trust_cache_lck);
982 	ret = txm_kernel_call(&txm_call, sig_obj);
983 	lck_rw_unlock_shared(&txm_trust_cache_lck);
984 
985 	return ret;
986 }
987 
988 kern_return_t
txm_reconstitute_code_signature(void * sig_obj,vm_address_t * unneeded_addr,vm_size_t * unneeded_size)989 txm_reconstitute_code_signature(
990 	void *sig_obj,
991 	vm_address_t *unneeded_addr,
992 	vm_size_t *unneeded_size)
993 {
994 	txm_call_t txm_call = {
995 		.selector = kTXMKernelSelectorReconstituteCodeSignature,
996 		.failure_fatal = true,
997 		.num_input_args = 1,
998 		.num_output_args = 2,
999 	};
1000 	vm_address_t return_addr = 0;
1001 	vm_size_t return_size = 0;
1002 
1003 	/* Reconstitute the code signature -- cannot fail */
1004 	txm_kernel_call(&txm_call, sig_obj);
1005 
1006 	return_addr = txm_call.return_words[0];
1007 	return_size = txm_call.return_words[1];
1008 
1009 	/* Reclaim the memory region if we need to */
1010 	if ((return_addr != 0) && (return_size != 0)) {
1011 		txm_reclaim_region(return_addr, return_size);
1012 	}
1013 
1014 	*unneeded_addr = return_addr;
1015 	*unneeded_size = return_size;
1016 
1017 	return KERN_SUCCESS;
1018 }
1019 
1020 #pragma mark Address Spaces
1021 
1022 kern_return_t
txm_register_address_space(pmap_t pmap,uint16_t addr_space_id,TXMAddressSpaceFlags_t flags)1023 txm_register_address_space(
1024 	pmap_t pmap,
1025 	uint16_t addr_space_id,
1026 	TXMAddressSpaceFlags_t flags)
1027 {
1028 	txm_call_t txm_call = {
1029 		.selector = kTXMKernelSelectorRegisterAddressSpace,
1030 		.failure_fatal = true,
1031 		.num_input_args = 2,
1032 		.num_output_args = 1,
1033 	};
1034 	TXMAddressSpace_t *txm_addr_space = NULL;
1035 
1036 	/* Register the address space -- cannot fail */
1037 	txm_kernel_call(&txm_call, addr_space_id, flags);
1038 
1039 	/* Set the address space object within the PMAP */
1040 	txm_addr_space = (TXMAddressSpace_t*)txm_call.return_words[0];
1041 	pmap_txm_set_addr_space(pmap, txm_addr_space);
1042 
1043 	return KERN_SUCCESS;
1044 }
1045 
1046 kern_return_t
txm_unregister_address_space(pmap_t pmap)1047 txm_unregister_address_space(
1048 	pmap_t pmap)
1049 {
1050 	txm_call_t txm_call = {
1051 		.selector = kTXMKernelSelectorUnregisterAddressSpace,
1052 		.failure_fatal = true,
1053 		.num_input_args = 1,
1054 	};
1055 	TXMAddressSpace_t *txm_addr_space = pmap_txm_addr_space(pmap);
1056 
1057 	/*
1058 	 * Take the unregistration sync lock.
1059 	 * For more information: rdar://99205627.
1060 	 */
1061 	lck_mtx_lock(&unregister_sync_lock);
1062 
1063 	/* Unregister the address space -- cannot fail */
1064 	txm_kernel_call(&txm_call, txm_addr_space);
1065 
1066 	/* Release the unregistration sync lock */
1067 	lck_mtx_unlock(&unregister_sync_lock);
1068 
1069 	/* Remove the address space from the pmap */
1070 	pmap_txm_set_addr_space(pmap, NULL);
1071 
1072 	return KERN_SUCCESS;
1073 }
1074 
1075 kern_return_t
txm_associate_code_signature(pmap_t pmap,void * sig_obj,const vm_address_t region_addr,const vm_size_t region_size,const vm_offset_t region_offset)1076 txm_associate_code_signature(
1077 	pmap_t pmap,
1078 	void *sig_obj,
1079 	const vm_address_t region_addr,
1080 	const vm_size_t region_size,
1081 	const vm_offset_t region_offset)
1082 {
1083 	txm_call_t txm_call = {
1084 		.selector = kTXMKernelSelectorAssociateCodeSignature,
1085 		.num_input_args = 5,
1086 	};
1087 	TXMAddressSpace_t *txm_addr_space = pmap_txm_addr_space(pmap);
1088 	kern_return_t ret = KERN_DENIED;
1089 
1090 	/*
1091 	 * Associating a code signature may require exclusive access to the TXM address
1092 	 * space lock within TXM.
1093 	 */
1094 	pmap_txm_acquire_exclusive_lock(pmap);
1095 
1096 	/*
1097 	 * If the address space in question is a nested address space, then all associations
1098 	 * need to go into the shared region base range. The VM layer is inconsistent with
1099 	 * how it makes associations with TXM vs. how it maps pages into the shared region.
1100 	 *
1101 	 * For TXM, the associations are made without taking the base range into account,
1102 	 * but when mappings are entered into the shared region, the base range is taken
1103 	 * into account. To normalize this, we add the base range address here.
1104 	 */
1105 	vm_address_t adjusted_region_addr = region_addr;
1106 	if (txm_addr_space->addrSpaceID.type == kTXMAddressSpaceIDTypeSharedRegion) {
1107 		adjusted_region_addr += SHARED_REGION_BASE;
1108 	}
1109 
1110 	/*
1111 	 * The VM tries a bunch of weird mappings within launchd for some platform code
1112 	 * which isn't mapped contiguously. These mappings don't succeed, but the failure
1113 	 * is fairly harmless since everything seems to work. However, since the call to
1114 	 * TXM fails, we make a series of logs. Hence, for launchd, we suppress failure
1115 	 * logs.
1116 	 */
1117 	if (txm_addr_space->addrSpaceID.type == kTXMAddressSpaceIDTypeAddressSpace) {
1118 		/* TXMTODO: Scope this to launchd better */
1119 		txm_call.failure_code_silent = kTXMReturnPlatformCodeMapping;
1120 	}
1121 
1122 	/* Check if the main region has been set on the address space */
1123 	bool main_region_set = txm_addr_space->mainRegion != NULL;
1124 	bool main_region_set_after = false;
1125 
1126 	ret = txm_kernel_call(
1127 		&txm_call,
1128 		txm_addr_space,
1129 		sig_obj,
1130 		adjusted_region_addr,
1131 		region_size,
1132 		region_offset);
1133 
1134 	/*
1135 	 * If the main region wasn't set on the address space before hand, but this new
1136 	 * call into TXM was successful and sets the main region, it means this signature
1137 	 * object is associated with the main region on the address space. With this, we
1138 	 * can now set the appropriate trust level on the PMAP.
1139 	 */
1140 	if (ret == KERN_SUCCESS) {
1141 		main_region_set_after = txm_addr_space->mainRegion != NULL;
1142 	}
1143 
1144 	/* Unlock the TXM address space lock */
1145 	pmap_txm_release_exclusive_lock(pmap);
1146 
1147 	/* Check if we should set the trust level on the PMAP */
1148 	if (!main_region_set && main_region_set_after) {
1149 		const TXMCodeSignature_t *cs_obj = sig_obj;
1150 		const SignatureValidation_t *sig = &cs_obj->sig;
1151 
1152 		/*
1153 		 * This is gross, as we're dereferencing into a private data structure type.
1154 		 * There are 2 ways to clean this up in the future:
1155 		 * 1. Import libCodeSignature, so we can use "codeSignatureGetTrustLevel".
1156 		 * 2. Cache the trust level on the address space within TXM and then use it.
1157 		 */
1158 		pmap_txm_set_trust_level(pmap, sig->trustLevel);
1159 	}
1160 
1161 	return ret;
1162 }
1163 
1164 kern_return_t
txm_allow_jit_region(pmap_t pmap)1165 txm_allow_jit_region(
1166 	pmap_t pmap)
1167 {
1168 	txm_call_t txm_call = {
1169 		.selector = kTXMKernelSelectorAllowJITRegion,
1170 		.num_input_args = 1,
1171 	};
1172 	TXMAddressSpace_t *txm_addr_space = pmap_txm_addr_space(pmap);
1173 	kern_return_t ret = KERN_DENIED;
1174 
1175 	pmap_txm_acquire_shared_lock(pmap);
1176 	ret = txm_kernel_call(&txm_call, txm_addr_space);
1177 	pmap_txm_release_shared_lock(pmap);
1178 
1179 	return ret;
1180 }
1181 
1182 kern_return_t
txm_associate_jit_region(pmap_t pmap,const vm_address_t region_addr,const vm_size_t region_size)1183 txm_associate_jit_region(
1184 	pmap_t pmap,
1185 	const vm_address_t region_addr,
1186 	const vm_size_t region_size)
1187 {
1188 	txm_call_t txm_call = {
1189 		.selector = kTXMKernelSelectorAssociateJITRegion,
1190 		.num_input_args = 3,
1191 	};
1192 	TXMAddressSpace_t *txm_addr_space = pmap_txm_addr_space(pmap);
1193 	kern_return_t ret = KERN_DENIED;
1194 
1195 	/*
1196 	 * Associating a JIT region may require exclusive access to the TXM address
1197 	 * space lock within TXM.
1198 	 */
1199 	pmap_txm_acquire_exclusive_lock(pmap);
1200 
1201 	ret = txm_kernel_call(
1202 		&txm_call,
1203 		txm_addr_space,
1204 		region_addr,
1205 		region_size);
1206 
1207 	/* Unlock the TXM address space lock */
1208 	pmap_txm_release_exclusive_lock(pmap);
1209 
1210 	return ret;
1211 }
1212 
1213 kern_return_t
txm_address_space_debugged(pmap_t pmap)1214 txm_address_space_debugged(
1215 	pmap_t pmap)
1216 {
1217 	TXMAddressSpace_t *txm_addr_space = pmap_txm_addr_space(pmap);
1218 	bool debug_regions_allowed = false;
1219 
1220 	/*
1221 	 * We do not actually need to trap into the monitor for this function for
1222 	 * now. It might be a tad bit more secure to actually trap into the monitor
1223 	 * as it implicitly verifies all of our pointers, but since this is a simple
1224 	 * state check against the address space, the real policy around it lies
1225 	 * within the kernel still, in which case entering the monitor doesn't
1226 	 * really provide much more security.
1227 	 */
1228 
1229 	pmap_txm_acquire_shared_lock(pmap);
1230 	debug_regions_allowed = os_atomic_load(&txm_addr_space->allowsInvalidCode, relaxed);
1231 	pmap_txm_release_shared_lock(pmap);
1232 
1233 	if (debug_regions_allowed == true) {
1234 		return KERN_SUCCESS;
1235 	}
1236 	return KERN_DENIED;
1237 }
1238 
1239 kern_return_t
txm_associate_debug_region(pmap_t pmap,const vm_address_t region_addr,const vm_size_t region_size)1240 txm_associate_debug_region(
1241 	pmap_t pmap,
1242 	const vm_address_t region_addr,
1243 	const vm_size_t region_size)
1244 {
1245 	/*
1246 	 * This function is an interesting one. There is no need for us to make
1247 	 * a call into TXM for this one and instead, all we need to do here is
1248 	 * to verify that the TXM address space actually allows debug regions to
1249 	 * be mapped in or not.
1250 	 */
1251 	(void)region_addr;
1252 	(void)region_size;
1253 
1254 	kern_return_t ret = txm_address_space_debugged(pmap);
1255 	if (ret != KERN_SUCCESS) {
1256 		printf("address space does not allow creating debug regions\n");
1257 	}
1258 
1259 	return ret;
1260 }
1261 
1262 kern_return_t
txm_allow_invalid_code(pmap_t pmap)1263 txm_allow_invalid_code(
1264 	pmap_t pmap)
1265 {
1266 	txm_call_t txm_call = {
1267 		.selector = kTXMKernelSelectorAllowInvalidCode,
1268 		.num_input_args = 1,
1269 	};
1270 	TXMAddressSpace_t *txm_addr_space = pmap_txm_addr_space(pmap);
1271 	kern_return_t ret = KERN_DENIED;
1272 
1273 	/*
1274 	 * Allowing invalid code may require exclusive access to the TXM address
1275 	 * space lock within TXM.
1276 	 */
1277 
1278 	pmap_txm_acquire_exclusive_lock(pmap);
1279 	ret = txm_kernel_call(&txm_call, txm_addr_space);
1280 	pmap_txm_release_exclusive_lock(pmap);
1281 
1282 	return ret;
1283 }
1284 
1285 kern_return_t
txm_get_trust_level_kdp(pmap_t pmap,uint32_t * trust_level)1286 txm_get_trust_level_kdp(
1287 	pmap_t pmap,
1288 	uint32_t *trust_level)
1289 {
1290 	CSTrust_t txm_trust_level = kCSTrustUntrusted;
1291 
1292 	kern_return_t ret = pmap_txm_get_trust_level_kdp(pmap, &txm_trust_level);
1293 	if (ret != KERN_SUCCESS) {
1294 		return ret;
1295 	}
1296 
1297 	if (trust_level != NULL) {
1298 		*trust_level = txm_trust_level;
1299 	}
1300 	return KERN_SUCCESS;
1301 }
1302 
1303 kern_return_t
txm_address_space_exempt(const pmap_t pmap)1304 txm_address_space_exempt(
1305 	const pmap_t pmap)
1306 {
1307 	if (pmap_performs_stage2_translations(pmap) == true) {
1308 		return KERN_SUCCESS;
1309 	}
1310 
1311 	return KERN_DENIED;
1312 }
1313 
1314 kern_return_t
txm_fork_prepare(pmap_t old_pmap,pmap_t new_pmap)1315 txm_fork_prepare(
1316 	pmap_t old_pmap,
1317 	pmap_t new_pmap)
1318 {
1319 	/*
1320 	 * We'll add support for this as the need for it becomes more important.
1321 	 * TXMTODO: Complete this implementation.
1322 	 */
1323 	(void)old_pmap;
1324 	(void)new_pmap;
1325 
1326 	return KERN_SUCCESS;
1327 }
1328 
1329 kern_return_t
txm_acquire_signing_identifier(const void * sig_obj,const char ** signing_id)1330 txm_acquire_signing_identifier(
1331 	const void *sig_obj,
1332 	const char **signing_id)
1333 {
1334 	txm_call_t txm_call = {
1335 		.selector = kTXMKernelSelectorAcquireSigningIdentifier,
1336 		.num_input_args = 1,
1337 		.num_output_args = 1,
1338 		.failure_fatal = true,
1339 	};
1340 
1341 	/* Get the signing ID -- should not fail */
1342 	txm_kernel_call(&txm_call, sig_obj);
1343 
1344 	if (signing_id != NULL) {
1345 		*signing_id = (const char*)txm_call.return_words[0];
1346 	}
1347 	return KERN_SUCCESS;
1348 }
1349 
1350 #pragma mark Entitlements
1351 
1352 kern_return_t
txm_associate_kernel_entitlements(void * sig_obj,const void * kernel_entitlements)1353 txm_associate_kernel_entitlements(
1354 	void *sig_obj,
1355 	const void *kernel_entitlements)
1356 {
1357 	txm_call_t txm_call = {
1358 		.selector = kTXMKernelSelectorAssociateKernelEntitlements,
1359 		.num_input_args = 2,
1360 		.failure_fatal = true,
1361 	};
1362 
1363 	/* Associate the kernel entitlements -- should not fail */
1364 	txm_kernel_call(&txm_call, sig_obj, kernel_entitlements);
1365 
1366 	return KERN_SUCCESS;
1367 }
1368 
1369 kern_return_t
txm_resolve_kernel_entitlements(pmap_t pmap,const void ** kernel_entitlements)1370 txm_resolve_kernel_entitlements(
1371 	pmap_t pmap,
1372 	const void **kernel_entitlements)
1373 {
1374 	txm_call_t txm_call = {
1375 		.selector = kTXMKernelSelectorResolveKernelEntitlementsAddressSpace,
1376 		.skip_logs = true,
1377 		.num_input_args = 1,
1378 		.num_output_args = 1,
1379 		.failure_silent = true,
1380 	};
1381 	TXMAddressSpace_t *txm_addr_space = NULL;
1382 	kern_return_t ret = KERN_DENIED;
1383 
1384 	if (pmap == pmap_txm_kernel_pmap()) {
1385 		return KERN_NOT_FOUND;
1386 	}
1387 	txm_addr_space = pmap_txm_addr_space(pmap);
1388 
1389 	pmap_txm_acquire_shared_lock(pmap);
1390 	ret = txm_kernel_call(&txm_call, txm_addr_space);
1391 	pmap_txm_release_shared_lock(pmap);
1392 
1393 	if ((ret == KERN_SUCCESS) && (kernel_entitlements != NULL)) {
1394 		*kernel_entitlements = (const void*)txm_call.return_words[0];
1395 	}
1396 	return ret;
1397 }
1398 
1399 kern_return_t
txm_accelerate_entitlements(void * sig_obj,CEQueryContext_t * ce_ctx)1400 txm_accelerate_entitlements(
1401 	void *sig_obj,
1402 	CEQueryContext_t *ce_ctx)
1403 {
1404 	txm_call_t txm_call = {
1405 		.selector = kTXMKernelSelectorAccelerateEntitlements,
1406 		.num_input_args = 1,
1407 		.num_output_args = 1,
1408 	};
1409 	kern_return_t ret = KERN_DENIED;
1410 
1411 	ret = txm_kernel_call(&txm_call, sig_obj);
1412 	if ((ret == KERN_SUCCESS) && (ce_ctx != NULL)) {
1413 		*ce_ctx = (CEQueryContext_t)txm_call.return_words[0];
1414 	}
1415 
1416 	return ret;
1417 }
1418 
1419 #pragma mark Image4
1420 
1421 void*
txm_image4_storage_data(__unused size_t * allocated_size)1422 txm_image4_storage_data(
1423 	__unused size_t *allocated_size)
1424 {
1425 	/*
1426 	 * AppleImage4 builds a variant of TXM which TXM should link against statically
1427 	 * thereby removing the need for the kernel to allocate some data on behalf of
1428 	 * the kernel extension.
1429 	 */
1430 	panic("unsupported AppleImage4 interface");
1431 }
1432 
1433 void
txm_image4_set_nonce(const img4_nonce_domain_index_t ndi,const img4_nonce_t * nonce)1434 txm_image4_set_nonce(
1435 	const img4_nonce_domain_index_t ndi,
1436 	const img4_nonce_t *nonce)
1437 {
1438 	txm_call_t txm_call = {
1439 		.selector = kTXMKernelSelectorImage4SetNonce,
1440 		.failure_fatal = true,
1441 		.num_input_args = 2,
1442 	};
1443 
1444 	txm_kernel_call(&txm_call, ndi, nonce);
1445 }
1446 
1447 void
txm_image4_roll_nonce(const img4_nonce_domain_index_t ndi)1448 txm_image4_roll_nonce(
1449 	const img4_nonce_domain_index_t ndi)
1450 {
1451 	txm_call_t txm_call = {
1452 		.selector = kTXMKernelSelectorImage4RollNonce,
1453 		.failure_fatal = true,
1454 		.num_input_args = 1,
1455 	};
1456 
1457 	txm_kernel_call(&txm_call, ndi);
1458 }
1459 
1460 errno_t
txm_image4_copy_nonce(const img4_nonce_domain_index_t ndi,img4_nonce_t * nonce_out)1461 txm_image4_copy_nonce(
1462 	const img4_nonce_domain_index_t ndi,
1463 	img4_nonce_t *nonce_out)
1464 {
1465 	txm_call_t txm_call = {
1466 		.selector = kTXMKernelSelectorImage4GetNonce,
1467 		.num_input_args = 1,
1468 		.num_output_args = 1,
1469 	};
1470 	const img4_nonce_t *nonce = NULL;
1471 	TXMReturn_t txm_ret = {0};
1472 	kern_return_t ret = KERN_DENIED;
1473 
1474 	ret = txm_kernel_call(&txm_call, ndi);
1475 	if (ret != KERN_SUCCESS) {
1476 		txm_ret = txm_call.txm_ret;
1477 		if (txm_ret.returnCode != kTXMReturnCodeErrno) {
1478 			return EPERM;
1479 		}
1480 		return txm_ret.errnoRet;
1481 	}
1482 
1483 	/* Acquire a pointer to the nonce from TXM */
1484 	nonce = (const img4_nonce_t*)txm_call.return_words[0];
1485 
1486 	if (nonce_out) {
1487 		*nonce_out = *nonce;
1488 	}
1489 	return 0;
1490 }
1491 
1492 errno_t
txm_image4_execute_object(img4_runtime_object_spec_index_t obj_spec_index,const img4_buff_t * payload,const img4_buff_t * manifest)1493 txm_image4_execute_object(
1494 	img4_runtime_object_spec_index_t obj_spec_index,
1495 	const img4_buff_t *payload,
1496 	const img4_buff_t *manifest)
1497 {
1498 	/* Not supported within TXM yet */
1499 	(void)obj_spec_index;
1500 	(void)payload;
1501 	(void)manifest;
1502 
1503 	printf("image4 object execution isn't supported by TXM\n");
1504 	return ENOSYS;
1505 }
1506 
1507 errno_t
txm_image4_copy_object(img4_runtime_object_spec_index_t obj_spec_index,vm_address_t object_out,size_t * object_length)1508 txm_image4_copy_object(
1509 	img4_runtime_object_spec_index_t obj_spec_index,
1510 	vm_address_t object_out,
1511 	size_t *object_length)
1512 {
1513 	/* Not supported within TXM yet */
1514 	(void)obj_spec_index;
1515 	(void)object_out;
1516 	(void)object_length;
1517 
1518 	printf("image4 object copying isn't supported by TXM\n");
1519 	return ENOSYS;
1520 }
1521 
1522 const void*
txm_image4_get_monitor_exports(void)1523 txm_image4_get_monitor_exports(void)
1524 {
1525 	txm_call_t txm_call = {
1526 		.selector = kTXMKernelSelectorImage4GetExports,
1527 		.failure_fatal = true,
1528 		.num_output_args = 1,
1529 	};
1530 
1531 	txm_kernel_call(&txm_call);
1532 	return (const void*)txm_call.return_words[0];
1533 }
1534 
1535 errno_t
txm_image4_set_release_type(const char * release_type)1536 txm_image4_set_release_type(
1537 	const char *release_type)
1538 {
1539 	txm_call_t txm_call = {
1540 		.selector = kTXMKernelSelectorImage4SetReleaseType,
1541 		.failure_fatal = true,
1542 		.num_input_args = 1,
1543 	};
1544 
1545 	/* Set the release type -- cannot fail */
1546 	txm_kernel_call(&txm_call, release_type);
1547 
1548 	return 0;
1549 }
1550 
1551 errno_t
txm_image4_set_bnch_shadow(const img4_nonce_domain_index_t ndi)1552 txm_image4_set_bnch_shadow(
1553 	const img4_nonce_domain_index_t ndi)
1554 {
1555 	txm_call_t txm_call = {
1556 		.selector = kTXMKernelSelectorImage4SetBootNonceShadow,
1557 		.failure_fatal = true,
1558 		.num_input_args = 1,
1559 	};
1560 
1561 	/* Set the release type -- cannot fail */
1562 	txm_kernel_call(&txm_call, ndi);
1563 
1564 	return 0;
1565 }
1566 
1567 #pragma mark Image4 - New
1568 
1569 static inline bool
_txm_image4_monitor_trap_supported(image4_cs_trap_t selector)1570 _txm_image4_monitor_trap_supported(
1571 	image4_cs_trap_t selector)
1572 {
1573 	switch (selector) {
1574 #if kTXMImage4APIVersion >= 1
1575 	case IMAGE4_CS_TRAP_KMOD_SET_RELEASE_TYPE:
1576 	case IMAGE4_CS_TRAP_KMOD_PIN_ROOT:
1577 	case IMAGE4_CS_TRAP_KMOD_EVALUATE_TRUST:
1578 	case IMAGE4_CS_TRAP_NONCE_SET:
1579 	case IMAGE4_CS_TRAP_NONCE_ROLL:
1580 	case IMAGE4_CS_TRAP_IMAGE_ACTIVATE:
1581 		return true;
1582 #endif
1583 
1584 	default:
1585 		return false;
1586 	}
1587 }
1588 
1589 kern_return_t
txm_image4_transfer_region(image4_cs_trap_t selector,vm_address_t region_addr,vm_size_t region_size)1590 txm_image4_transfer_region(
1591 	image4_cs_trap_t selector,
1592 	vm_address_t region_addr,
1593 	vm_size_t region_size)
1594 {
1595 	if (_txm_image4_monitor_trap_supported(selector) == true) {
1596 		txm_transfer_region(region_addr, region_size);
1597 	}
1598 	return KERN_SUCCESS;
1599 }
1600 
1601 kern_return_t
txm_image4_reclaim_region(image4_cs_trap_t selector,vm_address_t region_addr,vm_size_t region_size)1602 txm_image4_reclaim_region(
1603 	image4_cs_trap_t selector,
1604 	vm_address_t region_addr,
1605 	vm_size_t region_size)
1606 {
1607 	if (_txm_image4_monitor_trap_supported(selector) == true) {
1608 		txm_reclaim_region(region_addr, region_size);
1609 	}
1610 	return KERN_SUCCESS;
1611 }
1612 
1613 errno_t
txm_image4_monitor_trap(image4_cs_trap_t selector,__unused const void * input_data,__unused size_t input_size)1614 txm_image4_monitor_trap(
1615 	image4_cs_trap_t selector,
1616 	__unused const void *input_data,
1617 	__unused size_t input_size)
1618 {
1619 #if kTXMKernelAPIVersion >= 2
1620 	txm_call_t txm_call = {
1621 		.selector = kTXMKernelSelectorImage4Dispatch,
1622 		.num_input_args = 5,
1623 	};
1624 
1625 	kern_return_t ret = txm_kernel_call(
1626 		&txm_call, selector,
1627 		input_data, input_size,
1628 		NULL, NULL);
1629 
1630 	/* Return 0 for success */
1631 	if (ret == KERN_SUCCESS) {
1632 		return 0;
1633 	}
1634 
1635 	/* Check for an errno_t return */
1636 	if (txm_call.txm_ret.returnCode == kTXMReturnCodeErrno) {
1637 		if (txm_call.txm_ret.errnoRet == 0) {
1638 			panic("image4 dispatch: unexpected success errno_t: %llu", selector);
1639 		}
1640 		return txm_call.txm_ret.errnoRet;
1641 	}
1642 
1643 	/* Return a generic error */
1644 	return EPERM;
1645 #else
1646 	printf("image4 dispatch: traps not supported: %llu\n", selector);
1647 	return ENOSYS;
1648 #endif
1649 }
1650 
1651 #endif /* CONFIG_SPTM */
1652