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