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