]> git.saurik.com Git - apple/xnu.git/blob - bsd/kern/kern_cs.c
xnu-7195.101.1.tar.gz
[apple/xnu.git] / bsd / kern / kern_cs.c
1 /*
2 * Copyright (c) 2000-2012 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29 #include <sys/types.h>
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/kernel.h>
33 #include <sys/proc_internal.h>
34 #include <sys/sysctl.h>
35 #include <sys/signal.h>
36 #include <sys/signalvar.h>
37 #include <sys/codesign.h>
38
39 #include <sys/fcntl.h>
40 #include <sys/file.h>
41 #include <sys/file_internal.h>
42 #include <sys/kauth.h>
43 #include <sys/mount.h>
44 #include <sys/msg.h>
45 #include <sys/proc.h>
46 #include <sys/socketvar.h>
47 #include <sys/vnode.h>
48 #include <sys/vnode_internal.h>
49
50 #include <sys/ubc.h>
51 #include <sys/ubc_internal.h>
52
53 #include <security/mac.h>
54 #include <security/mac_policy.h>
55 #include <security/mac_framework.h>
56
57 #include <mach/mach_types.h>
58 #include <mach/vm_map.h>
59 #include <mach/mach_vm.h>
60
61 #include <kern/kern_types.h>
62 #include <kern/startup.h>
63 #include <kern/task.h>
64
65 #include <vm/vm_map.h>
66 #include <vm/pmap.h>
67 #include <vm/vm_kern.h>
68
69
70 #include <kern/assert.h>
71
72 #include <pexpert/pexpert.h>
73
74 #include <mach/shared_region.h>
75
76 #include <libkern/section_keywords.h>
77 #include <libkern/ptrauth_utils.h>
78
79
80 unsigned long cs_procs_killed = 0;
81 unsigned long cs_procs_invalidated = 0;
82
83 int cs_force_kill = 0;
84 int cs_force_hard = 0;
85 int cs_debug = 0;
86 // If set, AMFI will error out early on unsigned code, before evaluation the normal policy.
87 int cs_debug_fail_on_unsigned_code = 0;
88 // If the previous mode is enabled, we count the resulting failures here.
89 unsigned int cs_debug_unsigned_exec_failures = 0;
90 unsigned int cs_debug_unsigned_mmap_failures = 0;
91
92 #if CONFIG_ENFORCE_SIGNED_CODE
93 #define DEFAULT_CS_SYSTEM_ENFORCEMENT_ENABLE 1
94 #define DEFAULT_CS_PROCESS_ENFORCEMENT_ENABLE 1
95 #else
96 #define DEFAULT_CS_SYSTEM_ENFORCEMENT_ENABLE 1
97 #define DEFAULT_CS_PROCESS_ENFORCEMENT_ENABLE 0
98 #endif
99
100 #if CONFIG_ENFORCE_LIBRARY_VALIDATION
101 #define DEFAULT_CS_LIBRARY_VA_ENABLE 1
102 #else
103 #define DEFAULT_CS_LIBRARY_VA_ENABLE 0
104 #endif
105
106 #if SECURE_KERNEL
107
108 /*
109 * Here we split cs_enforcement_enable into cs_system_enforcement_enable and cs_process_enforcement_enable
110 *
111 * cs_system_enforcement_enable governs whether or not system level code signing enforcement mechanisms
112 * are applied on the system. Today, the only such mechanism is code signing enforcement of the dyld shared
113 * cache.
114 *
115 * cs_process_enforcement_enable governs whether code signing enforcement mechanisms are applied to all
116 * processes or only those that opt into such enforcement.
117 *
118 * (On iOS and related, both of these are set by default. On macOS, only cs_system_enforcement_enable
119 * is set by default. Processes can then be opted into code signing enforcement on a case by case basis.)
120 */
121 SECURITY_READ_ONLY_EARLY(int) cs_system_enforcement_enable = DEFAULT_CS_SYSTEM_ENFORCEMENT_ENABLE;
122 SECURITY_READ_ONLY_EARLY(int) cs_process_enforcement_enable = DEFAULT_CS_PROCESS_ENFORCEMENT_ENABLE;
123 SECURITY_READ_ONLY_EARLY(int) cs_library_val_enable = DEFAULT_CS_LIBRARY_VA_ENABLE;
124
125 #else /* !SECURE_KERNEL */
126 int cs_enforcement_panic = 0;
127 int cs_relax_platform_task_ports = 0;
128
129 SECURITY_READ_ONLY_LATE(int) cs_system_enforcement_enable = DEFAULT_CS_SYSTEM_ENFORCEMENT_ENABLE;
130 SECURITY_READ_ONLY_LATE(int) cs_process_enforcement_enable = DEFAULT_CS_PROCESS_ENFORCEMENT_ENABLE;
131
132 SECURITY_READ_ONLY_LATE(int) cs_library_val_enable = DEFAULT_CS_LIBRARY_VA_ENABLE;
133
134 #endif /* !SECURE_KERNEL */
135 int cs_all_vnodes = 0;
136
137 SYSCTL_INT(_vm, OID_AUTO, cs_force_kill, CTLFLAG_RW | CTLFLAG_LOCKED, &cs_force_kill, 0, "");
138 SYSCTL_INT(_vm, OID_AUTO, cs_force_hard, CTLFLAG_RW | CTLFLAG_LOCKED, &cs_force_hard, 0, "");
139 SYSCTL_INT(_vm, OID_AUTO, cs_debug, CTLFLAG_RW | CTLFLAG_LOCKED, &cs_debug, 0, "");
140 SYSCTL_INT(_vm, OID_AUTO, cs_debug_fail_on_unsigned_code, CTLFLAG_RW | CTLFLAG_LOCKED,
141 &cs_debug_fail_on_unsigned_code, 0, "");
142 SYSCTL_UINT(_vm, OID_AUTO, cs_debug_unsigned_exec_failures, CTLFLAG_RD | CTLFLAG_LOCKED,
143 &cs_debug_unsigned_exec_failures, 0, "");
144 SYSCTL_UINT(_vm, OID_AUTO, cs_debug_unsigned_mmap_failures, CTLFLAG_RD | CTLFLAG_LOCKED,
145 &cs_debug_unsigned_mmap_failures, 0, "");
146
147 SYSCTL_INT(_vm, OID_AUTO, cs_all_vnodes, CTLFLAG_RW | CTLFLAG_LOCKED, &cs_all_vnodes, 0, "");
148
149 #if !SECURE_KERNEL
150 SYSCTL_INT(_vm, OID_AUTO, cs_system_enforcement, CTLFLAG_RD | CTLFLAG_LOCKED, &cs_system_enforcement_enable, 0, "");
151 SYSCTL_INT(_vm, OID_AUTO, cs_process_enforcement, CTLFLAG_RW | CTLFLAG_LOCKED, &cs_process_enforcement_enable, 0, "");
152 SYSCTL_INT(_vm, OID_AUTO, cs_enforcement_panic, CTLFLAG_RW | CTLFLAG_LOCKED, &cs_enforcement_panic, 0, "");
153
154 #if !CONFIG_ENFORCE_LIBRARY_VALIDATION
155 SYSCTL_INT(_vm, OID_AUTO, cs_library_validation, CTLFLAG_RD | CTLFLAG_LOCKED, &cs_library_val_enable, 0, "");
156 #endif
157 #endif /* !SECURE_KERNEL */
158
159 int panic_on_cs_killed = 0;
160
161 __startup_func
162 static void
163 cs_init(void)
164 {
165 #if MACH_ASSERT
166 #if PLATFORM_WatchOS || __x86_64__
167 panic_on_cs_killed = 1;
168 #endif /* watchos || x86_64 */
169 #endif /* MACH_ASSERT */
170 PE_parse_boot_argn("panic_on_cs_killed", &panic_on_cs_killed,
171 sizeof(panic_on_cs_killed));
172 #if !SECURE_KERNEL
173 int disable_cs_enforcement = 0;
174 PE_parse_boot_argn("cs_enforcement_disable", &disable_cs_enforcement,
175 sizeof(disable_cs_enforcement));
176 if (disable_cs_enforcement && PE_i_can_has_debugger(NULL) != 0) {
177 cs_system_enforcement_enable = 0;
178 cs_process_enforcement_enable = 0;
179 } else {
180 int panic = 0;
181 PE_parse_boot_argn("cs_enforcement_panic", &panic, sizeof(panic));
182 cs_enforcement_panic = (panic != 0);
183 }
184
185 PE_parse_boot_argn("cs_relax_platform_task_ports",
186 &cs_relax_platform_task_ports,
187 sizeof(cs_relax_platform_task_ports));
188
189 PE_parse_boot_argn("cs_debug", &cs_debug, sizeof(cs_debug));
190
191 #if !CONFIG_ENFORCE_LIBRARY_VALIDATION
192 PE_parse_boot_argn("cs_library_val_enable", &cs_library_val_enable,
193 sizeof(cs_library_val_enable));
194 #endif
195 #endif /* !SECURE_KERNEL */
196 }
197 STARTUP(CODESIGNING, STARTUP_RANK_FIRST, cs_init);
198
199 int
200 cs_allow_invalid(struct proc *p)
201 {
202 #if MACH_ASSERT
203 lck_mtx_assert(&p->p_mlock, LCK_MTX_ASSERT_NOTOWNED);
204 #endif
205 #if CONFIG_MACF
206 /* There needs to be a MAC policy to implement this hook, or else the
207 * kill bits will be cleared here every time. If we have
208 * CONFIG_ENFORCE_SIGNED_CODE, we can assume there is a policy
209 * implementing the hook.
210 */
211 if (0 != mac_proc_check_run_cs_invalid(p)) {
212 if (cs_debug) {
213 printf("CODE SIGNING: cs_allow_invalid() "
214 "not allowed: pid %d\n",
215 p->p_pid);
216 }
217 return 0;
218 }
219 if (cs_debug) {
220 printf("CODE SIGNING: cs_allow_invalid() "
221 "allowed: pid %d\n",
222 p->p_pid);
223 }
224 proc_lock(p);
225 p->p_csflags &= ~(CS_KILL | CS_HARD);
226 if (p->p_csflags & CS_VALID) {
227 p->p_csflags |= CS_DEBUGGED;
228 }
229 #if PMAP_CS
230 task_t procTask = proc_task(p);
231 if (procTask) {
232 vm_map_t proc_map = get_task_map_reference(procTask);
233 if (proc_map) {
234 if (vm_map_cs_wx_enable(proc_map) != KERN_SUCCESS) {
235 printf("CODE SIGNING: cs_allow_invalid() not allowed by pmap: pid %d\n", p->p_pid);
236 }
237 vm_map_deallocate(proc_map);
238 }
239 }
240 #endif // MAP_CS
241 proc_unlock(p);
242
243 /* allow a debugged process to hide some (debug-only!) memory */
244 task_set_memory_ownership_transfer(p->task, TRUE);
245
246 vm_map_switch_protect(get_task_map(p->task), FALSE);
247 #endif
248 return (p->p_csflags & (CS_KILL | CS_HARD)) == 0;
249 }
250
251 int
252 cs_invalid_page(addr64_t vaddr, boolean_t *cs_killed)
253 {
254 struct proc *p;
255 int send_kill = 0, retval = 0, verbose = cs_debug;
256
257 p = current_proc();
258
259 if (verbose) {
260 printf("CODE SIGNING: cs_invalid_page(0x%llx): p=%d[%s]\n",
261 vaddr, p->p_pid, p->p_comm);
262 }
263
264 proc_lock(p);
265
266 /* XXX for testing */
267 if (cs_force_kill) {
268 p->p_csflags |= CS_KILL;
269 }
270 if (cs_force_hard) {
271 p->p_csflags |= CS_HARD;
272 }
273
274 /* CS_KILL triggers a kill signal, and no you can't have the page. Nothing else. */
275 if (p->p_csflags & CS_KILL) {
276 p->p_csflags |= CS_KILLED;
277 cs_procs_killed++;
278 send_kill = 1;
279 retval = 1;
280 }
281
282 /* CS_HARD means fail the mapping operation so the process stays valid. */
283 if (p->p_csflags & CS_HARD) {
284 retval = 1;
285 } else {
286 if (p->p_csflags & CS_VALID) {
287 p->p_csflags &= ~CS_VALID;
288 cs_procs_invalidated++;
289 verbose = 1;
290 cs_process_invalidated(NULL);
291 }
292 }
293 proc_unlock(p);
294
295 if (verbose) {
296 printf("CODE SIGNING: cs_invalid_page(0x%llx): "
297 "p=%d[%s] final status 0x%x, %s page%s\n",
298 vaddr, p->p_pid, p->p_comm, p->p_csflags,
299 retval ? "denying" : "allowing (remove VALID)",
300 send_kill ? " sending SIGKILL" : "");
301 }
302
303 if (send_kill) {
304 /* We will set the exit reason for the thread later */
305 threadsignal(current_thread(), SIGKILL, EXC_BAD_ACCESS, FALSE);
306 if (cs_killed) {
307 *cs_killed = TRUE;
308 }
309 } else if (cs_killed) {
310 *cs_killed = FALSE;
311 }
312
313 return retval;
314 }
315
316 /*
317 * Called after a process got its CS_VALID bit removed, either by
318 * a previous call to cs_invalid_page, or through other means.
319 * Called from fault handler with vm object lock held.
320 * Called with proc lock held for current_proc or, if passed in, p,
321 * to ensure MACF hook can suspend the task before other threads
322 * can access the memory that is paged in after cs_invalid_page
323 * returns 0 due to missing CS_HARD|CS_KILL.
324 */
325 void
326 cs_process_invalidated(struct proc * __unused p)
327 {
328 #if CONFIG_MACF
329 if (p == NULL) {
330 p = current_proc();
331 }
332 mac_proc_notify_cs_invalidated(p);
333 #endif
334 }
335
336 /*
337 * Assumes p (if passed in) is locked with proc_lock().
338 */
339
340 int
341 cs_process_enforcement(struct proc *p)
342 {
343 if (cs_process_enforcement_enable) {
344 return 1;
345 }
346
347 if (p == NULL) {
348 p = current_proc();
349 }
350
351 if (p != NULL && (p->p_csflags & CS_ENFORCEMENT)) {
352 return 1;
353 }
354
355 return 0;
356 }
357
358 int
359 cs_process_global_enforcement(void)
360 {
361 return cs_process_enforcement_enable ? 1 : 0;
362 }
363
364 int
365 cs_system_enforcement(void)
366 {
367 return cs_system_enforcement_enable ? 1 : 0;
368 }
369
370 int
371 cs_vm_supports_4k_translations(void)
372 {
373 return 0;
374 }
375
376
377 /*
378 * Returns whether a given process is still valid.
379 */
380 int
381 cs_valid(struct proc *p)
382 {
383 if (p == NULL) {
384 p = current_proc();
385 }
386
387 if (p != NULL && (p->p_csflags & CS_VALID)) {
388 return 1;
389 }
390
391 return 0;
392 }
393
394 /*
395 * Library validation functions
396 */
397 int
398 cs_require_lv(struct proc *p)
399 {
400 if (cs_library_val_enable) {
401 return 1;
402 }
403
404 if (p == NULL) {
405 p = current_proc();
406 }
407
408 if (p != NULL && (p->p_csflags & CS_REQUIRE_LV)) {
409 return 1;
410 }
411
412 return 0;
413 }
414
415 int
416 csproc_forced_lv(struct proc* p)
417 {
418 if (p == NULL) {
419 p = current_proc();
420 }
421 if (p != NULL && (p->p_csflags & CS_FORCED_LV)) {
422 return 1;
423 }
424 return 0;
425 }
426
427 /*
428 * <rdar://problem/24634089> added to allow system level library
429 * validation check at mac_cred_label_update_execve time
430 */
431 int
432 cs_system_require_lv(void)
433 {
434 return cs_library_val_enable ? 1 : 0;
435 }
436
437 /*
438 * Function: csblob_get_base_offset
439 *
440 * Description: This function returns the base offset into the (possibly universal) binary
441 * for a given blob.
442 */
443
444 off_t
445 csblob_get_base_offset(struct cs_blob *blob)
446 {
447 return blob->csb_base_offset;
448 }
449
450 /*
451 * Function: csblob_get_size
452 *
453 * Description: This function returns the size of a given blob.
454 */
455
456 vm_size_t
457 csblob_get_size(struct cs_blob *blob)
458 {
459 return blob->csb_mem_size;
460 }
461
462 /*
463 * Function: csblob_get_addr
464 *
465 * Description: This function returns the address of a given blob.
466 */
467
468 vm_address_t
469 csblob_get_addr(struct cs_blob *blob)
470 {
471 return (vm_address_t)blob->csb_mem_kaddr;
472 }
473
474 /*
475 * Function: csblob_get_platform_binary
476 *
477 * Description: This function returns true if the binary is
478 * in the trust cache.
479 */
480
481 int
482 csblob_get_platform_binary(struct cs_blob *blob)
483 {
484 if (blob && blob->csb_platform_binary) {
485 return 1;
486 }
487 return 0;
488 }
489
490 /*
491 * Function: csblob_get_flags
492 *
493 * Description: This function returns the flags for a given blob
494 */
495
496 unsigned int
497 csblob_get_flags(struct cs_blob *blob)
498 {
499 return blob->csb_flags;
500 }
501
502 /*
503 * Function: csblob_get_hashtype
504 *
505 * Description: This function returns the hash type for a given blob
506 */
507
508 uint8_t
509 csblob_get_hashtype(struct cs_blob const * const blob)
510 {
511 return blob->csb_hashtype != NULL ? cs_hash_type(blob->csb_hashtype) : 0;
512 }
513
514 /*
515 * Function: csproc_get_blob
516 *
517 * Description: This function returns the cs_blob
518 * for the process p
519 */
520 struct cs_blob *
521 csproc_get_blob(struct proc *p)
522 {
523 if (NULL == p) {
524 return NULL;
525 }
526
527 if (NULL == p->p_textvp) {
528 return NULL;
529 }
530
531 if ((p->p_csflags & CS_SIGNED) == 0) {
532 return NULL;
533 }
534
535 return ubc_cs_blob_get(p->p_textvp, -1, -1, p->p_textoff);
536 }
537
538 /*
539 * Function: csvnode_get_blob
540 *
541 * Description: This function returns the cs_blob
542 * for the vnode vp
543 */
544 struct cs_blob *
545 csvnode_get_blob(struct vnode *vp, off_t offset)
546 {
547 return ubc_cs_blob_get(vp, -1, -1, offset);
548 }
549
550 /*
551 * Function: csblob_get_teamid
552 *
553 * Description: This function returns a pointer to the
554 * team id of csblob
555 */
556 const char *
557 csblob_get_teamid(struct cs_blob *csblob)
558 {
559 return csblob->csb_teamid;
560 }
561
562 /*
563 * Function: csblob_get_identity
564 *
565 * Description: This function returns a pointer to the
566 * identity string
567 */
568 const char *
569 csblob_get_identity(struct cs_blob *csblob)
570 {
571 const CS_CodeDirectory *cd;
572
573 cd = (const CS_CodeDirectory *)csblob_find_blob(csblob, CSSLOT_CODEDIRECTORY, CSMAGIC_CODEDIRECTORY);
574 if (cd == NULL) {
575 return NULL;
576 }
577
578 if (cd->identOffset == 0) {
579 return NULL;
580 }
581
582 return ((const char *)cd) + ntohl(cd->identOffset);
583 }
584
585 /*
586 * Function: csblob_get_cdhash
587 *
588 * Description: This function returns a pointer to the
589 * cdhash of csblob (20 byte array)
590 */
591 const uint8_t *
592 csblob_get_cdhash(struct cs_blob *csblob)
593 {
594 ptrauth_utils_auth_blob_generic(csblob->csb_cdhash,
595 sizeof(csblob->csb_cdhash),
596 OS_PTRAUTH_DISCRIMINATOR("cs_blob.csb_cd_signature"),
597 PTRAUTH_ADDR_DIVERSIFY,
598 csblob->csb_cdhash_signature);
599 return csblob->csb_cdhash;
600 }
601
602 /*
603 * Function: csblob_get_signer_type
604 *
605 * Description: This function returns the signer type
606 * as an integer
607 */
608 unsigned int
609 csblob_get_signer_type(struct cs_blob *csblob)
610 {
611 return csblob->csb_signer_type;
612 }
613
614 void *
615 csblob_entitlements_dictionary_copy(struct cs_blob *csblob)
616 {
617 if (!csblob->csb_entitlements) {
618 return NULL;
619 }
620 osobject_retain(csblob->csb_entitlements);
621 return csblob->csb_entitlements;
622 }
623
624 void
625 csblob_entitlements_dictionary_set(struct cs_blob *csblob, void * entitlements)
626 {
627 assert(csblob->csb_entitlements == NULL);
628 if (entitlements) {
629 osobject_retain(entitlements);
630 }
631 csblob->csb_entitlements = entitlements;
632 }
633
634 /*
635 * Function: csproc_get_teamid
636 *
637 * Description: This function returns a pointer to the
638 * team id of the process p
639 */
640 const char *
641 csproc_get_teamid(struct proc *p)
642 {
643 struct cs_blob *csblob;
644
645 csblob = csproc_get_blob(p);
646 if (csblob == NULL) {
647 return NULL;
648 }
649
650 return csblob_get_teamid(csblob);
651 }
652
653 const char *
654 csproc_get_identity(struct proc *p)
655 {
656 struct cs_blob *csblob = NULL;
657
658 csblob = csproc_get_blob(p);
659 if (csblob == NULL) {
660 return NULL;
661 }
662
663 return csblob_get_identity(csblob);
664 }
665
666 /*
667 * Function: csproc_get_signer_type
668 *
669 * Description: This function returns the signer type
670 * of the process p
671 */
672 unsigned int
673 csproc_get_signer_type(struct proc *p)
674 {
675 struct cs_blob *csblob;
676
677 csblob = csproc_get_blob(p);
678 if (csblob == NULL) {
679 return CS_SIGNER_TYPE_UNKNOWN;
680 }
681
682 return csblob_get_signer_type(csblob);
683 }
684
685 /*
686 * Function: csvnode_get_teamid
687 *
688 * Description: This function returns a pointer to the
689 * team id of the binary at the given offset in vnode vp
690 */
691 const char *
692 csvnode_get_teamid(struct vnode *vp, off_t offset)
693 {
694 struct cs_blob *csblob;
695
696 if (vp == NULL) {
697 return NULL;
698 }
699
700 csblob = ubc_cs_blob_get(vp, -1, -1, offset);
701 if (csblob == NULL) {
702 return NULL;
703 }
704
705 return csblob_get_teamid(csblob);
706 }
707
708 /*
709 * Function: csproc_get_platform_binary
710 *
711 * Description: This function returns the value
712 * of the platform_binary field for proc p
713 */
714 int
715 csproc_get_platform_binary(struct proc *p)
716 {
717 struct cs_blob *csblob;
718
719 csblob = csproc_get_blob(p);
720
721 /* If there is no csblob this returns 0 because
722 * it is true that it is not a platform binary */
723 return (csblob == NULL) ? 0 : csblob->csb_platform_binary;
724 }
725
726 int
727 csproc_get_platform_path(struct proc *p)
728 {
729 struct cs_blob *csblob;
730
731 csblob = csproc_get_blob(p);
732
733 return (csblob == NULL) ? 0 : csblob->csb_platform_path;
734 }
735
736 #if DEVELOPMENT || DEBUG
737 void
738 csproc_clear_platform_binary(struct proc *p)
739 {
740 struct cs_blob *csblob = csproc_get_blob(p);
741
742 if (csblob == NULL) {
743 return;
744 }
745
746 if (cs_debug) {
747 printf("clearing platform binary on proc/task: pid = %d\n", p->p_pid);
748 }
749
750 csblob->csb_platform_binary = 0;
751 csblob->csb_platform_path = 0;
752 task_set_platform_binary(proc_task(p), FALSE);
753 }
754 #endif
755
756 void
757 csproc_disable_enforcement(struct proc* __unused p)
758 {
759 #if !CONFIG_ENFORCE_SIGNED_CODE
760 if (p != NULL) {
761 proc_lock(p);
762 p->p_csflags &= (~CS_ENFORCEMENT);
763 vm_map_cs_enforcement_set(get_task_map(p->task), FALSE);
764 proc_unlock(p);
765 }
766 #endif
767 }
768
769 /* Function: csproc_mark_invalid_allowed
770 *
771 * Description: Mark the process as being allowed to go invalid. Called as part of
772 * task_for_pid and ptrace policy. Note CS_INVALID_ALLOWED only matters for
773 * processes that have been opted into CS_ENFORCEMENT.
774 */
775 void
776 csproc_mark_invalid_allowed(struct proc* __unused p)
777 {
778 #if !CONFIG_ENFORCE_SIGNED_CODE
779 if (p != NULL) {
780 proc_lock(p);
781 p->p_csflags |= CS_INVALID_ALLOWED;
782 proc_unlock(p);
783 }
784 #endif
785 }
786
787 /*
788 * Function: csproc_check_invalid_allowed
789 *
790 * Description: Returns 1 if the process has been marked as allowed to go invalid
791 * because it gave its task port to an allowed process.
792 */
793 int
794 csproc_check_invalid_allowed(struct proc* __unused p)
795 {
796 #if !CONFIG_ENFORCE_SIGNED_CODE
797 if (p == NULL) {
798 p = current_proc();
799 }
800
801 if (p != NULL && (p->p_csflags & CS_INVALID_ALLOWED)) {
802 return 1;
803 }
804 #endif
805 return 0;
806 }
807
808 /*
809 * Function: csproc_get_prod_signed
810 *
811 * Description: Returns 1 if process is not signed with a developer identity.
812 * Note the inverted meaning from the cs_flag to make the error case safer.
813 * Will go away with rdar://problem/28322552.
814 */
815 int
816 csproc_get_prod_signed(struct proc *p)
817 {
818 return (p->p_csflags & CS_DEV_CODE) == 0;
819 }
820
821
822 /*
823 * Function: csfg_get_platform_binary
824 *
825 * Description: This function returns the
826 * platform binary field for the
827 * fileglob fg
828 */
829 int
830 csfg_get_platform_binary(struct fileglob *fg)
831 {
832 int platform_binary = 0;
833 struct ubc_info *uip;
834 vnode_t vp;
835
836 if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE) {
837 return 0;
838 }
839
840 vp = (struct vnode *)fg->fg_data;
841 if (vp == NULL) {
842 return 0;
843 }
844
845 vnode_lock(vp);
846 if (!UBCINFOEXISTS(vp)) {
847 goto out;
848 }
849
850 uip = vp->v_ubcinfo;
851 if (uip == NULL) {
852 goto out;
853 }
854
855 if (uip->cs_blobs == NULL) {
856 goto out;
857 }
858
859 /* It is OK to extract the teamid from the first blob
860 * because all blobs of a vnode must have the same teamid */
861 platform_binary = uip->cs_blobs->csb_platform_binary;
862 out:
863 vnode_unlock(vp);
864
865 return platform_binary;
866 }
867
868 int
869 csfg_get_supplement_platform_binary(struct fileglob *fg __unused)
870 {
871 #if CONFIG_SUPPLEMENTAL_SIGNATURES
872 int platform_binary = 0;
873 struct ubc_info *uip;
874 vnode_t vp;
875
876 if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE) {
877 return 0;
878 }
879
880 vp = (struct vnode *)fg->fg_data;
881 if (vp == NULL) {
882 return 0;
883 }
884
885 vnode_lock(vp);
886 if (!UBCINFOEXISTS(vp)) {
887 goto out;
888 }
889
890 uip = vp->v_ubcinfo;
891 if (uip == NULL) {
892 goto out;
893 }
894
895 if (uip->cs_blob_supplement == NULL) {
896 goto out;
897 }
898
899 platform_binary = uip->cs_blob_supplement->csb_platform_binary;
900 out:
901 vnode_unlock(vp);
902
903 return platform_binary;
904 #else
905 // Supplemental signatures are only allowed in CONFIG_SUPPLEMENTAL_SIGNATURES
906 // Return false if anyone asks about them
907 return 0;
908 #endif
909 }
910
911 uint8_t *
912 csfg_get_cdhash(struct fileglob *fg, uint64_t offset, size_t *cdhash_size)
913 {
914 vnode_t vp;
915
916 if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE) {
917 return NULL;
918 }
919
920 vp = (struct vnode *)fg->fg_data;
921 if (vp == NULL) {
922 return NULL;
923 }
924
925 struct cs_blob *csblob = NULL;
926 if ((csblob = ubc_cs_blob_get(vp, -1, -1, offset)) == NULL) {
927 return NULL;
928 }
929
930 if (cdhash_size) {
931 *cdhash_size = CS_CDHASH_LEN;
932 }
933 ptrauth_utils_auth_blob_generic(csblob->csb_cdhash,
934 sizeof(csblob->csb_cdhash),
935 OS_PTRAUTH_DISCRIMINATOR("cs_blob.csb_cd_signature"),
936 PTRAUTH_ADDR_DIVERSIFY,
937 csblob->csb_cdhash_signature);
938 return csblob->csb_cdhash;
939 }
940
941 uint8_t *
942 csfg_get_supplement_cdhash(struct fileglob *fg __unused, uint64_t offset __unused, size_t *cdhash_size __unused)
943 {
944 #if CONFIG_SUPPLEMENTAL_SIGNATURES
945 vnode_t vp;
946
947 if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE) {
948 return NULL;
949 }
950
951 vp = (struct vnode *)fg->fg_data;
952 if (vp == NULL) {
953 return NULL;
954 }
955
956 struct cs_blob *csblob = NULL;
957 if ((csblob = ubc_cs_blob_get_supplement(vp, offset)) == NULL) {
958 return NULL;
959 }
960
961 if (cdhash_size) {
962 *cdhash_size = CS_CDHASH_LEN;
963 }
964 ptrauth_utils_auth_blob_generic(csblob->csb_cdhash,
965 sizeof(csblob->csb_cdhash),
966 OS_PTRAUTH_DISCRIMINATOR("cs_blob.csb_cd_signature"),
967 PTRAUTH_ADDR_DIVERSIFY,
968 csblob->csb_cdhash_signature);
969 return csblob->csb_cdhash;
970 #else
971 // Supplemental signatures are only available in CONFIG_SUPPLEMENTAL_SIGNATURES
972 // return NULL if anyone asks about them
973 return NULL;
974 #endif
975 }
976
977 const uint8_t *
978 csfg_get_supplement_linkage_cdhash(struct fileglob *fg __unused, uint64_t offset __unused, size_t *cdhash_size __unused)
979 {
980 #if CONFIG_SUPPLEMENTAL_SIGNATURES
981 vnode_t vp;
982
983 if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE) {
984 return NULL;
985 }
986
987 vp = (struct vnode *)fg->fg_data;
988 if (vp == NULL) {
989 return NULL;
990 }
991
992 struct cs_blob *csblob = NULL;
993 if ((csblob = ubc_cs_blob_get_supplement(vp, offset)) == NULL) {
994 return NULL;
995 }
996
997 if (cdhash_size) {
998 *cdhash_size = CS_CDHASH_LEN;
999 }
1000
1001 return csblob->csb_linkage;
1002 #else
1003 // Supplemental signatures are only available in CONFIG_SUPPLEMENTAL_SIGNATURES
1004 // return NULL if anyone asks about them
1005 return NULL;
1006 #endif
1007 }
1008
1009 /*
1010 * Function: csfg_get_signer_type
1011 *
1012 * Description: This returns the signer type
1013 * for the fileglob fg
1014 */
1015 unsigned int
1016 csfg_get_signer_type(struct fileglob *fg)
1017 {
1018 struct ubc_info *uip;
1019 unsigned int signer_type = CS_SIGNER_TYPE_UNKNOWN;
1020 vnode_t vp;
1021
1022 if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE) {
1023 return CS_SIGNER_TYPE_UNKNOWN;
1024 }
1025
1026 vp = (struct vnode *)fg->fg_data;
1027 if (vp == NULL) {
1028 return CS_SIGNER_TYPE_UNKNOWN;
1029 }
1030
1031 vnode_lock(vp);
1032 if (!UBCINFOEXISTS(vp)) {
1033 goto out;
1034 }
1035
1036 uip = vp->v_ubcinfo;
1037 if (uip == NULL) {
1038 goto out;
1039 }
1040
1041 if (uip->cs_blobs == NULL) {
1042 goto out;
1043 }
1044
1045 /* It is OK to extract the signer type from the first blob,
1046 * because all blobs of a vnode must have the same signer type. */
1047 signer_type = uip->cs_blobs->csb_signer_type;
1048 out:
1049 vnode_unlock(vp);
1050
1051 return signer_type;
1052 }
1053
1054 unsigned int
1055 csfg_get_supplement_signer_type(struct fileglob *fg __unused)
1056 {
1057 #if CONFIG_SUPPLEMENTAL_SIGNATURES
1058 struct ubc_info *uip;
1059 unsigned int signer_type = CS_SIGNER_TYPE_UNKNOWN;
1060 vnode_t vp;
1061
1062 if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE) {
1063 return CS_SIGNER_TYPE_UNKNOWN;
1064 }
1065
1066 vp = (struct vnode *)fg->fg_data;
1067 if (vp == NULL) {
1068 return CS_SIGNER_TYPE_UNKNOWN;
1069 }
1070
1071 vnode_lock(vp);
1072 if (!UBCINFOEXISTS(vp)) {
1073 goto out;
1074 }
1075
1076 uip = vp->v_ubcinfo;
1077 if (uip == NULL) {
1078 goto out;
1079 }
1080
1081 if (uip->cs_blob_supplement == NULL) {
1082 goto out;
1083 }
1084
1085 signer_type = uip->cs_blob_supplement->csb_signer_type;
1086 out:
1087 vnode_unlock(vp);
1088
1089 return signer_type;
1090 #else
1091 // Supplemental signatures are only available in CONFIG_SUPPLEMENTAL_SIGNATURES
1092 // Return unknown if anyone asks
1093 return CS_SIGNER_TYPE_UNKNOWN;
1094 #endif
1095 }
1096
1097 /*
1098 * Function: csfg_get_teamid
1099 *
1100 * Description: This returns a pointer to
1101 * the teamid for the fileglob fg
1102 */
1103 const char *
1104 csfg_get_teamid(struct fileglob *fg)
1105 {
1106 struct ubc_info *uip;
1107 const char *str = NULL;
1108 vnode_t vp;
1109
1110 if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE) {
1111 return NULL;
1112 }
1113
1114 vp = (struct vnode *)fg->fg_data;
1115 if (vp == NULL) {
1116 return NULL;
1117 }
1118
1119 vnode_lock(vp);
1120 if (!UBCINFOEXISTS(vp)) {
1121 goto out;
1122 }
1123
1124 uip = vp->v_ubcinfo;
1125 if (uip == NULL) {
1126 goto out;
1127 }
1128
1129 if (uip->cs_blobs == NULL) {
1130 goto out;
1131 }
1132
1133 /* It is OK to extract the teamid from the first blob
1134 * because all blobs of a vnode must have the same teamid */
1135 str = uip->cs_blobs->csb_teamid;
1136 out:
1137 vnode_unlock(vp);
1138
1139 return str;
1140 }
1141
1142 const char *
1143 csfg_get_supplement_teamid(struct fileglob *fg __unused)
1144 {
1145 #if CONFIG_SUPPLEMENTAL_SIGNATURES
1146 struct ubc_info *uip;
1147 const char *str = NULL;
1148 vnode_t vp;
1149
1150 if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE) {
1151 return NULL;
1152 }
1153
1154 vp = (struct vnode *)fg->fg_data;
1155 if (vp == NULL) {
1156 return NULL;
1157 }
1158
1159 vnode_lock(vp);
1160 if (!UBCINFOEXISTS(vp)) {
1161 goto out;
1162 }
1163
1164 uip = vp->v_ubcinfo;
1165 if (uip == NULL) {
1166 goto out;
1167 }
1168
1169 if (uip->cs_blob_supplement == NULL) {
1170 goto out;
1171 }
1172
1173 str = uip->cs_blob_supplement->csb_supplement_teamid;
1174 out:
1175 vnode_unlock(vp);
1176
1177 return str;
1178 #else
1179 // Supplemental Signatures are only available in CONFIG_SUPPLEMENTAL_SIGNATURES
1180 // Return NULL if anyone asks
1181 return NULL;
1182 #endif
1183 }
1184
1185 /*
1186 * Function: csfg_get_prod_signed
1187 *
1188 * Description: Returns 1 if code is not signed with a developer identity.
1189 * Note the inverted meaning from the cs_flag to make the error case safer.
1190 * Will go away with rdar://problem/28322552.
1191 */
1192 int
1193 csfg_get_prod_signed(struct fileglob *fg)
1194 {
1195 struct ubc_info *uip;
1196 vnode_t vp;
1197 int prod_signed = 0;
1198
1199 if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE) {
1200 return 0;
1201 }
1202
1203 vp = (struct vnode *)fg->fg_data;
1204 if (vp == NULL) {
1205 return 0;
1206 }
1207
1208 vnode_lock(vp);
1209 if (!UBCINFOEXISTS(vp)) {
1210 goto out;
1211 }
1212
1213 uip = vp->v_ubcinfo;
1214 if (uip == NULL) {
1215 goto out;
1216 }
1217
1218 if (uip->cs_blobs == NULL) {
1219 goto out;
1220 }
1221
1222 /* It is OK to extract the flag from the first blob
1223 * because all blobs of a vnode must have the same cs_flags */
1224 prod_signed = (uip->cs_blobs->csb_flags & CS_DEV_CODE) == 0;
1225 out:
1226 vnode_unlock(vp);
1227
1228 return prod_signed;
1229 }
1230
1231 int
1232 csfg_get_supplement_prod_signed(struct fileglob *fg __unused)
1233 {
1234 #if CONFIG_SUPPLEMENTAL_SIGNATURES
1235 struct ubc_info *uip;
1236 vnode_t vp;
1237 int prod_signed = 0;
1238
1239 if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE) {
1240 return 0;
1241 }
1242
1243 vp = (struct vnode *)fg->fg_data;
1244 if (vp == NULL) {
1245 return 0;
1246 }
1247
1248 vnode_lock(vp);
1249 if (!UBCINFOEXISTS(vp)) {
1250 goto out;
1251 }
1252
1253 uip = vp->v_ubcinfo;
1254 if (uip == NULL) {
1255 goto out;
1256 }
1257
1258 if (uip->cs_blob_supplement == NULL) {
1259 goto out;
1260 }
1261
1262 /* It is OK to extract the flag from the first blob
1263 * because all blobs of a vnode must have the same cs_flags */
1264 prod_signed = (uip->cs_blob_supplement->csb_flags & CS_DEV_CODE) == 0;
1265 out:
1266 vnode_unlock(vp);
1267
1268 return prod_signed;
1269 #else
1270 // Supplemental signatures are only available in CONFIG_SUPPLEMENTAL_SIGNATURES
1271 // Indicate development signed if anyone tries to ask about one.
1272 return 0;
1273 #endif
1274 }
1275
1276 /*
1277 * Function: csfg_get_identity
1278 *
1279 * Description: This function returns the codesign identity
1280 * for the fileglob
1281 */
1282 const char *
1283 csfg_get_identity(struct fileglob *fg, off_t offset)
1284 {
1285 vnode_t vp;
1286 struct cs_blob *csblob = NULL;
1287
1288 if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE) {
1289 return NULL;
1290 }
1291
1292 vp = (struct vnode *)fg->fg_data;
1293 if (vp == NULL) {
1294 return NULL;
1295 }
1296
1297 csblob = ubc_cs_blob_get(vp, -1, -1, offset);
1298 if (csblob == NULL) {
1299 return NULL;
1300 }
1301
1302 return csblob_get_identity(csblob);
1303 }
1304
1305 /*
1306 * Function: csfg_get_platform_identifier
1307 *
1308 * Description: This function returns the codesign platform
1309 * identifier for the fileglob. Assumes the fileproc
1310 * is being held busy to keep the fileglob consistent.
1311 */
1312 uint8_t
1313 csfg_get_platform_identifier(struct fileglob *fg, off_t offset)
1314 {
1315 vnode_t vp;
1316
1317 if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE) {
1318 return 0;
1319 }
1320
1321 vp = (struct vnode *)fg->fg_data;
1322 if (vp == NULL) {
1323 return 0;
1324 }
1325
1326 return csvnode_get_platform_identifier(vp, offset);
1327 }
1328
1329 /*
1330 * Function: csvnode_get_platform_identifier
1331 *
1332 * Description: This function returns the codesign platform
1333 * identifier for the vnode. Assumes a vnode reference
1334 * is held.
1335 */
1336 uint8_t
1337 csvnode_get_platform_identifier(struct vnode *vp, off_t offset)
1338 {
1339 struct cs_blob *csblob;
1340 const CS_CodeDirectory *code_dir;
1341
1342 csblob = ubc_cs_blob_get(vp, -1, -1, offset);
1343 if (csblob == NULL) {
1344 return 0;
1345 }
1346
1347 code_dir = csblob->csb_cd;
1348 if (code_dir == NULL || ntohl(code_dir->length) < 8) {
1349 return 0;
1350 }
1351
1352 return code_dir->platform;
1353 }
1354
1355 /*
1356 * Function: csproc_get_platform_identifier
1357 *
1358 * Description: This function returns the codesign platform
1359 * identifier for the proc. Assumes proc will remain
1360 * valid through call.
1361 */
1362 uint8_t
1363 csproc_get_platform_identifier(struct proc *p)
1364 {
1365 if (NULL == p->p_textvp) {
1366 return 0;
1367 }
1368
1369 return csvnode_get_platform_identifier(p->p_textvp, p->p_textoff);
1370 }
1371
1372 uint32_t
1373 cs_entitlement_flags(struct proc *p)
1374 {
1375 return p->p_csflags & CS_ENTITLEMENT_FLAGS;
1376 }
1377
1378 int
1379 cs_restricted(struct proc *p)
1380 {
1381 return (p->p_csflags & CS_RESTRICT) ? 1 : 0;
1382 }
1383
1384 int
1385 csproc_hardened_runtime(struct proc* p)
1386 {
1387 return (p->p_csflags & CS_RUNTIME) ? 1 : 0;
1388 }
1389
1390 /*
1391 * Function: csfg_get_path
1392 *
1393 * Description: This populates the buffer passed in
1394 * with the path of the vnode
1395 * When calling this, the fileglob
1396 * cannot go away. The caller must have a
1397 * a reference on the fileglob or fileproc
1398 */
1399 int
1400 csfg_get_path(struct fileglob *fg, char *path, int *len)
1401 {
1402 vnode_t vp = NULL;
1403
1404 if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE) {
1405 return -1;
1406 }
1407
1408 vp = (struct vnode *)fg->fg_data;
1409
1410 /* vn_getpath returns 0 for success,
1411 * or an error code */
1412 return vn_getpath(vp, path, len);
1413 }
1414
1415 /*
1416 * Retrieve the entitlements blob for a vnode
1417 * Returns:
1418 * EINVAL no text vnode associated with the process
1419 * EBADEXEC invalid code signing data
1420 * 0 no error occurred
1421 *
1422 * On success, out_start and out_length will point to the
1423 * entitlements blob if found; or will be set to NULL/zero
1424 * if there were no entitlements.
1425 */
1426 int
1427 cs_entitlements_blob_get_vnode(vnode_t vnode, off_t offset, void **out_start, size_t *out_length)
1428 {
1429 struct cs_blob *csblob;
1430
1431 *out_start = NULL;
1432 *out_length = 0;
1433
1434 if (vnode == NULL) {
1435 return EINVAL;
1436 }
1437
1438 if ((csblob = ubc_cs_blob_get(vnode, -1, -1, offset)) == NULL) {
1439 return 0;
1440 }
1441
1442 return csblob_get_entitlements(csblob, out_start, out_length);
1443 }
1444
1445 /*
1446 * Retrieve the entitlements blob for a process.
1447 * Returns:
1448 * EINVAL no text vnode associated with the process
1449 * EBADEXEC invalid code signing data
1450 * 0 no error occurred
1451 *
1452 * On success, out_start and out_length will point to the
1453 * entitlements blob if found; or will be set to NULL/zero
1454 * if there were no entitlements.
1455 */
1456 int
1457 cs_entitlements_blob_get(proc_t p, void **out_start, size_t *out_length)
1458 {
1459 if ((p->p_csflags & CS_SIGNED) == 0) {
1460 return 0;
1461 }
1462
1463 return cs_entitlements_blob_get_vnode(p->p_textvp, p->p_textoff, out_start, out_length);
1464 }
1465
1466
1467 /* Retrieve the cached entitlements for a process
1468 * Returns:
1469 * EINVAL no text vnode associated with the process
1470 * EBADEXEC invalid code signing data
1471 * 0 no error occurred
1472 *
1473 * Note: the entitlements may be NULL if there is nothing cached.
1474 */
1475
1476 int
1477 cs_entitlements_dictionary_copy(proc_t p, void **entitlements)
1478 {
1479 struct cs_blob *csblob;
1480
1481 *entitlements = NULL;
1482
1483 if ((p->p_csflags & CS_SIGNED) == 0) {
1484 return 0;
1485 }
1486
1487 if (NULL == p->p_textvp) {
1488 return EINVAL;
1489 }
1490
1491 if ((csblob = ubc_cs_blob_get(p->p_textvp, -1, -1, p->p_textoff)) == NULL) {
1492 return 0;
1493 }
1494
1495 *entitlements = csblob_entitlements_dictionary_copy(csblob);
1496 return 0;
1497 }
1498
1499 /* Retrieve the codesign identity for a process.
1500 * Returns:
1501 * NULL an error occured
1502 * string the cs_identity
1503 */
1504
1505 const char *
1506 cs_identity_get(proc_t p)
1507 {
1508 struct cs_blob *csblob;
1509
1510 if ((p->p_csflags & CS_SIGNED) == 0) {
1511 return NULL;
1512 }
1513
1514 if (NULL == p->p_textvp) {
1515 return NULL;
1516 }
1517
1518 if ((csblob = ubc_cs_blob_get(p->p_textvp, -1, -1, p->p_textoff)) == NULL) {
1519 return NULL;
1520 }
1521
1522 return csblob_get_identity(csblob);
1523 }
1524
1525 /*
1526 * DO NOT USE THIS FUNCTION!
1527 * Use the properly guarded csproc_get_blob instead.
1528 *
1529 * This is currently here to allow detached signatures to work
1530 * properly. The only user of this function is also checking
1531 * for CS_VALID.
1532 */
1533
1534 int
1535 cs_blob_get(proc_t p, void **out_start, size_t *out_length)
1536 {
1537 struct cs_blob *csblob;
1538
1539 *out_start = NULL;
1540 *out_length = 0;
1541
1542 if (NULL == p->p_textvp) {
1543 return EINVAL;
1544 }
1545
1546 if ((csblob = ubc_cs_blob_get(p->p_textvp, -1, -1, p->p_textoff)) == NULL) {
1547 return 0;
1548 }
1549
1550 *out_start = csblob->csb_mem_kaddr;
1551 *out_length = csblob->csb_mem_size;
1552
1553 return 0;
1554 }
1555
1556 /*
1557 * return cshash of a process, cdhash is of size CS_CDHASH_LEN
1558 */
1559
1560 uint8_t *
1561 cs_get_cdhash(struct proc *p)
1562 {
1563 struct cs_blob *csblob;
1564
1565 if ((p->p_csflags & CS_SIGNED) == 0) {
1566 return NULL;
1567 }
1568
1569 if (NULL == p->p_textvp) {
1570 return NULL;
1571 }
1572
1573 if ((csblob = ubc_cs_blob_get(p->p_textvp, -1, -1, p->p_textoff)) == NULL) {
1574 return NULL;
1575 }
1576
1577 ptrauth_utils_auth_blob_generic(csblob->csb_cdhash,
1578 sizeof(csblob->csb_cdhash),
1579 OS_PTRAUTH_DISCRIMINATOR("cs_blob.csb_cd_signature"),
1580 PTRAUTH_ADDR_DIVERSIFY,
1581 csblob->csb_cdhash_signature);
1582 return csblob->csb_cdhash;
1583 }