xref: /xnu-12377.81.4/bsd/kern/code_signing/ppl.c (revision 043036a2b3718f7f0be807e2870f8f47d3fa0796)
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_xnu.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 kern_return_t
ppl_secure_channel_shared_page(__unused uint64_t * secure_channel_phys,__unused size_t * secure_channel_size)80 ppl_secure_channel_shared_page(
81 	__unused uint64_t *secure_channel_phys,
82 	__unused size_t *secure_channel_size)
83 {
84 	return KERN_NOT_SUPPORTED;
85 }
86 
87 #pragma mark Developer Mode
88 
89 SECURITY_READ_ONLY_LATE(bool*) developer_mode_enabled = &ppl_developer_mode_storage;
90 
91 void
ppl_toggle_developer_mode(bool state)92 ppl_toggle_developer_mode(
93 	bool state)
94 {
95 	pmap_toggle_developer_mode(state);
96 }
97 
98 #pragma mark Restricted Execution Mode
99 
100 kern_return_t
ppl_rem_enable(void)101 ppl_rem_enable(void)
102 {
103 	return KERN_NOT_SUPPORTED;
104 }
105 
106 kern_return_t
ppl_rem_state(void)107 ppl_rem_state(void)
108 {
109 	return KERN_NOT_SUPPORTED;
110 }
111 
112 #pragma mark Device State
113 
114 void
ppl_update_device_state(void)115 ppl_update_device_state(void)
116 {
117 	/* Does nothing */
118 }
119 
120 void
ppl_complete_security_boot_mode(__unused uint32_t security_boot_mode)121 ppl_complete_security_boot_mode(
122 	__unused uint32_t security_boot_mode)
123 {
124 	/* Does nothing */
125 }
126 
127 #pragma mark Code Signing and Provisioning Profiles
128 
129 bool
ppl_code_signing_enabled(void)130 ppl_code_signing_enabled(void)
131 {
132 	return pmap_cs_enabled();
133 }
134 
135 kern_return_t
ppl_register_provisioning_profile(const void * profile_blob,const size_t profile_blob_size,void ** profile_obj)136 ppl_register_provisioning_profile(
137 	const void *profile_blob,
138 	const size_t profile_blob_size,
139 	void **profile_obj)
140 {
141 	pmap_profile_payload_t *pmap_payload = NULL;
142 	vm_address_t payload_addr = 0;
143 	vm_size_t payload_size = 0;
144 	vm_size_t payload_size_aligned = 0;
145 	kern_return_t ret = KERN_DENIED;
146 
147 	if (os_add_overflow(sizeof(*pmap_payload), profile_blob_size, &payload_size)) {
148 		panic("attempted to load a too-large profile: %lu bytes", profile_blob_size);
149 	}
150 	payload_size_aligned = round_page(payload_size);
151 
152 	ret = kmem_alloc(kernel_map, &payload_addr, payload_size_aligned,
153 	    KMA_KOBJECT | KMA_DATA | KMA_ZERO, VM_KERN_MEMORY_SECURITY);
154 	if (ret != KERN_SUCCESS) {
155 		printf("unable to allocate memory for pmap profile payload: %d\n", ret);
156 		goto exit;
157 	}
158 
159 	/* We need to setup the payload before we send it to the PPL */
160 	pmap_payload = (pmap_profile_payload_t*)payload_addr;
161 
162 	pmap_payload->profile_blob_size = profile_blob_size;
163 	memcpy(pmap_payload->profile_blob, profile_blob, profile_blob_size);
164 
165 	ret = pmap_register_provisioning_profile(payload_addr, payload_size_aligned);
166 	if (ret == KERN_SUCCESS) {
167 		*profile_obj = &pmap_payload->profile_obj_storage;
168 		*profile_obj = (pmap_cs_profile_t*)phystokv(kvtophys_nofail((vm_offset_t)*profile_obj));
169 	}
170 
171 exit:
172 	if ((ret != KERN_SUCCESS) && (payload_addr != 0)) {
173 		kmem_free(kernel_map, payload_addr, payload_size_aligned);
174 		payload_addr = 0;
175 		payload_size_aligned = 0;
176 	}
177 
178 	return ret;
179 }
180 
181 kern_return_t
ppl_trust_provisioning_profile(__unused void * profile_obj,__unused const void * sig_data,__unused size_t sig_size)182 ppl_trust_provisioning_profile(
183 	__unused void *profile_obj,
184 	__unused const void *sig_data,
185 	__unused size_t sig_size)
186 {
187 	/* PPL does not support profile trust */
188 	return KERN_SUCCESS;
189 }
190 
191 kern_return_t
ppl_unregister_provisioning_profile(void * profile_obj)192 ppl_unregister_provisioning_profile(
193 	void *profile_obj)
194 {
195 	pmap_cs_profile_t *ppl_profile_obj = profile_obj;
196 	kern_return_t ret = KERN_DENIED;
197 
198 	ret = pmap_unregister_provisioning_profile(ppl_profile_obj);
199 	if (ret != KERN_SUCCESS) {
200 		return ret;
201 	}
202 
203 	/* Get the original payload address */
204 	const pmap_profile_payload_t *pmap_payload = ppl_profile_obj->original_payload;
205 	const vm_address_t payload_addr = (const vm_address_t)pmap_payload;
206 
207 	/* Get the original payload size */
208 	vm_size_t payload_size = pmap_payload->profile_blob_size + sizeof(*pmap_payload);
209 	payload_size = round_page(payload_size);
210 
211 	/* Free the payload */
212 	kmem_free(kernel_map, payload_addr, payload_size);
213 	pmap_payload = NULL;
214 
215 	return KERN_SUCCESS;
216 }
217 
218 kern_return_t
ppl_associate_provisioning_profile(void * sig_obj,void * profile_obj)219 ppl_associate_provisioning_profile(
220 	void *sig_obj,
221 	void *profile_obj)
222 {
223 	return pmap_associate_provisioning_profile(sig_obj, profile_obj);
224 }
225 
226 kern_return_t
ppl_disassociate_provisioning_profile(void * sig_obj)227 ppl_disassociate_provisioning_profile(
228 	void *sig_obj)
229 {
230 	return pmap_disassociate_provisioning_profile(sig_obj);
231 }
232 
233 void
ppl_set_compilation_service_cdhash(const uint8_t cdhash[CS_CDHASH_LEN])234 ppl_set_compilation_service_cdhash(
235 	const uint8_t cdhash[CS_CDHASH_LEN])
236 {
237 	pmap_set_compilation_service_cdhash(cdhash);
238 }
239 
240 bool
ppl_match_compilation_service_cdhash(const uint8_t cdhash[CS_CDHASH_LEN])241 ppl_match_compilation_service_cdhash(
242 	const uint8_t cdhash[CS_CDHASH_LEN])
243 {
244 	return pmap_match_compilation_service_cdhash(cdhash);
245 }
246 
247 void
ppl_set_local_signing_public_key(const uint8_t public_key[XNU_LOCAL_SIGNING_KEY_SIZE])248 ppl_set_local_signing_public_key(
249 	const uint8_t public_key[XNU_LOCAL_SIGNING_KEY_SIZE])
250 {
251 	return pmap_set_local_signing_public_key(public_key);
252 }
253 
254 uint8_t*
ppl_get_local_signing_public_key(void)255 ppl_get_local_signing_public_key(void)
256 {
257 	return pmap_get_local_signing_public_key();
258 }
259 
260 void
ppl_unrestrict_local_signing_cdhash(const uint8_t cdhash[CS_CDHASH_LEN])261 ppl_unrestrict_local_signing_cdhash(
262 	const uint8_t cdhash[CS_CDHASH_LEN])
263 {
264 	pmap_unrestrict_local_signing(cdhash);
265 }
266 
267 vm_size_t
ppl_managed_code_signature_size(void)268 ppl_managed_code_signature_size(void)
269 {
270 	return pmap_cs_blob_limit;
271 }
272 
273 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)274 ppl_register_code_signature(
275 	const vm_address_t signature_addr,
276 	const vm_size_t signature_size,
277 	const vm_offset_t code_directory_offset,
278 	const char *signature_path,
279 	void **sig_obj,
280 	vm_address_t *ppl_signature_addr)
281 {
282 	pmap_cs_code_directory_t *cd_entry = NULL;
283 
284 	/* PPL doesn't care about the signature path */
285 	(void)signature_path;
286 
287 	kern_return_t ret = pmap_cs_register_code_signature_blob(
288 		signature_addr,
289 		signature_size,
290 		code_directory_offset,
291 		(pmap_cs_code_directory_t**)sig_obj);
292 
293 	if (ret != KERN_SUCCESS) {
294 		return ret;
295 	}
296 	cd_entry = *((pmap_cs_code_directory_t**)sig_obj);
297 
298 	if (ppl_signature_addr) {
299 		*ppl_signature_addr = (vm_address_t)cd_entry->superblob;
300 	}
301 
302 	return KERN_SUCCESS;
303 }
304 
305 kern_return_t
ppl_unregister_code_signature(void * sig_obj)306 ppl_unregister_code_signature(
307 	void *sig_obj)
308 {
309 	return pmap_cs_unregister_code_signature_blob(sig_obj);
310 }
311 
312 kern_return_t
ppl_verify_code_signature(void * sig_obj,uint32_t * trust_level)313 ppl_verify_code_signature(
314 	void *sig_obj,
315 	uint32_t *trust_level)
316 {
317 	kern_return_t ret = pmap_cs_verify_code_signature_blob(sig_obj);
318 
319 	if ((ret == KERN_SUCCESS) && (trust_level != NULL)) {
320 		*trust_level = ((struct pmap_cs_code_directory*)sig_obj)->trust;
321 	}
322 	return ret;
323 }
324 
325 kern_return_t
ppl_reconstitute_code_signature(void * sig_obj,vm_address_t * unneeded_addr,vm_size_t * unneeded_size)326 ppl_reconstitute_code_signature(
327 	void *sig_obj,
328 	vm_address_t *unneeded_addr,
329 	vm_size_t *unneeded_size)
330 {
331 	return pmap_cs_unlock_unneeded_code_signature(
332 		sig_obj,
333 		unneeded_addr,
334 		unneeded_size);
335 }
336 
337 #pragma mark Address Spaces
338 
339 kern_return_t
ppl_setup_nested_address_space(__unused pmap_t pmap,__unused const vm_address_t region_addr,__unused const vm_size_t region_size)340 ppl_setup_nested_address_space(
341 	__unused pmap_t pmap,
342 	__unused const vm_address_t region_addr,
343 	__unused const vm_size_t region_size)
344 {
345 	/*
346 	 * We don't need to do anything here from the code-signing-monitor's perspective
347 	 * because the PMAP's base address fields are setup when someone eventually calls
348 	 * pmap_nest on the PMAP object.
349 	 */
350 	return KERN_SUCCESS;
351 }
352 
353 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)354 ppl_associate_code_signature(
355 	pmap_t pmap,
356 	void *sig_obj,
357 	const vm_address_t region_addr,
358 	const vm_size_t region_size,
359 	const vm_offset_t region_offset)
360 {
361 	return pmap_cs_associate(
362 		pmap,
363 		sig_obj,
364 		region_addr,
365 		region_size,
366 		region_offset);
367 }
368 
369 kern_return_t
ppl_allow_jit_region(__unused pmap_t pmap)370 ppl_allow_jit_region(
371 	__unused pmap_t pmap)
372 {
373 	/* PPL does not support this API */
374 	return KERN_NOT_SUPPORTED;
375 }
376 
377 kern_return_t
ppl_associate_jit_region(pmap_t pmap,const vm_address_t region_addr,const vm_size_t region_size)378 ppl_associate_jit_region(
379 	pmap_t pmap,
380 	const vm_address_t region_addr,
381 	const vm_size_t region_size)
382 {
383 	return pmap_cs_associate(
384 		pmap,
385 		PMAP_CS_ASSOCIATE_JIT,
386 		region_addr,
387 		region_size,
388 		0);
389 }
390 
391 kern_return_t
ppl_associate_debug_region(pmap_t pmap,const vm_address_t region_addr,const vm_size_t region_size)392 ppl_associate_debug_region(
393 	pmap_t pmap,
394 	const vm_address_t region_addr,
395 	const vm_size_t region_size)
396 {
397 	bool debugger_mapping = false;
398 
399 	/*
400 	 * Check that the debug association is coming from a debugger and not just
401 	 * any application. If it isn't a debugger, then the debug association is not
402 	 * allowed. This isn't a strong security requirement, so we don't need to
403 	 * perform this check within the PPL proper.
404 	 *
405 	 * When the region_addr is PAGE_SIZE, then we're not actually creating any
406 	 * debug mappings, we're just trying to check if the address space can be or
407 	 * has been marked as debugged or not.
408 	 */
409 	if (region_addr != PAGE_SIZE) {
410 		if (IOCurrentTaskHasEntitlement("com.apple.private.cs.debugger") == true) {
411 			debugger_mapping = true;
412 		}
413 	} else {
414 		debugger_mapping = true;
415 	}
416 
417 #if DEVELOPMENT || DEBUG
418 	code_signing_config_t cs_config = 0;
419 	code_signing_configuration(NULL, &cs_config);
420 	if ((cs_config & CS_CONFIG_UNRESTRICTED_DEBUGGING) != 0) {
421 		debugger_mapping = true;
422 	}
423 #endif
424 
425 	if (debugger_mapping == false) {
426 		printf("disallowed non-debugger initiated debug mapping\n");
427 		return KERN_DENIED;
428 	}
429 
430 	return pmap_cs_associate(
431 		pmap,
432 		PMAP_CS_ASSOCIATE_COW,
433 		region_addr,
434 		region_size,
435 		0);
436 }
437 
438 kern_return_t
ppl_address_space_debugged(pmap_t pmap)439 ppl_address_space_debugged(
440 	pmap_t pmap)
441 {
442 	/*
443 	 * ppl_associate_debug_region is a fairly idempotent function which simply
444 	 * checks if an address space is already debugged or not and returns a value
445 	 * based on that. The actual memory region is not inserted into the address
446 	 * space, so we can pass whatever in this case. The only caveat here though
447 	 * is that the memory region needs to be page-aligned and cannot be NULL.
448 	 */
449 	return ppl_associate_debug_region(pmap, PAGE_SIZE, PAGE_SIZE);
450 }
451 
452 kern_return_t
ppl_allow_invalid_code(pmap_t pmap)453 ppl_allow_invalid_code(
454 	pmap_t pmap)
455 {
456 	return pmap_cs_allow_invalid(pmap);
457 }
458 
459 kern_return_t
ppl_get_trust_level_kdp(pmap_t pmap,uint32_t * trust_level)460 ppl_get_trust_level_kdp(
461 	pmap_t pmap,
462 	uint32_t *trust_level)
463 {
464 	return pmap_get_trust_level_kdp(pmap, trust_level);
465 }
466 
467 kern_return_t
ppl_get_jit_address_range_kdp(pmap_t pmap,uintptr_t * jit_region_start,uintptr_t * jit_region_end)468 ppl_get_jit_address_range_kdp(
469 	pmap_t pmap,
470 	uintptr_t *jit_region_start,
471 	uintptr_t *jit_region_end)
472 {
473 	return pmap_get_jit_address_range_kdp(pmap, jit_region_start, jit_region_end);
474 }
475 
476 kern_return_t
ppl_address_space_exempt(const pmap_t pmap)477 ppl_address_space_exempt(
478 	const pmap_t pmap)
479 {
480 	if (pmap_performs_stage2_translations(pmap) == true) {
481 		return KERN_SUCCESS;
482 	}
483 
484 	return KERN_DENIED;
485 }
486 
487 kern_return_t
ppl_fork_prepare(pmap_t old_pmap,pmap_t new_pmap)488 ppl_fork_prepare(
489 	pmap_t old_pmap,
490 	pmap_t new_pmap)
491 {
492 	return pmap_cs_fork_prepare(old_pmap, new_pmap);
493 }
494 
495 kern_return_t
ppl_acquire_signing_identifier(const void * sig_obj,const char ** signing_id)496 ppl_acquire_signing_identifier(
497 	const void *sig_obj,
498 	const char **signing_id)
499 {
500 	const pmap_cs_code_directory_t *cd_entry = sig_obj;
501 
502 	/* If we reach here, the identifier must have been setup */
503 	assert(cd_entry->identifier != NULL);
504 
505 	if (signing_id) {
506 		*signing_id = cd_entry->identifier;
507 	}
508 
509 	return KERN_SUCCESS;
510 }
511 
512 #pragma mark Entitlements
513 
514 kern_return_t
ppl_associate_kernel_entitlements(void * sig_obj,const void * kernel_entitlements)515 ppl_associate_kernel_entitlements(
516 	void *sig_obj,
517 	const void *kernel_entitlements)
518 {
519 	pmap_cs_code_directory_t *cd_entry = sig_obj;
520 	return pmap_associate_kernel_entitlements(cd_entry, kernel_entitlements);
521 }
522 
523 kern_return_t
ppl_resolve_kernel_entitlements(pmap_t pmap,const void ** kernel_entitlements)524 ppl_resolve_kernel_entitlements(
525 	pmap_t pmap,
526 	const void **kernel_entitlements)
527 {
528 	kern_return_t ret = KERN_DENIED;
529 	const void *entitlements = NULL;
530 
531 	ret = pmap_resolve_kernel_entitlements(pmap, &entitlements);
532 	if ((ret == KERN_SUCCESS) && (kernel_entitlements != NULL)) {
533 		*kernel_entitlements = entitlements;
534 	}
535 
536 	return ret;
537 }
538 
539 kern_return_t
ppl_accelerate_entitlements(void * sig_obj,CEQueryContext_t * ce_ctx)540 ppl_accelerate_entitlements(
541 	void *sig_obj,
542 	CEQueryContext_t *ce_ctx)
543 {
544 	pmap_cs_code_directory_t *cd_entry = sig_obj;
545 	kern_return_t ret = KERN_DENIED;
546 
547 	ret = pmap_accelerate_entitlements(cd_entry);
548 
549 	/*
550 	 * We only ever get KERN_ABORTED when we cannot accelerate the entitlements
551 	 * because it would consume too much memory. In this case, we still want to
552 	 * return the ce_ctx since we don't want the system to fall-back to non-PPL
553 	 * locked down memory, so we switch this to a success case.
554 	 */
555 	if (ret == KERN_ABORTED) {
556 		ret = KERN_SUCCESS;
557 	}
558 
559 	/* Return the accelerated context to the caller */
560 	if ((ret == KERN_SUCCESS) && (ce_ctx != NULL)) {
561 		*ce_ctx = cd_entry->ce_ctx;
562 	}
563 
564 	return ret;
565 }
566 
567 #pragma mark Image4
568 
569 void*
ppl_image4_storage_data(size_t * allocated_size)570 ppl_image4_storage_data(
571 	size_t *allocated_size)
572 {
573 	return pmap_image4_pmap_data(allocated_size);
574 }
575 
576 void
ppl_image4_set_nonce(const img4_nonce_domain_index_t ndi,const img4_nonce_t * nonce)577 ppl_image4_set_nonce(
578 	const img4_nonce_domain_index_t ndi,
579 	const img4_nonce_t *nonce)
580 {
581 	return pmap_image4_set_nonce(ndi, nonce);
582 }
583 
584 void
ppl_image4_roll_nonce(const img4_nonce_domain_index_t ndi)585 ppl_image4_roll_nonce(
586 	const img4_nonce_domain_index_t ndi)
587 {
588 	return pmap_image4_roll_nonce(ndi);
589 }
590 
591 errno_t
ppl_image4_copy_nonce(const img4_nonce_domain_index_t ndi,img4_nonce_t * nonce_out)592 ppl_image4_copy_nonce(
593 	const img4_nonce_domain_index_t ndi,
594 	img4_nonce_t *nonce_out)
595 {
596 	return pmap_image4_copy_nonce(ndi, nonce_out);
597 }
598 
599 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)600 ppl_image4_execute_object(
601 	img4_runtime_object_spec_index_t obj_spec_index,
602 	const img4_buff_t *payload,
603 	const img4_buff_t *manifest)
604 {
605 	errno_t err = EINVAL;
606 	kern_return_t kr = KERN_DENIED;
607 	img4_buff_t payload_aligned = IMG4_BUFF_INIT;
608 	img4_buff_t manifest_aligned = IMG4_BUFF_INIT;
609 	vm_address_t payload_addr = 0;
610 	vm_size_t payload_len_aligned = 0;
611 	vm_address_t manifest_addr = 0;
612 	vm_size_t manifest_len_aligned = 0;
613 
614 	if (payload == NULL) {
615 		printf("invalid object execution request: no payload\n");
616 		goto out;
617 	}
618 
619 	/*
620 	 * The PPL will attempt to lockdown both the payload and the manifest before executing
621 	 * the object. In order for that to happen, both the artifacts need to be page-aligned.
622 	 */
623 	payload_len_aligned = round_page(payload->i4b_len);
624 	if (manifest != NULL) {
625 		manifest_len_aligned = round_page(manifest->i4b_len);
626 	}
627 
628 	kr = kmem_alloc(
629 		kernel_map,
630 		&payload_addr,
631 		payload_len_aligned,
632 		KMA_KOBJECT,
633 		VM_KERN_MEMORY_SECURITY);
634 
635 	if (kr != KERN_SUCCESS) {
636 		printf("unable to allocate memory for image4 payload: %d\n", kr);
637 		err = ENOMEM;
638 		goto out;
639 	}
640 
641 	/* Copy in the payload */
642 	memcpy((uint8_t*)payload_addr, payload->i4b_bytes, payload->i4b_len);
643 
644 	/* Construct the aligned payload buffer */
645 	payload_aligned.i4b_bytes = (uint8_t*)payload_addr;
646 	payload_aligned.i4b_len = payload->i4b_len;
647 
648 	if (manifest != NULL) {
649 		kr = kmem_alloc(
650 			kernel_map,
651 			&manifest_addr,
652 			manifest_len_aligned,
653 			KMA_KOBJECT,
654 			VM_KERN_MEMORY_SECURITY);
655 
656 		if (kr != KERN_SUCCESS) {
657 			printf("unable to allocate memory for image4 manifest: %d\n", kr);
658 			err = ENOMEM;
659 			goto out;
660 		}
661 
662 		/* Construct the aligned manifest buffer */
663 		manifest_aligned.i4b_bytes = (uint8_t*)manifest_addr;
664 		manifest_aligned.i4b_len = manifest->i4b_len;
665 
666 		/* Copy in the manifest */
667 		memcpy((uint8_t*)manifest_addr, manifest->i4b_bytes, manifest->i4b_len);
668 	}
669 
670 	err = pmap_image4_execute_object(obj_spec_index, &payload_aligned, &manifest_aligned);
671 	if (err != 0) {
672 		printf("unable to execute image4 object: %d\n", err);
673 		goto out;
674 	}
675 
676 out:
677 	/* We always free the manifest as it isn't required anymore */
678 	if (manifest_addr != 0) {
679 		kmem_free(kernel_map, manifest_addr, manifest_len_aligned);
680 		manifest_addr = 0;
681 		manifest_len_aligned = 0;
682 	}
683 
684 	/* If we encountered an error -- free the allocated payload */
685 	if ((err != 0) && (payload_addr != 0)) {
686 		kmem_free(kernel_map, payload_addr, payload_len_aligned);
687 		payload_addr = 0;
688 		payload_len_aligned = 0;
689 	}
690 
691 	return err;
692 }
693 
694 errno_t
ppl_image4_copy_object(img4_runtime_object_spec_index_t obj_spec_index,vm_address_t object_out,size_t * object_length)695 ppl_image4_copy_object(
696 	img4_runtime_object_spec_index_t obj_spec_index,
697 	vm_address_t object_out,
698 	size_t *object_length)
699 {
700 	errno_t err = EINVAL;
701 	kern_return_t kr = KERN_DENIED;
702 	vm_address_t object_addr = 0;
703 	vm_size_t object_len_aligned = 0;
704 
705 	if (object_out == 0) {
706 		printf("invalid object copy request: no object input buffer\n");
707 		goto out;
708 	} else if (object_length == NULL) {
709 		printf("invalid object copy request: no object input length\n");
710 		goto out;
711 	}
712 
713 	/*
714 	 * The PPL will attempt to pin the input buffer in order to ensure that the kernel
715 	 * didn't pass in PPL-owned buffers. The PPL cannot pin the same page more than once,
716 	 * and attempting to do so will panic the system. Hence, we allocate fresh pages for
717 	 * for the PPL to pin.
718 	 *
719 	 * We can send in the address for the length pointer since that is allocated on the
720 	 * stack, so the PPL can pin our stack for the duration of the call as no other
721 	 * thread can be using our stack, meaning the PPL will never attempt to double-pin
722 	 * the page.
723 	 */
724 	object_len_aligned = round_page(*object_length);
725 
726 	kr = kmem_alloc(
727 		kernel_map,
728 		&object_addr,
729 		object_len_aligned,
730 		KMA_KOBJECT,
731 		VM_KERN_MEMORY_SECURITY);
732 
733 	if (kr != KERN_SUCCESS) {
734 		printf("unable to allocate memory for image4 object: %d\n", kr);
735 		err = ENOMEM;
736 		goto out;
737 	}
738 
739 	err = pmap_image4_copy_object(obj_spec_index, object_addr, object_length);
740 	if (err != 0) {
741 		printf("unable to copy image4 object: %d\n", err);
742 		goto out;
743 	}
744 
745 	/* Copy the data back into the caller passed buffer */
746 	memcpy((void*)object_out, (void*)object_addr, *object_length);
747 
748 out:
749 	/* We don't ever need to keep around our page-aligned buffer */
750 	if (object_addr != 0) {
751 		kmem_free(kernel_map, object_addr, object_len_aligned);
752 		object_addr = 0;
753 		object_len_aligned = 0;
754 	}
755 
756 	return err;
757 }
758 
759 const void*
ppl_image4_get_monitor_exports(void)760 ppl_image4_get_monitor_exports(void)
761 {
762 	/*
763 	 * AppleImage4 can query the PMAP_CS runtime on its own since the PMAP_CS
764 	 * runtime is compiled within the kernel extension itself. As a result, we
765 	 * never expect this KPI to be called when the system uses the PPL monitor.
766 	 */
767 
768 	printf("explicit monitor-exports-get not required for the PPL\n");
769 	return NULL;
770 }
771 
772 errno_t
ppl_image4_set_release_type(__unused const char * release_type)773 ppl_image4_set_release_type(
774 	__unused const char *release_type)
775 {
776 	/*
777 	 * AppleImage4 stores the release type in the CTRR protected memory region
778 	 * of its kernel extension. This is accessible by the PMAP_CS runtime as the
779 	 * runtime is compiled alongside the kernel extension. As a result, we never
780 	 * expect this KPI to be called when the system uses the PPL monitor.
781 	 */
782 
783 	printf("explicit release-type-set set not required for the PPL\n");
784 	return ENOTSUP;
785 }
786 
787 errno_t
ppl_image4_set_bnch_shadow(__unused const img4_nonce_domain_index_t ndi)788 ppl_image4_set_bnch_shadow(
789 	__unused const img4_nonce_domain_index_t ndi)
790 {
791 	/*
792 	 * AppleImage4 stores the BNCH shadow in the CTRR protected memory region
793 	 * of its kernel extension. This is accessible by the PMAP_CS runtime as the
794 	 * runtime is compiled alongside the kernel extension. As a result, we never
795 	 * expect this KPI to be called when the system uses the PPL monitor.
796 	 */
797 
798 	printf("explicit BNCH-shadow-set not required for the PPL\n");
799 	return ENOTSUP;
800 }
801 
802 #pragma mark Image4 - New
803 
804 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)805 ppl_image4_transfer_region(
806 	__unused image4_cs_trap_t selector,
807 	__unused vm_address_t region_addr,
808 	__unused vm_size_t region_size)
809 {
810 	/* All regions transfers happen internally with the PPL */
811 	return KERN_SUCCESS;
812 }
813 
814 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)815 ppl_image4_reclaim_region(
816 	__unused image4_cs_trap_t selector,
817 	__unused vm_address_t region_addr,
818 	__unused vm_size_t region_size)
819 {
820 	/* All regions transfers happen internally with the PPL */
821 	return KERN_SUCCESS;
822 }
823 
824 errno_t
ppl_image4_monitor_trap(image4_cs_trap_t selector,const void * input_data,size_t input_size)825 ppl_image4_monitor_trap(
826 	image4_cs_trap_t selector,
827 	const void *input_data,
828 	size_t input_size)
829 {
830 	return pmap_image4_monitor_trap(selector, input_data, input_size);
831 }
832 
833 #endif /* PMAP_CS_PPL_MONITOR */
834