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_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)340 ppl_associate_code_signature(
341 pmap_t pmap,
342 void *sig_obj,
343 const vm_address_t region_addr,
344 const vm_size_t region_size,
345 const vm_offset_t region_offset)
346 {
347 return pmap_cs_associate(
348 pmap,
349 sig_obj,
350 region_addr,
351 region_size,
352 region_offset);
353 }
354
355 kern_return_t
ppl_allow_jit_region(__unused pmap_t pmap)356 ppl_allow_jit_region(
357 __unused pmap_t pmap)
358 {
359 /* PPL does not support this API */
360 return KERN_NOT_SUPPORTED;
361 }
362
363 kern_return_t
ppl_associate_jit_region(pmap_t pmap,const vm_address_t region_addr,const vm_size_t region_size)364 ppl_associate_jit_region(
365 pmap_t pmap,
366 const vm_address_t region_addr,
367 const vm_size_t region_size)
368 {
369 return pmap_cs_associate(
370 pmap,
371 PMAP_CS_ASSOCIATE_JIT,
372 region_addr,
373 region_size,
374 0);
375 }
376
377 kern_return_t
ppl_associate_debug_region(pmap_t pmap,const vm_address_t region_addr,const vm_size_t region_size)378 ppl_associate_debug_region(
379 pmap_t pmap,
380 const vm_address_t region_addr,
381 const vm_size_t region_size)
382 {
383 volatile bool force_true = true;
384 bool debugger_mapping = false;
385
386 /*
387 * Check that the debug association is coming from a debugger and not just
388 * any application. If it isn't a debugger, then the debug association is not
389 * allowed. This isn't a strong security requirement, so we don't need to
390 * perform this check within the PPL proper.
391 *
392 * When the region_addr is PAGE_SIZE, then we're not actually creating any
393 * debug mappings, we're just trying to check if the address space can be or
394 * has been marked as debugged or not.
395 */
396 if (region_addr != PAGE_SIZE) {
397 if (IOCurrentTaskHasEntitlement("com.apple.private.cs.debugger") == true) {
398 debugger_mapping = true;
399 }
400 } else {
401 debugger_mapping = true;
402 }
403
404 #if DEVELOPMENT || DEBUG
405 code_signing_config_t cs_config = 0;
406 code_signing_configuration(NULL, &cs_config);
407 if ((cs_config & CS_CONFIG_UNRESTRICTED_DEBUGGING) != 0) {
408 debugger_mapping = true;
409 }
410 #endif
411
412 /*
413 * For now, we're just going to revert back to our previous policy and continue
414 * to allow a debugger mapped to be created by a process on its own.
415 *
416 * For more information: rdar://145588999.
417 */
418 if (force_true == true) {
419 debugger_mapping = true;
420 }
421
422 if (debugger_mapping == false) {
423 printf("disallowed non-debugger initiated debug mapping\n");
424 return KERN_DENIED;
425 }
426
427 return pmap_cs_associate(
428 pmap,
429 PMAP_CS_ASSOCIATE_COW,
430 region_addr,
431 region_size,
432 0);
433 }
434
435 kern_return_t
ppl_address_space_debugged(pmap_t pmap)436 ppl_address_space_debugged(
437 pmap_t pmap)
438 {
439 /*
440 * ppl_associate_debug_region is a fairly idempotent function which simply
441 * checks if an address space is already debugged or not and returns a value
442 * based on that. The actual memory region is not inserted into the address
443 * space, so we can pass whatever in this case. The only caveat here though
444 * is that the memory region needs to be page-aligned and cannot be NULL.
445 */
446 return ppl_associate_debug_region(pmap, PAGE_SIZE, PAGE_SIZE);
447 }
448
449 kern_return_t
ppl_allow_invalid_code(pmap_t pmap)450 ppl_allow_invalid_code(
451 pmap_t pmap)
452 {
453 return pmap_cs_allow_invalid(pmap);
454 }
455
456 kern_return_t
ppl_get_trust_level_kdp(pmap_t pmap,uint32_t * trust_level)457 ppl_get_trust_level_kdp(
458 pmap_t pmap,
459 uint32_t *trust_level)
460 {
461 return pmap_get_trust_level_kdp(pmap, trust_level);
462 }
463
464 kern_return_t
ppl_get_jit_address_range_kdp(pmap_t pmap,uintptr_t * jit_region_start,uintptr_t * jit_region_end)465 ppl_get_jit_address_range_kdp(
466 pmap_t pmap,
467 uintptr_t *jit_region_start,
468 uintptr_t *jit_region_end)
469 {
470 return pmap_get_jit_address_range_kdp(pmap, jit_region_start, jit_region_end);
471 }
472
473 kern_return_t
ppl_address_space_exempt(const pmap_t pmap)474 ppl_address_space_exempt(
475 const pmap_t pmap)
476 {
477 if (pmap_performs_stage2_translations(pmap) == true) {
478 return KERN_SUCCESS;
479 }
480
481 return KERN_DENIED;
482 }
483
484 kern_return_t
ppl_fork_prepare(pmap_t old_pmap,pmap_t new_pmap)485 ppl_fork_prepare(
486 pmap_t old_pmap,
487 pmap_t new_pmap)
488 {
489 return pmap_cs_fork_prepare(old_pmap, new_pmap);
490 }
491
492 kern_return_t
ppl_acquire_signing_identifier(const void * sig_obj,const char ** signing_id)493 ppl_acquire_signing_identifier(
494 const void *sig_obj,
495 const char **signing_id)
496 {
497 const pmap_cs_code_directory_t *cd_entry = sig_obj;
498
499 /* If we reach here, the identifier must have been setup */
500 assert(cd_entry->identifier != NULL);
501
502 if (signing_id) {
503 *signing_id = cd_entry->identifier;
504 }
505
506 return KERN_SUCCESS;
507 }
508
509 #pragma mark Entitlements
510
511 kern_return_t
ppl_associate_kernel_entitlements(void * sig_obj,const void * kernel_entitlements)512 ppl_associate_kernel_entitlements(
513 void *sig_obj,
514 const void *kernel_entitlements)
515 {
516 pmap_cs_code_directory_t *cd_entry = sig_obj;
517 return pmap_associate_kernel_entitlements(cd_entry, kernel_entitlements);
518 }
519
520 kern_return_t
ppl_resolve_kernel_entitlements(pmap_t pmap,const void ** kernel_entitlements)521 ppl_resolve_kernel_entitlements(
522 pmap_t pmap,
523 const void **kernel_entitlements)
524 {
525 kern_return_t ret = KERN_DENIED;
526 const void *entitlements = NULL;
527
528 ret = pmap_resolve_kernel_entitlements(pmap, &entitlements);
529 if ((ret == KERN_SUCCESS) && (kernel_entitlements != NULL)) {
530 *kernel_entitlements = entitlements;
531 }
532
533 return ret;
534 }
535
536 kern_return_t
ppl_accelerate_entitlements(void * sig_obj,CEQueryContext_t * ce_ctx)537 ppl_accelerate_entitlements(
538 void *sig_obj,
539 CEQueryContext_t *ce_ctx)
540 {
541 pmap_cs_code_directory_t *cd_entry = sig_obj;
542 kern_return_t ret = KERN_DENIED;
543
544 ret = pmap_accelerate_entitlements(cd_entry);
545
546 /*
547 * We only ever get KERN_ABORTED when we cannot accelerate the entitlements
548 * because it would consume too much memory. In this case, we still want to
549 * return the ce_ctx since we don't want the system to fall-back to non-PPL
550 * locked down memory, so we switch this to a success case.
551 */
552 if (ret == KERN_ABORTED) {
553 ret = KERN_SUCCESS;
554 }
555
556 /* Return the accelerated context to the caller */
557 if ((ret == KERN_SUCCESS) && (ce_ctx != NULL)) {
558 *ce_ctx = cd_entry->ce_ctx;
559 }
560
561 return ret;
562 }
563
564 #pragma mark Image4
565
566 void*
ppl_image4_storage_data(size_t * allocated_size)567 ppl_image4_storage_data(
568 size_t *allocated_size)
569 {
570 return pmap_image4_pmap_data(allocated_size);
571 }
572
573 void
ppl_image4_set_nonce(const img4_nonce_domain_index_t ndi,const img4_nonce_t * nonce)574 ppl_image4_set_nonce(
575 const img4_nonce_domain_index_t ndi,
576 const img4_nonce_t *nonce)
577 {
578 return pmap_image4_set_nonce(ndi, nonce);
579 }
580
581 void
ppl_image4_roll_nonce(const img4_nonce_domain_index_t ndi)582 ppl_image4_roll_nonce(
583 const img4_nonce_domain_index_t ndi)
584 {
585 return pmap_image4_roll_nonce(ndi);
586 }
587
588 errno_t
ppl_image4_copy_nonce(const img4_nonce_domain_index_t ndi,img4_nonce_t * nonce_out)589 ppl_image4_copy_nonce(
590 const img4_nonce_domain_index_t ndi,
591 img4_nonce_t *nonce_out)
592 {
593 return pmap_image4_copy_nonce(ndi, nonce_out);
594 }
595
596 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)597 ppl_image4_execute_object(
598 img4_runtime_object_spec_index_t obj_spec_index,
599 const img4_buff_t *payload,
600 const img4_buff_t *manifest)
601 {
602 errno_t err = EINVAL;
603 kern_return_t kr = KERN_DENIED;
604 img4_buff_t payload_aligned = IMG4_BUFF_INIT;
605 img4_buff_t manifest_aligned = IMG4_BUFF_INIT;
606 vm_address_t payload_addr = 0;
607 vm_size_t payload_len_aligned = 0;
608 vm_address_t manifest_addr = 0;
609 vm_size_t manifest_len_aligned = 0;
610
611 if (payload == NULL) {
612 printf("invalid object execution request: no payload\n");
613 goto out;
614 }
615
616 /*
617 * The PPL will attempt to lockdown both the payload and the manifest before executing
618 * the object. In order for that to happen, both the artifacts need to be page-aligned.
619 */
620 payload_len_aligned = round_page(payload->i4b_len);
621 if (manifest != NULL) {
622 manifest_len_aligned = round_page(manifest->i4b_len);
623 }
624
625 kr = kmem_alloc(
626 kernel_map,
627 &payload_addr,
628 payload_len_aligned,
629 KMA_KOBJECT,
630 VM_KERN_MEMORY_SECURITY);
631
632 if (kr != KERN_SUCCESS) {
633 printf("unable to allocate memory for image4 payload: %d\n", kr);
634 err = ENOMEM;
635 goto out;
636 }
637
638 /* Copy in the payload */
639 memcpy((uint8_t*)payload_addr, payload->i4b_bytes, payload->i4b_len);
640
641 /* Construct the aligned payload buffer */
642 payload_aligned.i4b_bytes = (uint8_t*)payload_addr;
643 payload_aligned.i4b_len = payload->i4b_len;
644
645 if (manifest != NULL) {
646 kr = kmem_alloc(
647 kernel_map,
648 &manifest_addr,
649 manifest_len_aligned,
650 KMA_KOBJECT,
651 VM_KERN_MEMORY_SECURITY);
652
653 if (kr != KERN_SUCCESS) {
654 printf("unable to allocate memory for image4 manifest: %d\n", kr);
655 err = ENOMEM;
656 goto out;
657 }
658
659 /* Construct the aligned manifest buffer */
660 manifest_aligned.i4b_bytes = (uint8_t*)manifest_addr;
661 manifest_aligned.i4b_len = manifest->i4b_len;
662
663 /* Copy in the manifest */
664 memcpy((uint8_t*)manifest_addr, manifest->i4b_bytes, manifest->i4b_len);
665 }
666
667 err = pmap_image4_execute_object(obj_spec_index, &payload_aligned, &manifest_aligned);
668 if (err != 0) {
669 printf("unable to execute image4 object: %d\n", err);
670 goto out;
671 }
672
673 out:
674 /* We always free the manifest as it isn't required anymore */
675 if (manifest_addr != 0) {
676 kmem_free(kernel_map, manifest_addr, manifest_len_aligned);
677 manifest_addr = 0;
678 manifest_len_aligned = 0;
679 }
680
681 /* If we encountered an error -- free the allocated payload */
682 if ((err != 0) && (payload_addr != 0)) {
683 kmem_free(kernel_map, payload_addr, payload_len_aligned);
684 payload_addr = 0;
685 payload_len_aligned = 0;
686 }
687
688 return err;
689 }
690
691 errno_t
ppl_image4_copy_object(img4_runtime_object_spec_index_t obj_spec_index,vm_address_t object_out,size_t * object_length)692 ppl_image4_copy_object(
693 img4_runtime_object_spec_index_t obj_spec_index,
694 vm_address_t object_out,
695 size_t *object_length)
696 {
697 errno_t err = EINVAL;
698 kern_return_t kr = KERN_DENIED;
699 vm_address_t object_addr = 0;
700 vm_size_t object_len_aligned = 0;
701
702 if (object_out == 0) {
703 printf("invalid object copy request: no object input buffer\n");
704 goto out;
705 } else if (object_length == NULL) {
706 printf("invalid object copy request: no object input length\n");
707 goto out;
708 }
709
710 /*
711 * The PPL will attempt to pin the input buffer in order to ensure that the kernel
712 * didn't pass in PPL-owned buffers. The PPL cannot pin the same page more than once,
713 * and attempting to do so will panic the system. Hence, we allocate fresh pages for
714 * for the PPL to pin.
715 *
716 * We can send in the address for the length pointer since that is allocated on the
717 * stack, so the PPL can pin our stack for the duration of the call as no other
718 * thread can be using our stack, meaning the PPL will never attempt to double-pin
719 * the page.
720 */
721 object_len_aligned = round_page(*object_length);
722
723 kr = kmem_alloc(
724 kernel_map,
725 &object_addr,
726 object_len_aligned,
727 KMA_KOBJECT,
728 VM_KERN_MEMORY_SECURITY);
729
730 if (kr != KERN_SUCCESS) {
731 printf("unable to allocate memory for image4 object: %d\n", kr);
732 err = ENOMEM;
733 goto out;
734 }
735
736 err = pmap_image4_copy_object(obj_spec_index, object_addr, object_length);
737 if (err != 0) {
738 printf("unable to copy image4 object: %d\n", err);
739 goto out;
740 }
741
742 /* Copy the data back into the caller passed buffer */
743 memcpy((void*)object_out, (void*)object_addr, *object_length);
744
745 out:
746 /* We don't ever need to keep around our page-aligned buffer */
747 if (object_addr != 0) {
748 kmem_free(kernel_map, object_addr, object_len_aligned);
749 object_addr = 0;
750 object_len_aligned = 0;
751 }
752
753 return err;
754 }
755
756 const void*
ppl_image4_get_monitor_exports(void)757 ppl_image4_get_monitor_exports(void)
758 {
759 /*
760 * AppleImage4 can query the PMAP_CS runtime on its own since the PMAP_CS
761 * runtime is compiled within the kernel extension itself. As a result, we
762 * never expect this KPI to be called when the system uses the PPL monitor.
763 */
764
765 printf("explicit monitor-exports-get not required for the PPL\n");
766 return NULL;
767 }
768
769 errno_t
ppl_image4_set_release_type(__unused const char * release_type)770 ppl_image4_set_release_type(
771 __unused const char *release_type)
772 {
773 /*
774 * AppleImage4 stores the release type in the CTRR protected memory region
775 * of its kernel extension. This is accessible by the PMAP_CS runtime as the
776 * runtime is compiled alongside the kernel extension. As a result, we never
777 * expect this KPI to be called when the system uses the PPL monitor.
778 */
779
780 printf("explicit release-type-set set not required for the PPL\n");
781 return ENOTSUP;
782 }
783
784 errno_t
ppl_image4_set_bnch_shadow(__unused const img4_nonce_domain_index_t ndi)785 ppl_image4_set_bnch_shadow(
786 __unused const img4_nonce_domain_index_t ndi)
787 {
788 /*
789 * AppleImage4 stores the BNCH shadow in the CTRR protected memory region
790 * of its kernel extension. This is accessible by the PMAP_CS runtime as the
791 * runtime is compiled alongside the kernel extension. As a result, we never
792 * expect this KPI to be called when the system uses the PPL monitor.
793 */
794
795 printf("explicit BNCH-shadow-set not required for the PPL\n");
796 return ENOTSUP;
797 }
798
799 #pragma mark Image4 - New
800
801 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)802 ppl_image4_transfer_region(
803 __unused image4_cs_trap_t selector,
804 __unused vm_address_t region_addr,
805 __unused vm_size_t region_size)
806 {
807 /* All regions transfers happen internally with the PPL */
808 return KERN_SUCCESS;
809 }
810
811 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)812 ppl_image4_reclaim_region(
813 __unused image4_cs_trap_t selector,
814 __unused vm_address_t region_addr,
815 __unused vm_size_t region_size)
816 {
817 /* All regions transfers happen internally with the PPL */
818 return KERN_SUCCESS;
819 }
820
821 errno_t
ppl_image4_monitor_trap(image4_cs_trap_t selector,const void * input_data,size_t input_size)822 ppl_image4_monitor_trap(
823 image4_cs_trap_t selector,
824 const void *input_data,
825 size_t input_size)
826 {
827 return pmap_image4_monitor_trap(selector, input_data, input_size);
828 }
829
830 #endif /* PMAP_CS_PPL_MONITOR */
831