xref: /xnu-10063.101.15/bsd/kern/code_signing/ppl.c (revision 94d3b452840153a99b38a3a9659680b2a006908e)
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 <os/overflow.h>
24 #include <machine/atomic.h>
25 #include <mach/vm_param.h>
26 #include <vm/vm_kern.h>
27 #include <kern/zalloc.h>
28 #include <kern/kalloc.h>
29 #include <kern/assert.h>
30 #include <kern/locks.h>
31 #include <kern/lock_rw.h>
32 #include <libkern/libkern.h>
33 #include <libkern/section_keywords.h>
34 #include <libkern/coretrust/coretrust.h>
35 #include <pexpert/pexpert.h>
36 #include <sys/vm.h>
37 #include <sys/proc.h>
38 #include <sys/codesign.h>
39 #include <sys/code_signing.h>
40 #include <uuid/uuid.h>
41 #include <IOKit/IOBSD.h>
42 
43 #if PMAP_CS_PPL_MONITOR
44 /*
45  * The Page Protection Layer layer implements the PMAP_CS monitor environment which
46  * provides code signing and memory isolation enforcements for data structures which
47  * are critical to ensuring that all code executed on the system is authorized to do
48  * so.
49  *
50  * Unless the data is managed by the PPL itself, XNU needs to page-align everything,
51  * and then reference the memory as read-only.
52  */
53 
54 typedef uint64_t pmap_paddr_t __kernel_ptr_semantics;
55 extern vm_map_address_t phystokv(pmap_paddr_t pa);
56 extern pmap_paddr_t kvtophys_nofail(vm_offset_t va);
57 
58 #pragma mark Initialization
59 
60 void
code_signing_init()61 code_signing_init()
62 {
63 	/* Does nothing */
64 }
65 
66 void
ppl_enter_lockdown_mode(void)67 ppl_enter_lockdown_mode(void)
68 {
69 	/*
70 	 * This function is expected to be called before read-only lockdown on the
71 	 * system. As a result, the PPL variable should be mutable. If not, then we
72 	 * will panic (as we should).
73 	 */
74 	ppl_lockdown_mode_enabled = true;
75 
76 	printf("entered lockdown mode policy for the PPL");
77 }
78 
79 #pragma mark Developer Mode
80 
81 SECURITY_READ_ONLY_LATE(bool*) developer_mode_enabled = &ppl_developer_mode_storage;
82 
83 void
ppl_toggle_developer_mode(bool state)84 ppl_toggle_developer_mode(
85 	bool state)
86 {
87 	pmap_toggle_developer_mode(state);
88 }
89 
90 #pragma mark Code Signing and Provisioning Profiles
91 
92 bool
ppl_code_signing_enabled(void)93 ppl_code_signing_enabled(void)
94 {
95 	return pmap_cs_enabled();
96 }
97 
98 kern_return_t
ppl_register_provisioning_profile(const void * profile_blob,const size_t profile_blob_size,void ** profile_obj)99 ppl_register_provisioning_profile(
100 	const void *profile_blob,
101 	const size_t profile_blob_size,
102 	void **profile_obj)
103 {
104 	pmap_profile_payload_t *pmap_payload = NULL;
105 	vm_address_t payload_addr = 0;
106 	vm_size_t payload_size = 0;
107 	vm_size_t payload_size_aligned = 0;
108 	kern_return_t ret = KERN_DENIED;
109 
110 	if (os_add_overflow(sizeof(*pmap_payload), profile_blob_size, &payload_size)) {
111 		panic("attempted to load a too-large profile: %lu bytes", profile_blob_size);
112 	}
113 	payload_size_aligned = round_page(payload_size);
114 
115 	ret = kmem_alloc(kernel_map, &payload_addr, payload_size_aligned,
116 	    KMA_KOBJECT | KMA_DATA | KMA_ZERO, VM_KERN_MEMORY_SECURITY);
117 	if (ret != KERN_SUCCESS) {
118 		printf("unable to allocate memory for pmap profile payload: %d\n", ret);
119 		goto exit;
120 	}
121 
122 	/* We need to setup the payload before we send it to the PPL */
123 	pmap_payload = (pmap_profile_payload_t*)payload_addr;
124 
125 	pmap_payload->profile_blob_size = profile_blob_size;
126 	memcpy(pmap_payload->profile_blob, profile_blob, profile_blob_size);
127 
128 	ret = pmap_register_provisioning_profile(payload_addr, payload_size_aligned);
129 	if (ret == KERN_SUCCESS) {
130 		*profile_obj = &pmap_payload->profile_obj_storage;
131 		*profile_obj = (pmap_cs_profile_t*)phystokv(kvtophys_nofail((vm_offset_t)*profile_obj));
132 	}
133 
134 exit:
135 	if ((ret != KERN_SUCCESS) && (payload_addr != 0)) {
136 		kmem_free(kernel_map, payload_addr, payload_size_aligned);
137 		payload_addr = 0;
138 		payload_size_aligned = 0;
139 	}
140 
141 	return ret;
142 }
143 
144 kern_return_t
ppl_unregister_provisioning_profile(void * profile_obj)145 ppl_unregister_provisioning_profile(
146 	void *profile_obj)
147 {
148 	pmap_cs_profile_t *ppl_profile_obj = profile_obj;
149 	kern_return_t ret = KERN_DENIED;
150 
151 	ret = pmap_unregister_provisioning_profile(ppl_profile_obj);
152 	if (ret != KERN_SUCCESS) {
153 		return ret;
154 	}
155 
156 	/* Get the original payload address */
157 	const pmap_profile_payload_t *pmap_payload = ppl_profile_obj->original_payload;
158 	const vm_address_t payload_addr = (const vm_address_t)pmap_payload;
159 
160 	/* Get the original payload size */
161 	vm_size_t payload_size = pmap_payload->profile_blob_size + sizeof(*pmap_payload);
162 	payload_size = round_page(payload_size);
163 
164 	/* Free the payload */
165 	kmem_free(kernel_map, payload_addr, payload_size);
166 	pmap_payload = NULL;
167 
168 	return KERN_SUCCESS;
169 }
170 
171 kern_return_t
ppl_associate_provisioning_profile(void * sig_obj,void * profile_obj)172 ppl_associate_provisioning_profile(
173 	void *sig_obj,
174 	void *profile_obj)
175 {
176 	return pmap_associate_provisioning_profile(sig_obj, profile_obj);
177 }
178 
179 kern_return_t
ppl_disassociate_provisioning_profile(void * sig_obj)180 ppl_disassociate_provisioning_profile(
181 	void *sig_obj)
182 {
183 	return pmap_disassociate_provisioning_profile(sig_obj);
184 }
185 
186 void
ppl_set_compilation_service_cdhash(const uint8_t cdhash[CS_CDHASH_LEN])187 ppl_set_compilation_service_cdhash(
188 	const uint8_t cdhash[CS_CDHASH_LEN])
189 {
190 	pmap_set_compilation_service_cdhash(cdhash);
191 }
192 
193 bool
ppl_match_compilation_service_cdhash(const uint8_t cdhash[CS_CDHASH_LEN])194 ppl_match_compilation_service_cdhash(
195 	const uint8_t cdhash[CS_CDHASH_LEN])
196 {
197 	return pmap_match_compilation_service_cdhash(cdhash);
198 }
199 
200 void
ppl_set_local_signing_public_key(const uint8_t public_key[XNU_LOCAL_SIGNING_KEY_SIZE])201 ppl_set_local_signing_public_key(
202 	const uint8_t public_key[XNU_LOCAL_SIGNING_KEY_SIZE])
203 {
204 	return pmap_set_local_signing_public_key(public_key);
205 }
206 
207 uint8_t*
ppl_get_local_signing_public_key(void)208 ppl_get_local_signing_public_key(void)
209 {
210 	return pmap_get_local_signing_public_key();
211 }
212 
213 void
ppl_unrestrict_local_signing_cdhash(const uint8_t cdhash[CS_CDHASH_LEN])214 ppl_unrestrict_local_signing_cdhash(
215 	const uint8_t cdhash[CS_CDHASH_LEN])
216 {
217 	pmap_unrestrict_local_signing(cdhash);
218 }
219 
220 vm_size_t
ppl_managed_code_signature_size(void)221 ppl_managed_code_signature_size(void)
222 {
223 	return pmap_cs_blob_limit;
224 }
225 
226 kern_return_t
ppl_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 * ppl_signature_addr)227 ppl_register_code_signature(
228 	const vm_address_t signature_addr,
229 	const vm_size_t signature_size,
230 	const vm_offset_t code_directory_offset,
231 	const char *signature_path,
232 	void **sig_obj,
233 	vm_address_t *ppl_signature_addr)
234 {
235 	pmap_cs_code_directory_t *cd_entry = NULL;
236 
237 	/* PPL doesn't care about the signature path */
238 	(void)signature_path;
239 
240 	kern_return_t ret = pmap_cs_register_code_signature_blob(
241 		signature_addr,
242 		signature_size,
243 		code_directory_offset,
244 		(pmap_cs_code_directory_t**)sig_obj);
245 
246 	if (ret != KERN_SUCCESS) {
247 		return ret;
248 	}
249 	cd_entry = *((pmap_cs_code_directory_t**)sig_obj);
250 
251 	if (ppl_signature_addr) {
252 		*ppl_signature_addr = (vm_address_t)cd_entry->superblob;
253 	}
254 
255 	return KERN_SUCCESS;
256 }
257 
258 kern_return_t
ppl_unregister_code_signature(void * sig_obj)259 ppl_unregister_code_signature(
260 	void *sig_obj)
261 {
262 	return pmap_cs_unregister_code_signature_blob(sig_obj);
263 }
264 
265 kern_return_t
ppl_verify_code_signature(void * sig_obj)266 ppl_verify_code_signature(
267 	void *sig_obj)
268 {
269 	return pmap_cs_verify_code_signature_blob(sig_obj);
270 }
271 
272 kern_return_t
ppl_reconstitute_code_signature(void * sig_obj,vm_address_t * unneeded_addr,vm_size_t * unneeded_size)273 ppl_reconstitute_code_signature(
274 	void *sig_obj,
275 	vm_address_t *unneeded_addr,
276 	vm_size_t *unneeded_size)
277 {
278 	return pmap_cs_unlock_unneeded_code_signature(
279 		sig_obj,
280 		unneeded_addr,
281 		unneeded_size);
282 }
283 
284 #pragma mark Address Spaces
285 
286 kern_return_t
ppl_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)287 ppl_associate_code_signature(
288 	pmap_t pmap,
289 	void *sig_obj,
290 	const vm_address_t region_addr,
291 	const vm_size_t region_size,
292 	const vm_offset_t region_offset)
293 {
294 	return pmap_cs_associate(
295 		pmap,
296 		sig_obj,
297 		region_addr,
298 		region_size,
299 		region_offset);
300 }
301 
302 kern_return_t
ppl_allow_jit_region(__unused pmap_t pmap)303 ppl_allow_jit_region(
304 	__unused pmap_t pmap)
305 {
306 	/* PPL does not support this API */
307 	return KERN_NOT_SUPPORTED;
308 }
309 
310 kern_return_t
ppl_associate_jit_region(pmap_t pmap,const vm_address_t region_addr,const vm_size_t region_size)311 ppl_associate_jit_region(
312 	pmap_t pmap,
313 	const vm_address_t region_addr,
314 	const vm_size_t region_size)
315 {
316 	return pmap_cs_associate(
317 		pmap,
318 		PMAP_CS_ASSOCIATE_JIT,
319 		region_addr,
320 		region_size,
321 		0);
322 }
323 
324 kern_return_t
ppl_associate_debug_region(pmap_t pmap,const vm_address_t region_addr,const vm_size_t region_size)325 ppl_associate_debug_region(
326 	pmap_t pmap,
327 	const vm_address_t region_addr,
328 	const vm_size_t region_size)
329 {
330 	return pmap_cs_associate(
331 		pmap,
332 		PMAP_CS_ASSOCIATE_COW,
333 		region_addr,
334 		region_size,
335 		0);
336 }
337 
338 kern_return_t
ppl_address_space_debugged(pmap_t pmap)339 ppl_address_space_debugged(
340 	pmap_t pmap)
341 {
342 	/*
343 	 * ppl_associate_debug_region is a fairly idempotent function which simply
344 	 * checks if an address space is already debugged or not and returns a value
345 	 * based on that. The actual memory region is not inserted into the address
346 	 * space, so we can pass whatever in this case. The only caveat here though
347 	 * is that the memory region needs to be page-aligned and cannot be NULL.
348 	 */
349 	return ppl_associate_debug_region(pmap, PAGE_SIZE, PAGE_SIZE);
350 }
351 
352 kern_return_t
ppl_allow_invalid_code(pmap_t pmap)353 ppl_allow_invalid_code(
354 	pmap_t pmap)
355 {
356 	return pmap_cs_allow_invalid(pmap);
357 }
358 
359 kern_return_t
ppl_get_trust_level_kdp(pmap_t pmap,uint32_t * trust_level)360 ppl_get_trust_level_kdp(
361 	pmap_t pmap,
362 	uint32_t *trust_level)
363 {
364 	return pmap_get_trust_level_kdp(pmap, trust_level);
365 }
366 
367 kern_return_t
ppl_address_space_exempt(const pmap_t pmap)368 ppl_address_space_exempt(
369 	const pmap_t pmap)
370 {
371 	if (pmap_performs_stage2_translations(pmap) == true) {
372 		return KERN_SUCCESS;
373 	}
374 
375 	return KERN_DENIED;
376 }
377 
378 kern_return_t
ppl_fork_prepare(pmap_t old_pmap,pmap_t new_pmap)379 ppl_fork_prepare(
380 	pmap_t old_pmap,
381 	pmap_t new_pmap)
382 {
383 	return pmap_cs_fork_prepare(old_pmap, new_pmap);
384 }
385 
386 kern_return_t
ppl_acquire_signing_identifier(const void * sig_obj,const char ** signing_id)387 ppl_acquire_signing_identifier(
388 	const void *sig_obj,
389 	const char **signing_id)
390 {
391 	const pmap_cs_code_directory_t *cd_entry = sig_obj;
392 
393 	/* If we reach here, the identifier must have been setup */
394 	assert(cd_entry->identifier != NULL);
395 
396 	if (signing_id) {
397 		*signing_id = cd_entry->identifier;
398 	}
399 
400 	return KERN_SUCCESS;
401 }
402 
403 #pragma mark Entitlements
404 
405 kern_return_t
ppl_associate_kernel_entitlements(void * sig_obj,const void * kernel_entitlements)406 ppl_associate_kernel_entitlements(
407 	void *sig_obj,
408 	const void *kernel_entitlements)
409 {
410 	pmap_cs_code_directory_t *cd_entry = sig_obj;
411 	return pmap_associate_kernel_entitlements(cd_entry, kernel_entitlements);
412 }
413 
414 kern_return_t
ppl_resolve_kernel_entitlements(pmap_t pmap,const void ** kernel_entitlements)415 ppl_resolve_kernel_entitlements(
416 	pmap_t pmap,
417 	const void **kernel_entitlements)
418 {
419 	kern_return_t ret = KERN_DENIED;
420 	const void *entitlements = NULL;
421 
422 	ret = pmap_resolve_kernel_entitlements(pmap, &entitlements);
423 	if ((ret == KERN_SUCCESS) && (kernel_entitlements != NULL)) {
424 		*kernel_entitlements = entitlements;
425 	}
426 
427 	return ret;
428 }
429 
430 kern_return_t
ppl_accelerate_entitlements(void * sig_obj,CEQueryContext_t * ce_ctx)431 ppl_accelerate_entitlements(
432 	void *sig_obj,
433 	CEQueryContext_t *ce_ctx)
434 {
435 	pmap_cs_code_directory_t *cd_entry = sig_obj;
436 	kern_return_t ret = KERN_DENIED;
437 
438 	ret = pmap_accelerate_entitlements(cd_entry);
439 
440 	/*
441 	 * We only ever get KERN_ABORTED when we cannot accelerate the entitlements
442 	 * because it would consume too much memory. In this case, we still want to
443 	 * return the ce_ctx since we don't want the system to fall-back to non-PPL
444 	 * locked down memory, so we switch this to a success case.
445 	 */
446 	if (ret == KERN_ABORTED) {
447 		ret = KERN_SUCCESS;
448 	}
449 
450 	/* Return the accelerated context to the caller */
451 	if ((ret == KERN_SUCCESS) && (ce_ctx != NULL)) {
452 		*ce_ctx = cd_entry->ce_ctx;
453 	}
454 
455 	return ret;
456 }
457 
458 #pragma mark Image4
459 
460 void*
ppl_image4_storage_data(size_t * allocated_size)461 ppl_image4_storage_data(
462 	size_t *allocated_size)
463 {
464 	return pmap_image4_pmap_data(allocated_size);
465 }
466 
467 void
ppl_image4_set_nonce(const img4_nonce_domain_index_t ndi,const img4_nonce_t * nonce)468 ppl_image4_set_nonce(
469 	const img4_nonce_domain_index_t ndi,
470 	const img4_nonce_t *nonce)
471 {
472 	return pmap_image4_set_nonce(ndi, nonce);
473 }
474 
475 void
ppl_image4_roll_nonce(const img4_nonce_domain_index_t ndi)476 ppl_image4_roll_nonce(
477 	const img4_nonce_domain_index_t ndi)
478 {
479 	return pmap_image4_roll_nonce(ndi);
480 }
481 
482 errno_t
ppl_image4_copy_nonce(const img4_nonce_domain_index_t ndi,img4_nonce_t * nonce_out)483 ppl_image4_copy_nonce(
484 	const img4_nonce_domain_index_t ndi,
485 	img4_nonce_t *nonce_out)
486 {
487 	return pmap_image4_copy_nonce(ndi, nonce_out);
488 }
489 
490 errno_t
ppl_image4_execute_object(img4_runtime_object_spec_index_t obj_spec_index,const img4_buff_t * payload,const img4_buff_t * manifest)491 ppl_image4_execute_object(
492 	img4_runtime_object_spec_index_t obj_spec_index,
493 	const img4_buff_t *payload,
494 	const img4_buff_t *manifest)
495 {
496 	errno_t err = EINVAL;
497 	kern_return_t kr = KERN_DENIED;
498 	img4_buff_t payload_aligned = IMG4_BUFF_INIT;
499 	img4_buff_t manifest_aligned = IMG4_BUFF_INIT;
500 	vm_address_t payload_addr = 0;
501 	vm_size_t payload_len_aligned = 0;
502 	vm_address_t manifest_addr = 0;
503 	vm_size_t manifest_len_aligned = 0;
504 
505 	if (payload == NULL) {
506 		printf("invalid object execution request: no payload\n");
507 		goto out;
508 	}
509 
510 	/*
511 	 * The PPL will attempt to lockdown both the payload and the manifest before executing
512 	 * the object. In order for that to happen, both the artifacts need to be page-aligned.
513 	 */
514 	payload_len_aligned = round_page(payload->i4b_len);
515 	if (manifest != NULL) {
516 		manifest_len_aligned = round_page(manifest->i4b_len);
517 	}
518 
519 	kr = kmem_alloc(
520 		kernel_map,
521 		&payload_addr,
522 		payload_len_aligned,
523 		KMA_KOBJECT,
524 		VM_KERN_MEMORY_SECURITY);
525 
526 	if (kr != KERN_SUCCESS) {
527 		printf("unable to allocate memory for image4 payload: %d\n", kr);
528 		err = ENOMEM;
529 		goto out;
530 	}
531 
532 	/* Copy in the payload */
533 	memcpy((uint8_t*)payload_addr, payload->i4b_bytes, payload->i4b_len);
534 
535 	/* Construct the aligned payload buffer */
536 	payload_aligned.i4b_bytes = (uint8_t*)payload_addr;
537 	payload_aligned.i4b_len = payload->i4b_len;
538 
539 	if (manifest != NULL) {
540 		kr = kmem_alloc(
541 			kernel_map,
542 			&manifest_addr,
543 			manifest_len_aligned,
544 			KMA_KOBJECT,
545 			VM_KERN_MEMORY_SECURITY);
546 
547 		if (kr != KERN_SUCCESS) {
548 			printf("unable to allocate memory for image4 manifest: %d\n", kr);
549 			err = ENOMEM;
550 			goto out;
551 		}
552 
553 		/* Construct the aligned manifest buffer */
554 		manifest_aligned.i4b_bytes = (uint8_t*)manifest_addr;
555 		manifest_aligned.i4b_len = manifest->i4b_len;
556 
557 		/* Copy in the manifest */
558 		memcpy((uint8_t*)manifest_addr, manifest->i4b_bytes, manifest->i4b_len);
559 	}
560 
561 	err = pmap_image4_execute_object(obj_spec_index, &payload_aligned, &manifest_aligned);
562 	if (err != 0) {
563 		printf("unable to execute image4 object: %d\n", err);
564 		goto out;
565 	}
566 
567 out:
568 	/* We always free the manifest as it isn't required anymore */
569 	if (manifest_addr != 0) {
570 		kmem_free(kernel_map, manifest_addr, manifest_len_aligned);
571 		manifest_addr = 0;
572 		manifest_len_aligned = 0;
573 	}
574 
575 	/* If we encountered an error -- free the allocated payload */
576 	if ((err != 0) && (payload_addr != 0)) {
577 		kmem_free(kernel_map, payload_addr, payload_len_aligned);
578 		payload_addr = 0;
579 		payload_len_aligned = 0;
580 	}
581 
582 	return err;
583 }
584 
585 errno_t
ppl_image4_copy_object(img4_runtime_object_spec_index_t obj_spec_index,vm_address_t object_out,size_t * object_length)586 ppl_image4_copy_object(
587 	img4_runtime_object_spec_index_t obj_spec_index,
588 	vm_address_t object_out,
589 	size_t *object_length)
590 {
591 	errno_t err = EINVAL;
592 	kern_return_t kr = KERN_DENIED;
593 	vm_address_t object_addr = 0;
594 	vm_size_t object_len_aligned = 0;
595 
596 	if (object_out == 0) {
597 		printf("invalid object copy request: no object input buffer\n");
598 		goto out;
599 	} else if (object_length == NULL) {
600 		printf("invalid object copy request: no object input length\n");
601 		goto out;
602 	}
603 
604 	/*
605 	 * The PPL will attempt to pin the input buffer in order to ensure that the kernel
606 	 * didn't pass in PPL-owned buffers. The PPL cannot pin the same page more than once,
607 	 * and attempting to do so will panic the system. Hence, we allocate fresh pages for
608 	 * for the PPL to pin.
609 	 *
610 	 * We can send in the address for the length pointer since that is allocated on the
611 	 * stack, so the PPL can pin our stack for the duration of the call as no other
612 	 * thread can be using our stack, meaning the PPL will never attempt to double-pin
613 	 * the page.
614 	 */
615 	object_len_aligned = round_page(*object_length);
616 
617 	kr = kmem_alloc(
618 		kernel_map,
619 		&object_addr,
620 		object_len_aligned,
621 		KMA_KOBJECT,
622 		VM_KERN_MEMORY_SECURITY);
623 
624 	if (kr != KERN_SUCCESS) {
625 		printf("unable to allocate memory for image4 object: %d\n", kr);
626 		err = ENOMEM;
627 		goto out;
628 	}
629 
630 	err = pmap_image4_copy_object(obj_spec_index, object_addr, object_length);
631 	if (err != 0) {
632 		printf("unable to copy image4 object: %d\n", err);
633 		goto out;
634 	}
635 
636 	/* Copy the data back into the caller passed buffer */
637 	memcpy((void*)object_out, (void*)object_addr, *object_length);
638 
639 out:
640 	/* We don't ever need to keep around our page-aligned buffer */
641 	if (object_addr != 0) {
642 		kmem_free(kernel_map, object_addr, object_len_aligned);
643 		object_addr = 0;
644 		object_len_aligned = 0;
645 	}
646 
647 	return err;
648 }
649 
650 const void*
ppl_image4_get_monitor_exports(void)651 ppl_image4_get_monitor_exports(void)
652 {
653 	/*
654 	 * AppleImage4 can query the PMAP_CS runtime on its own since the PMAP_CS
655 	 * runtime is compiled within the kernel extension itself. As a result, we
656 	 * never expect this KPI to be called when the system uses the PPL monitor.
657 	 */
658 
659 	printf("explicit monitor-exports-get not required for the PPL\n");
660 	return NULL;
661 }
662 
663 errno_t
ppl_image4_set_release_type(__unused const char * release_type)664 ppl_image4_set_release_type(
665 	__unused const char *release_type)
666 {
667 	/*
668 	 * AppleImage4 stores the release type in the CTRR protected memory region
669 	 * of its kernel extension. This is accessible by the PMAP_CS runtime as the
670 	 * runtime is compiled alongside the kernel extension. As a result, we never
671 	 * expect this KPI to be called when the system uses the PPL monitor.
672 	 */
673 
674 	printf("explicit release-type-set set not required for the PPL\n");
675 	return ENOTSUP;
676 }
677 
678 errno_t
ppl_image4_set_bnch_shadow(__unused const img4_nonce_domain_index_t ndi)679 ppl_image4_set_bnch_shadow(
680 	__unused const img4_nonce_domain_index_t ndi)
681 {
682 	/*
683 	 * AppleImage4 stores the BNCH shadow in the CTRR protected memory region
684 	 * of its kernel extension. This is accessible by the PMAP_CS runtime as the
685 	 * runtime is compiled alongside the kernel extension. As a result, we never
686 	 * expect this KPI to be called when the system uses the PPL monitor.
687 	 */
688 
689 	printf("explicit BNCH-shadow-set not required for the PPL\n");
690 	return ENOTSUP;
691 }
692 
693 #pragma mark Image4 - New
694 
695 kern_return_t
ppl_image4_transfer_region(__unused image4_cs_trap_t selector,__unused vm_address_t region_addr,__unused vm_size_t region_size)696 ppl_image4_transfer_region(
697 	__unused image4_cs_trap_t selector,
698 	__unused vm_address_t region_addr,
699 	__unused vm_size_t region_size)
700 {
701 	/* All regions transfers happen internally with the PPL */
702 	return KERN_SUCCESS;
703 }
704 
705 kern_return_t
ppl_image4_reclaim_region(__unused image4_cs_trap_t selector,__unused vm_address_t region_addr,__unused vm_size_t region_size)706 ppl_image4_reclaim_region(
707 	__unused image4_cs_trap_t selector,
708 	__unused vm_address_t region_addr,
709 	__unused vm_size_t region_size)
710 {
711 	/* All regions transfers happen internally with the PPL */
712 	return KERN_SUCCESS;
713 }
714 
715 errno_t
ppl_image4_monitor_trap(image4_cs_trap_t selector,const void * input_data,size_t input_size)716 ppl_image4_monitor_trap(
717 	image4_cs_trap_t selector,
718 	const void *input_data,
719 	size_t input_size)
720 {
721 	return pmap_image4_monitor_trap(selector, input_data, input_size);
722 }
723 
724 #endif /* PMAP_CS_PPL_MONITOR */
725