]> git.saurik.com Git - apple/xnu.git/blob - bsd/kern/kern_cs.c
c6ab1e5bf086fef758f2c295acde1b4007112f3f
[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/task.h>
63
64 #include <vm/vm_map.h>
65 #include <vm/vm_kern.h>
66
67
68 #include <kern/assert.h>
69
70 #include <pexpert/pexpert.h>
71
72 #include <mach/shared_region.h>
73
74 #include <libkern/section_keywords.h>
75
76 unsigned long cs_procs_killed = 0;
77 unsigned long cs_procs_invalidated = 0;
78
79 int cs_force_kill = 0;
80 int cs_force_hard = 0;
81 int cs_debug = 0;
82 // If set, AMFI will error out early on unsigned code, before evaluation the normal policy.
83 int cs_debug_fail_on_unsigned_code = 0;
84 // If the previous mode is enabled, we count the resulting failures here.
85 unsigned int cs_debug_unsigned_exec_failures = 0;
86 unsigned int cs_debug_unsigned_mmap_failures = 0;
87
88 #if SECURE_KERNEL
89 /*
90 * Here we split cs_enforcement_enable into cs_system_enforcement_enable and cs_process_enforcement_enable
91 *
92 * cs_system_enforcement_enable governs whether or not system level code signing enforcement mechanisms
93 * are applied on the system. Today, the only such mechanism is code signing enforcement of the dyld shared
94 * cache.
95 *
96 * cs_process_enforcement_enable governs whether code signing enforcement mechanisms are applied to all
97 * processes or only those that opt into such enforcement.
98 *
99 * (On iOS and related, both of these are set by default. On macOS, only cs_system_enforcement_enable
100 * is set by default. Processes can then be opted into code signing enforcement on a case by case basis.)
101 */
102 const int cs_system_enforcement_enable = 1;
103 const int cs_process_enforcement_enable = 1;
104 const int cs_library_val_enable = 1;
105 #else /* !SECURE_KERNEL */
106 int cs_enforcement_panic = 0;
107 int cs_relax_platform_task_ports = 0;
108
109 #if CONFIG_ENFORCE_SIGNED_CODE
110 #define DEFAULT_CS_SYSTEM_ENFORCEMENT_ENABLE 1
111 #define DEFAULT_CS_PROCESS_ENFORCEMENT_ENABLE 1
112 #else
113 #define DEFAULT_CS_SYSTEM_ENFORCEMENT_ENABLE 1
114 #define DEFAULT_CS_PROCESS_ENFORCEMENT_ENABLE 0
115 #endif
116 SECURITY_READ_ONLY_LATE(int) cs_system_enforcement_enable = DEFAULT_CS_SYSTEM_ENFORCEMENT_ENABLE;
117 SECURITY_READ_ONLY_LATE(int) cs_process_enforcement_enable = DEFAULT_CS_PROCESS_ENFORCEMENT_ENABLE;
118
119 #if CONFIG_ENFORCE_LIBRARY_VALIDATION
120 #define DEFAULT_CS_LIBRARY_VA_ENABLE 1
121 #else
122 #define DEFAULT_CS_LIBRARY_VA_ENABLE 0
123 #endif
124 SECURITY_READ_ONLY_LATE(int) cs_library_val_enable = DEFAULT_CS_LIBRARY_VA_ENABLE;
125
126 #endif /* !SECURE_KERNEL */
127 int cs_all_vnodes = 0;
128
129 static lck_grp_t *cs_lockgrp;
130
131 SYSCTL_INT(_vm, OID_AUTO, cs_force_kill, CTLFLAG_RW | CTLFLAG_LOCKED, &cs_force_kill, 0, "");
132 SYSCTL_INT(_vm, OID_AUTO, cs_force_hard, CTLFLAG_RW | CTLFLAG_LOCKED, &cs_force_hard, 0, "");
133 SYSCTL_INT(_vm, OID_AUTO, cs_debug, CTLFLAG_RW | CTLFLAG_LOCKED, &cs_debug, 0, "");
134 SYSCTL_INT(_vm, OID_AUTO, cs_debug_fail_on_unsigned_code, CTLFLAG_RW | CTLFLAG_LOCKED,
135 &cs_debug_fail_on_unsigned_code, 0, "");
136 SYSCTL_UINT(_vm, OID_AUTO, cs_debug_unsigned_exec_failures, CTLFLAG_RD | CTLFLAG_LOCKED,
137 &cs_debug_unsigned_exec_failures, 0, "");
138 SYSCTL_UINT(_vm, OID_AUTO, cs_debug_unsigned_mmap_failures, CTLFLAG_RD | CTLFLAG_LOCKED,
139 &cs_debug_unsigned_mmap_failures, 0, "");
140
141 SYSCTL_INT(_vm, OID_AUTO, cs_all_vnodes, CTLFLAG_RW | CTLFLAG_LOCKED, &cs_all_vnodes, 0, "");
142
143 #if !SECURE_KERNEL
144 SYSCTL_INT(_vm, OID_AUTO, cs_system_enforcement, CTLFLAG_RD | CTLFLAG_LOCKED, &cs_system_enforcement_enable, 0, "");
145 SYSCTL_INT(_vm, OID_AUTO, cs_process_enforcement, CTLFLAG_RW | CTLFLAG_LOCKED, &cs_process_enforcement_enable, 0, "");
146 SYSCTL_INT(_vm, OID_AUTO, cs_enforcement_panic, CTLFLAG_RW | CTLFLAG_LOCKED, &cs_enforcement_panic, 0, "");
147
148 #if !CONFIG_ENFORCE_LIBRARY_VALIDATION
149 SYSCTL_INT(_vm, OID_AUTO, cs_library_validation, CTLFLAG_RD | CTLFLAG_LOCKED, &cs_library_val_enable, 0, "");
150 #endif
151 #endif /* !SECURE_KERNEL */
152
153 int panic_on_cs_killed = 0;
154
155 void
156 cs_init(void)
157 {
158 #if MACH_ASSERT
159 #if PLATFORM_WatchOS || __x86_64__
160 panic_on_cs_killed = 1;
161 #endif /* watchos || x86_64 */
162 #endif /* MACH_ASSERT */
163 PE_parse_boot_argn("panic_on_cs_killed", &panic_on_cs_killed,
164 sizeof(panic_on_cs_killed));
165 #if !SECURE_KERNEL
166 int disable_cs_enforcement = 0;
167 PE_parse_boot_argn("cs_enforcement_disable", &disable_cs_enforcement,
168 sizeof(disable_cs_enforcement));
169 if (disable_cs_enforcement && PE_i_can_has_debugger(NULL) != 0) {
170 cs_system_enforcement_enable = 0;
171 cs_process_enforcement_enable = 0;
172 } else {
173 int panic = 0;
174 PE_parse_boot_argn("cs_enforcement_panic", &panic, sizeof(panic));
175 cs_enforcement_panic = (panic != 0);
176 }
177
178 PE_parse_boot_argn("cs_relax_platform_task_ports",
179 &cs_relax_platform_task_ports,
180 sizeof(cs_relax_platform_task_ports));
181
182 PE_parse_boot_argn("cs_debug", &cs_debug, sizeof(cs_debug));
183
184 #if !CONFIG_ENFORCE_LIBRARY_VALIDATION
185 PE_parse_boot_argn("cs_library_val_enable", &cs_library_val_enable,
186 sizeof(cs_library_val_enable));
187 #endif
188 #endif /* !SECURE_KERNEL */
189
190 lck_grp_attr_t *attr = lck_grp_attr_alloc_init();
191 cs_lockgrp = lck_grp_alloc_init("KERNCS", attr);
192 lck_grp_attr_free(attr);
193 }
194
195 int
196 cs_allow_invalid(struct proc *p)
197 {
198 #if MACH_ASSERT
199 lck_mtx_assert(&p->p_mlock, LCK_MTX_ASSERT_NOTOWNED);
200 #endif
201 #if CONFIG_MACF
202 /* There needs to be a MAC policy to implement this hook, or else the
203 * kill bits will be cleared here every time. If we have
204 * CONFIG_ENFORCE_SIGNED_CODE, we can assume there is a policy
205 * implementing the hook.
206 */
207 if (0 != mac_proc_check_run_cs_invalid(p)) {
208 if (cs_debug) {
209 printf("CODE SIGNING: cs_allow_invalid() "
210 "not allowed: pid %d\n",
211 p->p_pid);
212 }
213 return 0;
214 }
215 if (cs_debug) {
216 printf("CODE SIGNING: cs_allow_invalid() "
217 "allowed: pid %d\n",
218 p->p_pid);
219 }
220 proc_lock(p);
221 p->p_csflags &= ~(CS_KILL | CS_HARD);
222 if (p->p_csflags & CS_VALID) {
223 p->p_csflags |= CS_DEBUGGED;
224 }
225 proc_unlock(p);
226
227 vm_map_switch_protect(get_task_map(p->task), FALSE);
228 #endif
229 return (p->p_csflags & (CS_KILL | CS_HARD)) == 0;
230 }
231
232 int
233 cs_invalid_page(addr64_t vaddr, boolean_t *cs_killed)
234 {
235 struct proc *p;
236 int send_kill = 0, retval = 0, verbose = cs_debug;
237 uint32_t csflags;
238
239 p = current_proc();
240
241 if (verbose) {
242 printf("CODE SIGNING: cs_invalid_page(0x%llx): p=%d[%s]\n",
243 vaddr, p->p_pid, p->p_comm);
244 }
245
246 proc_lock(p);
247
248 /* XXX for testing */
249 if (cs_force_kill) {
250 p->p_csflags |= CS_KILL;
251 }
252 if (cs_force_hard) {
253 p->p_csflags |= CS_HARD;
254 }
255
256 /* CS_KILL triggers a kill signal, and no you can't have the page. Nothing else. */
257 if (p->p_csflags & CS_KILL) {
258 p->p_csflags |= CS_KILLED;
259 cs_procs_killed++;
260 send_kill = 1;
261 retval = 1;
262 }
263
264 /* CS_HARD means fail the mapping operation so the process stays valid. */
265 if (p->p_csflags & CS_HARD) {
266 retval = 1;
267 } else {
268 if (p->p_csflags & CS_VALID) {
269 p->p_csflags &= ~CS_VALID;
270 cs_procs_invalidated++;
271 verbose = 1;
272 }
273 }
274 csflags = p->p_csflags;
275 proc_unlock(p);
276
277 if (verbose) {
278 printf("CODE SIGNING: cs_invalid_page(0x%llx): "
279 "p=%d[%s] final status 0x%x, %s page%s\n",
280 vaddr, p->p_pid, p->p_comm, p->p_csflags,
281 retval ? "denying" : "allowing (remove VALID)",
282 send_kill ? " sending SIGKILL" : "");
283 }
284
285 if (send_kill) {
286 /* We will set the exit reason for the thread later */
287 threadsignal(current_thread(), SIGKILL, EXC_BAD_ACCESS, FALSE);
288 if (cs_killed) {
289 *cs_killed = TRUE;
290 }
291 } else if (cs_killed) {
292 *cs_killed = FALSE;
293 }
294
295
296 return retval;
297 }
298
299 /*
300 * Assumes p (if passed in) is locked with proc_lock().
301 */
302
303 int
304 cs_process_enforcement(struct proc *p)
305 {
306 if (cs_process_enforcement_enable) {
307 return 1;
308 }
309
310 if (p == NULL) {
311 p = current_proc();
312 }
313
314 if (p != NULL && (p->p_csflags & CS_ENFORCEMENT)) {
315 return 1;
316 }
317
318 return 0;
319 }
320
321 int
322 cs_process_global_enforcement(void)
323 {
324 return cs_process_enforcement_enable ? 1 : 0;
325 }
326
327 int
328 cs_system_enforcement(void)
329 {
330 return cs_system_enforcement_enable ? 1 : 0;
331 }
332
333 /*
334 * Returns whether a given process is still valid.
335 */
336 int
337 cs_valid(struct proc *p)
338 {
339 if (p == NULL) {
340 p = current_proc();
341 }
342
343 if (p != NULL && (p->p_csflags & CS_VALID)) {
344 return 1;
345 }
346
347 return 0;
348 }
349
350 /*
351 * Library validation functions
352 */
353 int
354 cs_require_lv(struct proc *p)
355 {
356 if (cs_library_val_enable) {
357 return 1;
358 }
359
360 if (p == NULL) {
361 p = current_proc();
362 }
363
364 if (p != NULL && (p->p_csflags & CS_REQUIRE_LV)) {
365 return 1;
366 }
367
368 return 0;
369 }
370
371 int
372 csproc_forced_lv(struct proc* p)
373 {
374 if (p == NULL) {
375 p = current_proc();
376 }
377 if (p != NULL && (p->p_csflags & CS_FORCED_LV)) {
378 return 1;
379 }
380 return 0;
381 }
382
383 /*
384 * <rdar://problem/24634089> added to allow system level library
385 * validation check at mac_cred_label_update_execve time
386 */
387 int
388 cs_system_require_lv(void)
389 {
390 return cs_library_val_enable ? 1 : 0;
391 }
392
393 /*
394 * Function: csblob_get_base_offset
395 *
396 * Description: This function returns the base offset into the (possibly universal) binary
397 * for a given blob.
398 */
399
400 off_t
401 csblob_get_base_offset(struct cs_blob *blob)
402 {
403 return blob->csb_base_offset;
404 }
405
406 /*
407 * Function: csblob_get_size
408 *
409 * Description: This function returns the size of a given blob.
410 */
411
412 vm_size_t
413 csblob_get_size(struct cs_blob *blob)
414 {
415 return blob->csb_mem_size;
416 }
417
418 /*
419 * Function: csblob_get_addr
420 *
421 * Description: This function returns the address of a given blob.
422 */
423
424 vm_address_t
425 csblob_get_addr(struct cs_blob *blob)
426 {
427 return blob->csb_mem_kaddr;
428 }
429
430 /*
431 * Function: csblob_get_platform_binary
432 *
433 * Description: This function returns true if the binary is
434 * in the trust cache.
435 */
436
437 int
438 csblob_get_platform_binary(struct cs_blob *blob)
439 {
440 if (blob && blob->csb_platform_binary) {
441 return 1;
442 }
443 return 0;
444 }
445
446 /*
447 * Function: csblob_get_flags
448 *
449 * Description: This function returns the flags for a given blob
450 */
451
452 unsigned int
453 csblob_get_flags(struct cs_blob *blob)
454 {
455 return blob->csb_flags;
456 }
457
458 /*
459 * Function: csblob_get_hashtype
460 *
461 * Description: This function returns the hash type for a given blob
462 */
463
464 uint8_t
465 csblob_get_hashtype(struct cs_blob const * const blob)
466 {
467 return blob->csb_hashtype != NULL ? cs_hash_type(blob->csb_hashtype) : 0;
468 }
469
470 /*
471 * Function: csproc_get_blob
472 *
473 * Description: This function returns the cs_blob
474 * for the process p
475 */
476 struct cs_blob *
477 csproc_get_blob(struct proc *p)
478 {
479 if (NULL == p) {
480 return NULL;
481 }
482
483 if (NULL == p->p_textvp) {
484 return NULL;
485 }
486
487 if ((p->p_csflags & CS_SIGNED) == 0) {
488 return NULL;
489 }
490
491 return ubc_cs_blob_get(p->p_textvp, -1, p->p_textoff);
492 }
493
494 /*
495 * Function: csvnode_get_blob
496 *
497 * Description: This function returns the cs_blob
498 * for the vnode vp
499 */
500 struct cs_blob *
501 csvnode_get_blob(struct vnode *vp, off_t offset)
502 {
503 return ubc_cs_blob_get(vp, -1, offset);
504 }
505
506 /*
507 * Function: csblob_get_teamid
508 *
509 * Description: This function returns a pointer to the
510 * team id of csblob
511 */
512 const char *
513 csblob_get_teamid(struct cs_blob *csblob)
514 {
515 return csblob->csb_teamid;
516 }
517
518 /*
519 * Function: csblob_get_identity
520 *
521 * Description: This function returns a pointer to the
522 * identity string
523 */
524 const char *
525 csblob_get_identity(struct cs_blob *csblob)
526 {
527 const CS_CodeDirectory *cd;
528
529 cd = (const CS_CodeDirectory *)csblob_find_blob(csblob, CSSLOT_CODEDIRECTORY, CSMAGIC_CODEDIRECTORY);
530 if (cd == NULL) {
531 return NULL;
532 }
533
534 if (cd->identOffset == 0) {
535 return NULL;
536 }
537
538 return ((const char *)cd) + ntohl(cd->identOffset);
539 }
540
541 /*
542 * Function: csblob_get_cdhash
543 *
544 * Description: This function returns a pointer to the
545 * cdhash of csblob (20 byte array)
546 */
547 const uint8_t *
548 csblob_get_cdhash(struct cs_blob *csblob)
549 {
550 return csblob->csb_cdhash;
551 }
552
553 /*
554 * Function: csblob_get_signer_type
555 *
556 * Description: This function returns the signer type
557 * as an integer
558 */
559 unsigned int
560 csblob_get_signer_type(struct cs_blob *csblob)
561 {
562 return csblob->csb_signer_type;
563 }
564
565 void *
566 csblob_entitlements_dictionary_copy(struct cs_blob *csblob)
567 {
568 if (!csblob->csb_entitlements) {
569 return NULL;
570 }
571 osobject_retain(csblob->csb_entitlements);
572 return csblob->csb_entitlements;
573 }
574
575 void
576 csblob_entitlements_dictionary_set(struct cs_blob *csblob, void * entitlements)
577 {
578 assert(csblob->csb_entitlements == NULL);
579 if (entitlements) {
580 osobject_retain(entitlements);
581 }
582 csblob->csb_entitlements = entitlements;
583 }
584
585 /*
586 * Function: csproc_get_teamid
587 *
588 * Description: This function returns a pointer to the
589 * team id of the process p
590 */
591 const char *
592 csproc_get_teamid(struct proc *p)
593 {
594 struct cs_blob *csblob;
595
596 csblob = csproc_get_blob(p);
597 if (csblob == NULL) {
598 return NULL;
599 }
600
601 return csblob_get_teamid(csblob);
602 }
603
604 /*
605 * Function: csproc_get_signer_type
606 *
607 * Description: This function returns the signer type
608 * of the process p
609 */
610 unsigned int
611 csproc_get_signer_type(struct proc *p)
612 {
613 struct cs_blob *csblob;
614
615 csblob = csproc_get_blob(p);
616 if (csblob == NULL) {
617 return CS_SIGNER_TYPE_UNKNOWN;
618 }
619
620 return csblob_get_signer_type(csblob);
621 }
622
623 /*
624 * Function: csvnode_get_teamid
625 *
626 * Description: This function returns a pointer to the
627 * team id of the binary at the given offset in vnode vp
628 */
629 const char *
630 csvnode_get_teamid(struct vnode *vp, off_t offset)
631 {
632 struct cs_blob *csblob;
633
634 if (vp == NULL) {
635 return NULL;
636 }
637
638 csblob = ubc_cs_blob_get(vp, -1, offset);
639 if (csblob == NULL) {
640 return NULL;
641 }
642
643 return csblob_get_teamid(csblob);
644 }
645
646 /*
647 * Function: csproc_get_platform_binary
648 *
649 * Description: This function returns the value
650 * of the platform_binary field for proc p
651 */
652 int
653 csproc_get_platform_binary(struct proc *p)
654 {
655 struct cs_blob *csblob;
656
657 csblob = csproc_get_blob(p);
658
659 /* If there is no csblob this returns 0 because
660 * it is true that it is not a platform binary */
661 return (csblob == NULL) ? 0 : csblob->csb_platform_binary;
662 }
663
664 int
665 csproc_get_platform_path(struct proc *p)
666 {
667 struct cs_blob *csblob;
668
669 csblob = csproc_get_blob(p);
670
671 return (csblob == NULL) ? 0 : csblob->csb_platform_path;
672 }
673
674 #if DEVELOPMENT || DEBUG
675 void
676 csproc_clear_platform_binary(struct proc *p)
677 {
678 struct cs_blob *csblob = csproc_get_blob(p);
679
680 if (csblob == NULL) {
681 return;
682 }
683
684 if (cs_debug) {
685 printf("clearing platform binary on proc/task: pid = %d\n", p->p_pid);
686 }
687
688 csblob->csb_platform_binary = 0;
689 csblob->csb_platform_path = 0;
690 task_set_platform_binary(proc_task(p), FALSE);
691 }
692 #endif
693
694 void
695 csproc_disable_enforcement(struct proc* __unused p)
696 {
697 #if !CONFIG_ENFORCE_SIGNED_CODE
698 if (p != NULL) {
699 proc_lock(p);
700 p->p_csflags &= (~CS_ENFORCEMENT);
701 proc_unlock(p);
702 }
703 #endif
704 }
705
706 /* Function: csproc_mark_invalid_allowed
707 *
708 * Description: Mark the process as being allowed to go invalid. Called as part of
709 * task_for_pid and ptrace policy. Note CS_INVALID_ALLOWED only matters for
710 * processes that have been opted into CS_ENFORCEMENT.
711 */
712 void
713 csproc_mark_invalid_allowed(struct proc* __unused p)
714 {
715 #if !CONFIG_ENFORCE_SIGNED_CODE
716 if (p != NULL) {
717 proc_lock(p);
718 p->p_csflags |= CS_INVALID_ALLOWED;
719 proc_unlock(p);
720 }
721 #endif
722 }
723
724 /*
725 * Function: csproc_check_invalid_allowed
726 *
727 * Description: Returns 1 if the process has been marked as allowed to go invalid
728 * because it gave its task port to an allowed process.
729 */
730 int
731 csproc_check_invalid_allowed(struct proc* __unused p)
732 {
733 #if !CONFIG_ENFORCE_SIGNED_CODE
734 if (p == NULL) {
735 p = current_proc();
736 }
737
738 if (p != NULL && (p->p_csflags & CS_INVALID_ALLOWED)) {
739 return 1;
740 }
741 #endif
742 return 0;
743 }
744
745 /*
746 * Function: csproc_get_prod_signed
747 *
748 * Description: Returns 1 if process is not signed with a developer identity.
749 * Note the inverted meaning from the cs_flag to make the error case safer.
750 * Will go away with rdar://problem/28322552.
751 */
752 int
753 csproc_get_prod_signed(struct proc *p)
754 {
755 return (p->p_csflags & CS_DEV_CODE) == 0;
756 }
757
758
759 /*
760 * Function: csfg_get_platform_binary
761 *
762 * Description: This function returns the
763 * platform binary field for the
764 * fileglob fg
765 */
766 int
767 csfg_get_platform_binary(struct fileglob *fg)
768 {
769 int platform_binary = 0;
770 struct ubc_info *uip;
771 vnode_t vp;
772
773 if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE) {
774 return 0;
775 }
776
777 vp = (struct vnode *)fg->fg_data;
778 if (vp == NULL) {
779 return 0;
780 }
781
782 vnode_lock(vp);
783 if (!UBCINFOEXISTS(vp)) {
784 goto out;
785 }
786
787 uip = vp->v_ubcinfo;
788 if (uip == NULL) {
789 goto out;
790 }
791
792 if (uip->cs_blobs == NULL) {
793 goto out;
794 }
795
796 /* It is OK to extract the teamid from the first blob
797 * because all blobs of a vnode must have the same teamid */
798 platform_binary = uip->cs_blobs->csb_platform_binary;
799 out:
800 vnode_unlock(vp);
801
802 return platform_binary;
803 }
804
805 uint8_t *
806 csfg_get_cdhash(struct fileglob *fg, uint64_t offset, size_t *cdhash_size)
807 {
808 vnode_t vp;
809
810 if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE) {
811 return NULL;
812 }
813
814 vp = (struct vnode *)fg->fg_data;
815 if (vp == NULL) {
816 return NULL;
817 }
818
819 struct cs_blob *csblob = NULL;
820 if ((csblob = ubc_cs_blob_get(vp, -1, offset)) == NULL) {
821 return NULL;
822 }
823
824 if (cdhash_size) {
825 *cdhash_size = CS_CDHASH_LEN;
826 }
827
828 return csblob->csb_cdhash;
829 }
830
831 /*
832 * Function: csfg_get_signer_type
833 *
834 * Description: This returns the signer type
835 * for the fileglob fg
836 */
837 unsigned int
838 csfg_get_signer_type(struct fileglob *fg)
839 {
840 struct ubc_info *uip;
841 unsigned int signer_type = CS_SIGNER_TYPE_UNKNOWN;
842 vnode_t vp;
843
844 if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE) {
845 return CS_SIGNER_TYPE_UNKNOWN;
846 }
847
848 vp = (struct vnode *)fg->fg_data;
849 if (vp == NULL) {
850 return CS_SIGNER_TYPE_UNKNOWN;
851 }
852
853 vnode_lock(vp);
854 if (!UBCINFOEXISTS(vp)) {
855 goto out;
856 }
857
858 uip = vp->v_ubcinfo;
859 if (uip == NULL) {
860 goto out;
861 }
862
863 if (uip->cs_blobs == NULL) {
864 goto out;
865 }
866
867 /* It is OK to extract the signer type from the first blob,
868 * because all blobs of a vnode must have the same signer type. */
869 signer_type = uip->cs_blobs->csb_signer_type;
870 out:
871 vnode_unlock(vp);
872
873 return signer_type;
874 }
875
876 /*
877 * Function: csfg_get_teamid
878 *
879 * Description: This returns a pointer to
880 * the teamid for the fileglob fg
881 */
882 const char *
883 csfg_get_teamid(struct fileglob *fg)
884 {
885 struct ubc_info *uip;
886 const char *str = NULL;
887 vnode_t vp;
888
889 if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE) {
890 return NULL;
891 }
892
893 vp = (struct vnode *)fg->fg_data;
894 if (vp == NULL) {
895 return NULL;
896 }
897
898 vnode_lock(vp);
899 if (!UBCINFOEXISTS(vp)) {
900 goto out;
901 }
902
903 uip = vp->v_ubcinfo;
904 if (uip == NULL) {
905 goto out;
906 }
907
908 if (uip->cs_blobs == NULL) {
909 goto out;
910 }
911
912 /* It is OK to extract the teamid from the first blob
913 * because all blobs of a vnode must have the same teamid */
914 str = uip->cs_blobs->csb_teamid;
915 out:
916 vnode_unlock(vp);
917
918 return str;
919 }
920
921 /*
922 * Function: csfg_get_prod_signed
923 *
924 * Description: Returns 1 if code is not signed with a developer identity.
925 * Note the inverted meaning from the cs_flag to make the error case safer.
926 * Will go away with rdar://problem/28322552.
927 */
928 int
929 csfg_get_prod_signed(struct fileglob *fg)
930 {
931 struct ubc_info *uip;
932 vnode_t vp;
933 int prod_signed = 0;
934
935 if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE) {
936 return 0;
937 }
938
939 vp = (struct vnode *)fg->fg_data;
940 if (vp == NULL) {
941 return 0;
942 }
943
944 vnode_lock(vp);
945 if (!UBCINFOEXISTS(vp)) {
946 goto out;
947 }
948
949 uip = vp->v_ubcinfo;
950 if (uip == NULL) {
951 goto out;
952 }
953
954 if (uip->cs_blobs == NULL) {
955 goto out;
956 }
957
958 /* It is OK to extract the flag from the first blob
959 * because all blobs of a vnode must have the same cs_flags */
960 prod_signed = (uip->cs_blobs->csb_flags & CS_DEV_CODE) == 0;
961 out:
962 vnode_unlock(vp);
963
964 return prod_signed;
965 }
966
967 /*
968 * Function: csfg_get_identity
969 *
970 * Description: This function returns the codesign identity
971 * for the fileglob
972 */
973 const char *
974 csfg_get_identity(struct fileglob *fg, off_t offset)
975 {
976 vnode_t vp;
977 struct cs_blob *csblob = NULL;
978
979 if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE) {
980 return NULL;
981 }
982
983 vp = (struct vnode *)fg->fg_data;
984 if (vp == NULL) {
985 return NULL;
986 }
987
988 csblob = ubc_cs_blob_get(vp, -1, offset);
989 if (csblob == NULL) {
990 return NULL;
991 }
992
993 return csblob_get_identity(csblob);
994 }
995
996 /*
997 * Function: csfg_get_platform_identifier
998 *
999 * Description: This function returns the codesign platform
1000 * identifier for the fileglob. Assumes the fileproc
1001 * is being held busy to keep the fileglob consistent.
1002 */
1003 uint8_t
1004 csfg_get_platform_identifier(struct fileglob *fg, off_t offset)
1005 {
1006 vnode_t vp;
1007
1008 if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE) {
1009 return 0;
1010 }
1011
1012 vp = (struct vnode *)fg->fg_data;
1013 if (vp == NULL) {
1014 return 0;
1015 }
1016
1017 return csvnode_get_platform_identifier(vp, offset);
1018 }
1019
1020 /*
1021 * Function: csvnode_get_platform_identifier
1022 *
1023 * Description: This function returns the codesign platform
1024 * identifier for the vnode. Assumes a vnode reference
1025 * is held.
1026 */
1027 uint8_t
1028 csvnode_get_platform_identifier(struct vnode *vp, off_t offset)
1029 {
1030 struct cs_blob *csblob;
1031 const CS_CodeDirectory *code_dir;
1032
1033 csblob = ubc_cs_blob_get(vp, -1, offset);
1034 if (csblob == NULL) {
1035 return 0;
1036 }
1037
1038 code_dir = csblob->csb_cd;
1039 if (code_dir == NULL || ntohl(code_dir->length) < 8) {
1040 return 0;
1041 }
1042
1043 return code_dir->platform;
1044 }
1045
1046 /*
1047 * Function: csproc_get_platform_identifier
1048 *
1049 * Description: This function returns the codesign platform
1050 * identifier for the proc. Assumes proc will remain
1051 * valid through call.
1052 */
1053 uint8_t
1054 csproc_get_platform_identifier(struct proc *p)
1055 {
1056 if (NULL == p->p_textvp) {
1057 return 0;
1058 }
1059
1060 return csvnode_get_platform_identifier(p->p_textvp, p->p_textoff);
1061 }
1062
1063 uint32_t
1064 cs_entitlement_flags(struct proc *p)
1065 {
1066 return p->p_csflags & CS_ENTITLEMENT_FLAGS;
1067 }
1068
1069 int
1070 cs_restricted(struct proc *p)
1071 {
1072 return (p->p_csflags & CS_RESTRICT) ? 1 : 0;
1073 }
1074
1075 int
1076 csproc_hardened_runtime(struct proc* p)
1077 {
1078 return (p->p_csflags & CS_RUNTIME) ? 1 : 0;
1079 }
1080
1081 /*
1082 * Function: csfg_get_path
1083 *
1084 * Description: This populates the buffer passed in
1085 * with the path of the vnode
1086 * When calling this, the fileglob
1087 * cannot go away. The caller must have a
1088 * a reference on the fileglob or fileproc
1089 */
1090 int
1091 csfg_get_path(struct fileglob *fg, char *path, int *len)
1092 {
1093 vnode_t vp = NULL;
1094
1095 if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE) {
1096 return -1;
1097 }
1098
1099 vp = (struct vnode *)fg->fg_data;
1100
1101 /* vn_getpath returns 0 for success,
1102 * or an error code */
1103 return vn_getpath(vp, path, len);
1104 }
1105
1106 /* Retrieve the entitlements blob for a process.
1107 * Returns:
1108 * EINVAL no text vnode associated with the process
1109 * EBADEXEC invalid code signing data
1110 * 0 no error occurred
1111 *
1112 * On success, out_start and out_length will point to the
1113 * entitlements blob if found; or will be set to NULL/zero
1114 * if there were no entitlements.
1115 */
1116
1117 int
1118 cs_entitlements_blob_get(proc_t p, void **out_start, size_t *out_length)
1119 {
1120 struct cs_blob *csblob;
1121
1122 *out_start = NULL;
1123 *out_length = 0;
1124
1125 if ((p->p_csflags & CS_SIGNED) == 0) {
1126 return 0;
1127 }
1128
1129 if (NULL == p->p_textvp) {
1130 return EINVAL;
1131 }
1132
1133 if ((csblob = ubc_cs_blob_get(p->p_textvp, -1, p->p_textoff)) == NULL) {
1134 return 0;
1135 }
1136
1137 return csblob_get_entitlements(csblob, out_start, out_length);
1138 }
1139
1140 /* Retrieve the codesign identity for a process.
1141 * Returns:
1142 * NULL an error occured
1143 * string the cs_identity
1144 */
1145
1146 const char *
1147 cs_identity_get(proc_t p)
1148 {
1149 struct cs_blob *csblob;
1150
1151 if ((p->p_csflags & CS_SIGNED) == 0) {
1152 return NULL;
1153 }
1154
1155 if (NULL == p->p_textvp) {
1156 return NULL;
1157 }
1158
1159 if ((csblob = ubc_cs_blob_get(p->p_textvp, -1, p->p_textoff)) == NULL) {
1160 return NULL;
1161 }
1162
1163 return csblob_get_identity(csblob);
1164 }
1165
1166 /*
1167 * DO NOT USE THIS FUNCTION!
1168 * Use the properly guarded csproc_get_blob instead.
1169 *
1170 * This is currently here to allow detached signatures to work
1171 * properly. The only user of this function is also checking
1172 * for CS_VALID.
1173 */
1174
1175 int
1176 cs_blob_get(proc_t p, void **out_start, size_t *out_length)
1177 {
1178 struct cs_blob *csblob;
1179
1180 *out_start = NULL;
1181 *out_length = 0;
1182
1183 if (NULL == p->p_textvp) {
1184 return EINVAL;
1185 }
1186
1187 if ((csblob = ubc_cs_blob_get(p->p_textvp, -1, p->p_textoff)) == NULL) {
1188 return 0;
1189 }
1190
1191 *out_start = (void *)csblob->csb_mem_kaddr;
1192 *out_length = csblob->csb_mem_size;
1193
1194 return 0;
1195 }
1196
1197 /*
1198 * return cshash of a process, cdhash is of size CS_CDHASH_LEN
1199 */
1200
1201 uint8_t *
1202 cs_get_cdhash(struct proc *p)
1203 {
1204 struct cs_blob *csblob;
1205
1206 if ((p->p_csflags & CS_SIGNED) == 0) {
1207 return NULL;
1208 }
1209
1210 if (NULL == p->p_textvp) {
1211 return NULL;
1212 }
1213
1214 if ((csblob = ubc_cs_blob_get(p->p_textvp, -1, p->p_textoff)) == NULL) {
1215 return NULL;
1216 }
1217
1218 return csblob->csb_cdhash;
1219 }