]> git.saurik.com Git - apple/xnu.git/blob - bsd/kern/kern_cs.c
xnu-6153.141.1.tar.gz
[apple/xnu.git] / bsd / kern / kern_cs.c
1 /*
2 * Copyright (c) 2000-2012 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29 #include <sys/types.h>
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/kernel.h>
33 #include <sys/proc_internal.h>
34 #include <sys/sysctl.h>
35 #include <sys/signal.h>
36 #include <sys/signalvar.h>
37 #include <sys/codesign.h>
38
39 #include <sys/fcntl.h>
40 #include <sys/file.h>
41 #include <sys/file_internal.h>
42 #include <sys/kauth.h>
43 #include <sys/mount.h>
44 #include <sys/msg.h>
45 #include <sys/proc.h>
46 #include <sys/socketvar.h>
47 #include <sys/vnode.h>
48 #include <sys/vnode_internal.h>
49
50 #include <sys/ubc.h>
51 #include <sys/ubc_internal.h>
52
53 #include <security/mac.h>
54 #include <security/mac_policy.h>
55 #include <security/mac_framework.h>
56
57 #include <mach/mach_types.h>
58 #include <mach/vm_map.h>
59 #include <mach/mach_vm.h>
60
61 #include <kern/kern_types.h>
62 #include <kern/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 /* allow a debugged process to hide some (debug-only!) memory */
228 task_set_memory_ownership_transfer(p->task, TRUE);
229
230 vm_map_switch_protect(get_task_map(p->task), FALSE);
231 #endif
232 return (p->p_csflags & (CS_KILL | CS_HARD)) == 0;
233 }
234
235 int
236 cs_invalid_page(addr64_t vaddr, boolean_t *cs_killed)
237 {
238 struct proc *p;
239 int send_kill = 0, retval = 0, verbose = cs_debug;
240 uint32_t csflags;
241
242 p = current_proc();
243
244 if (verbose) {
245 printf("CODE SIGNING: cs_invalid_page(0x%llx): p=%d[%s]\n",
246 vaddr, p->p_pid, p->p_comm);
247 }
248
249 proc_lock(p);
250
251 /* XXX for testing */
252 if (cs_force_kill) {
253 p->p_csflags |= CS_KILL;
254 }
255 if (cs_force_hard) {
256 p->p_csflags |= CS_HARD;
257 }
258
259 /* CS_KILL triggers a kill signal, and no you can't have the page. Nothing else. */
260 if (p->p_csflags & CS_KILL) {
261 p->p_csflags |= CS_KILLED;
262 cs_procs_killed++;
263 send_kill = 1;
264 retval = 1;
265 }
266
267 /* CS_HARD means fail the mapping operation so the process stays valid. */
268 if (p->p_csflags & CS_HARD) {
269 retval = 1;
270 } else {
271 if (p->p_csflags & CS_VALID) {
272 p->p_csflags &= ~CS_VALID;
273 cs_procs_invalidated++;
274 verbose = 1;
275 }
276 }
277 csflags = p->p_csflags;
278 proc_unlock(p);
279
280 if (verbose) {
281 printf("CODE SIGNING: cs_invalid_page(0x%llx): "
282 "p=%d[%s] final status 0x%x, %s page%s\n",
283 vaddr, p->p_pid, p->p_comm, p->p_csflags,
284 retval ? "denying" : "allowing (remove VALID)",
285 send_kill ? " sending SIGKILL" : "");
286 }
287
288 if (send_kill) {
289 /* We will set the exit reason for the thread later */
290 threadsignal(current_thread(), SIGKILL, EXC_BAD_ACCESS, FALSE);
291 if (cs_killed) {
292 *cs_killed = TRUE;
293 }
294 } else if (cs_killed) {
295 *cs_killed = FALSE;
296 }
297
298
299 return retval;
300 }
301
302 /*
303 * Assumes p (if passed in) is locked with proc_lock().
304 */
305
306 int
307 cs_process_enforcement(struct proc *p)
308 {
309 if (cs_process_enforcement_enable) {
310 return 1;
311 }
312
313 if (p == NULL) {
314 p = current_proc();
315 }
316
317 if (p != NULL && (p->p_csflags & CS_ENFORCEMENT)) {
318 return 1;
319 }
320
321 return 0;
322 }
323
324 int
325 cs_process_global_enforcement(void)
326 {
327 return cs_process_enforcement_enable ? 1 : 0;
328 }
329
330 int
331 cs_system_enforcement(void)
332 {
333 return cs_system_enforcement_enable ? 1 : 0;
334 }
335
336 /*
337 * Returns whether a given process is still valid.
338 */
339 int
340 cs_valid(struct proc *p)
341 {
342 if (p == NULL) {
343 p = current_proc();
344 }
345
346 if (p != NULL && (p->p_csflags & CS_VALID)) {
347 return 1;
348 }
349
350 return 0;
351 }
352
353 /*
354 * Library validation functions
355 */
356 int
357 cs_require_lv(struct proc *p)
358 {
359 if (cs_library_val_enable) {
360 return 1;
361 }
362
363 if (p == NULL) {
364 p = current_proc();
365 }
366
367 if (p != NULL && (p->p_csflags & CS_REQUIRE_LV)) {
368 return 1;
369 }
370
371 return 0;
372 }
373
374 int
375 csproc_forced_lv(struct proc* p)
376 {
377 if (p == NULL) {
378 p = current_proc();
379 }
380 if (p != NULL && (p->p_csflags & CS_FORCED_LV)) {
381 return 1;
382 }
383 return 0;
384 }
385
386 /*
387 * <rdar://problem/24634089> added to allow system level library
388 * validation check at mac_cred_label_update_execve time
389 */
390 int
391 cs_system_require_lv(void)
392 {
393 return cs_library_val_enable ? 1 : 0;
394 }
395
396 /*
397 * Function: csblob_get_base_offset
398 *
399 * Description: This function returns the base offset into the (possibly universal) binary
400 * for a given blob.
401 */
402
403 off_t
404 csblob_get_base_offset(struct cs_blob *blob)
405 {
406 return blob->csb_base_offset;
407 }
408
409 /*
410 * Function: csblob_get_size
411 *
412 * Description: This function returns the size of a given blob.
413 */
414
415 vm_size_t
416 csblob_get_size(struct cs_blob *blob)
417 {
418 return blob->csb_mem_size;
419 }
420
421 /*
422 * Function: csblob_get_addr
423 *
424 * Description: This function returns the address of a given blob.
425 */
426
427 vm_address_t
428 csblob_get_addr(struct cs_blob *blob)
429 {
430 return blob->csb_mem_kaddr;
431 }
432
433 /*
434 * Function: csblob_get_platform_binary
435 *
436 * Description: This function returns true if the binary is
437 * in the trust cache.
438 */
439
440 int
441 csblob_get_platform_binary(struct cs_blob *blob)
442 {
443 if (blob && blob->csb_platform_binary) {
444 return 1;
445 }
446 return 0;
447 }
448
449 /*
450 * Function: csblob_get_flags
451 *
452 * Description: This function returns the flags for a given blob
453 */
454
455 unsigned int
456 csblob_get_flags(struct cs_blob *blob)
457 {
458 return blob->csb_flags;
459 }
460
461 /*
462 * Function: csblob_get_hashtype
463 *
464 * Description: This function returns the hash type for a given blob
465 */
466
467 uint8_t
468 csblob_get_hashtype(struct cs_blob const * const blob)
469 {
470 return blob->csb_hashtype != NULL ? cs_hash_type(blob->csb_hashtype) : 0;
471 }
472
473 /*
474 * Function: csproc_get_blob
475 *
476 * Description: This function returns the cs_blob
477 * for the process p
478 */
479 struct cs_blob *
480 csproc_get_blob(struct proc *p)
481 {
482 if (NULL == p) {
483 return NULL;
484 }
485
486 if (NULL == p->p_textvp) {
487 return NULL;
488 }
489
490 if ((p->p_csflags & CS_SIGNED) == 0) {
491 return NULL;
492 }
493
494 return ubc_cs_blob_get(p->p_textvp, -1, p->p_textoff);
495 }
496
497 /*
498 * Function: csvnode_get_blob
499 *
500 * Description: This function returns the cs_blob
501 * for the vnode vp
502 */
503 struct cs_blob *
504 csvnode_get_blob(struct vnode *vp, off_t offset)
505 {
506 return ubc_cs_blob_get(vp, -1, offset);
507 }
508
509 /*
510 * Function: csblob_get_teamid
511 *
512 * Description: This function returns a pointer to the
513 * team id of csblob
514 */
515 const char *
516 csblob_get_teamid(struct cs_blob *csblob)
517 {
518 return csblob->csb_teamid;
519 }
520
521 /*
522 * Function: csblob_get_identity
523 *
524 * Description: This function returns a pointer to the
525 * identity string
526 */
527 const char *
528 csblob_get_identity(struct cs_blob *csblob)
529 {
530 const CS_CodeDirectory *cd;
531
532 cd = (const CS_CodeDirectory *)csblob_find_blob(csblob, CSSLOT_CODEDIRECTORY, CSMAGIC_CODEDIRECTORY);
533 if (cd == NULL) {
534 return NULL;
535 }
536
537 if (cd->identOffset == 0) {
538 return NULL;
539 }
540
541 return ((const char *)cd) + ntohl(cd->identOffset);
542 }
543
544 /*
545 * Function: csblob_get_cdhash
546 *
547 * Description: This function returns a pointer to the
548 * cdhash of csblob (20 byte array)
549 */
550 const uint8_t *
551 csblob_get_cdhash(struct cs_blob *csblob)
552 {
553 return csblob->csb_cdhash;
554 }
555
556 /*
557 * Function: csblob_get_signer_type
558 *
559 * Description: This function returns the signer type
560 * as an integer
561 */
562 unsigned int
563 csblob_get_signer_type(struct cs_blob *csblob)
564 {
565 return csblob->csb_signer_type;
566 }
567
568 void *
569 csblob_entitlements_dictionary_copy(struct cs_blob *csblob)
570 {
571 if (!csblob->csb_entitlements) {
572 return NULL;
573 }
574 osobject_retain(csblob->csb_entitlements);
575 return csblob->csb_entitlements;
576 }
577
578 void
579 csblob_entitlements_dictionary_set(struct cs_blob *csblob, void * entitlements)
580 {
581 assert(csblob->csb_entitlements == NULL);
582 if (entitlements) {
583 osobject_retain(entitlements);
584 }
585 csblob->csb_entitlements = entitlements;
586 }
587
588 /*
589 * Function: csproc_get_teamid
590 *
591 * Description: This function returns a pointer to the
592 * team id of the process p
593 */
594 const char *
595 csproc_get_teamid(struct proc *p)
596 {
597 struct cs_blob *csblob;
598
599 csblob = csproc_get_blob(p);
600 if (csblob == NULL) {
601 return NULL;
602 }
603
604 return csblob_get_teamid(csblob);
605 }
606
607 /*
608 * Function: csproc_get_signer_type
609 *
610 * Description: This function returns the signer type
611 * of the process p
612 */
613 unsigned int
614 csproc_get_signer_type(struct proc *p)
615 {
616 struct cs_blob *csblob;
617
618 csblob = csproc_get_blob(p);
619 if (csblob == NULL) {
620 return CS_SIGNER_TYPE_UNKNOWN;
621 }
622
623 return csblob_get_signer_type(csblob);
624 }
625
626 /*
627 * Function: csvnode_get_teamid
628 *
629 * Description: This function returns a pointer to the
630 * team id of the binary at the given offset in vnode vp
631 */
632 const char *
633 csvnode_get_teamid(struct vnode *vp, off_t offset)
634 {
635 struct cs_blob *csblob;
636
637 if (vp == NULL) {
638 return NULL;
639 }
640
641 csblob = ubc_cs_blob_get(vp, -1, offset);
642 if (csblob == NULL) {
643 return NULL;
644 }
645
646 return csblob_get_teamid(csblob);
647 }
648
649 /*
650 * Function: csproc_get_platform_binary
651 *
652 * Description: This function returns the value
653 * of the platform_binary field for proc p
654 */
655 int
656 csproc_get_platform_binary(struct proc *p)
657 {
658 struct cs_blob *csblob;
659
660 csblob = csproc_get_blob(p);
661
662 /* If there is no csblob this returns 0 because
663 * it is true that it is not a platform binary */
664 return (csblob == NULL) ? 0 : csblob->csb_platform_binary;
665 }
666
667 int
668 csproc_get_platform_path(struct proc *p)
669 {
670 struct cs_blob *csblob;
671
672 csblob = csproc_get_blob(p);
673
674 return (csblob == NULL) ? 0 : csblob->csb_platform_path;
675 }
676
677 #if DEVELOPMENT || DEBUG
678 void
679 csproc_clear_platform_binary(struct proc *p)
680 {
681 struct cs_blob *csblob = csproc_get_blob(p);
682
683 if (csblob == NULL) {
684 return;
685 }
686
687 if (cs_debug) {
688 printf("clearing platform binary on proc/task: pid = %d\n", p->p_pid);
689 }
690
691 csblob->csb_platform_binary = 0;
692 csblob->csb_platform_path = 0;
693 task_set_platform_binary(proc_task(p), FALSE);
694 }
695 #endif
696
697 void
698 csproc_disable_enforcement(struct proc* __unused p)
699 {
700 #if !CONFIG_ENFORCE_SIGNED_CODE
701 if (p != NULL) {
702 proc_lock(p);
703 p->p_csflags &= (~CS_ENFORCEMENT);
704 proc_unlock(p);
705 }
706 #endif
707 }
708
709 /* Function: csproc_mark_invalid_allowed
710 *
711 * Description: Mark the process as being allowed to go invalid. Called as part of
712 * task_for_pid and ptrace policy. Note CS_INVALID_ALLOWED only matters for
713 * processes that have been opted into CS_ENFORCEMENT.
714 */
715 void
716 csproc_mark_invalid_allowed(struct proc* __unused p)
717 {
718 #if !CONFIG_ENFORCE_SIGNED_CODE
719 if (p != NULL) {
720 proc_lock(p);
721 p->p_csflags |= CS_INVALID_ALLOWED;
722 proc_unlock(p);
723 }
724 #endif
725 }
726
727 /*
728 * Function: csproc_check_invalid_allowed
729 *
730 * Description: Returns 1 if the process has been marked as allowed to go invalid
731 * because it gave its task port to an allowed process.
732 */
733 int
734 csproc_check_invalid_allowed(struct proc* __unused p)
735 {
736 #if !CONFIG_ENFORCE_SIGNED_CODE
737 if (p == NULL) {
738 p = current_proc();
739 }
740
741 if (p != NULL && (p->p_csflags & CS_INVALID_ALLOWED)) {
742 return 1;
743 }
744 #endif
745 return 0;
746 }
747
748 /*
749 * Function: csproc_get_prod_signed
750 *
751 * Description: Returns 1 if process is not signed with a developer identity.
752 * Note the inverted meaning from the cs_flag to make the error case safer.
753 * Will go away with rdar://problem/28322552.
754 */
755 int
756 csproc_get_prod_signed(struct proc *p)
757 {
758 return (p->p_csflags & CS_DEV_CODE) == 0;
759 }
760
761
762 /*
763 * Function: csfg_get_platform_binary
764 *
765 * Description: This function returns the
766 * platform binary field for the
767 * fileglob fg
768 */
769 int
770 csfg_get_platform_binary(struct fileglob *fg)
771 {
772 int platform_binary = 0;
773 struct ubc_info *uip;
774 vnode_t vp;
775
776 if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE) {
777 return 0;
778 }
779
780 vp = (struct vnode *)fg->fg_data;
781 if (vp == NULL) {
782 return 0;
783 }
784
785 vnode_lock(vp);
786 if (!UBCINFOEXISTS(vp)) {
787 goto out;
788 }
789
790 uip = vp->v_ubcinfo;
791 if (uip == NULL) {
792 goto out;
793 }
794
795 if (uip->cs_blobs == NULL) {
796 goto out;
797 }
798
799 /* It is OK to extract the teamid from the first blob
800 * because all blobs of a vnode must have the same teamid */
801 platform_binary = uip->cs_blobs->csb_platform_binary;
802 out:
803 vnode_unlock(vp);
804
805 return platform_binary;
806 }
807
808 uint8_t *
809 csfg_get_cdhash(struct fileglob *fg, uint64_t offset, size_t *cdhash_size)
810 {
811 vnode_t vp;
812
813 if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE) {
814 return NULL;
815 }
816
817 vp = (struct vnode *)fg->fg_data;
818 if (vp == NULL) {
819 return NULL;
820 }
821
822 struct cs_blob *csblob = NULL;
823 if ((csblob = ubc_cs_blob_get(vp, -1, offset)) == NULL) {
824 return NULL;
825 }
826
827 if (cdhash_size) {
828 *cdhash_size = CS_CDHASH_LEN;
829 }
830
831 return csblob->csb_cdhash;
832 }
833
834 /*
835 * Function: csfg_get_signer_type
836 *
837 * Description: This returns the signer type
838 * for the fileglob fg
839 */
840 unsigned int
841 csfg_get_signer_type(struct fileglob *fg)
842 {
843 struct ubc_info *uip;
844 unsigned int signer_type = CS_SIGNER_TYPE_UNKNOWN;
845 vnode_t vp;
846
847 if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE) {
848 return CS_SIGNER_TYPE_UNKNOWN;
849 }
850
851 vp = (struct vnode *)fg->fg_data;
852 if (vp == NULL) {
853 return CS_SIGNER_TYPE_UNKNOWN;
854 }
855
856 vnode_lock(vp);
857 if (!UBCINFOEXISTS(vp)) {
858 goto out;
859 }
860
861 uip = vp->v_ubcinfo;
862 if (uip == NULL) {
863 goto out;
864 }
865
866 if (uip->cs_blobs == NULL) {
867 goto out;
868 }
869
870 /* It is OK to extract the signer type from the first blob,
871 * because all blobs of a vnode must have the same signer type. */
872 signer_type = uip->cs_blobs->csb_signer_type;
873 out:
874 vnode_unlock(vp);
875
876 return signer_type;
877 }
878
879 /*
880 * Function: csfg_get_teamid
881 *
882 * Description: This returns a pointer to
883 * the teamid for the fileglob fg
884 */
885 const char *
886 csfg_get_teamid(struct fileglob *fg)
887 {
888 struct ubc_info *uip;
889 const char *str = NULL;
890 vnode_t vp;
891
892 if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE) {
893 return NULL;
894 }
895
896 vp = (struct vnode *)fg->fg_data;
897 if (vp == NULL) {
898 return NULL;
899 }
900
901 vnode_lock(vp);
902 if (!UBCINFOEXISTS(vp)) {
903 goto out;
904 }
905
906 uip = vp->v_ubcinfo;
907 if (uip == NULL) {
908 goto out;
909 }
910
911 if (uip->cs_blobs == NULL) {
912 goto out;
913 }
914
915 /* It is OK to extract the teamid from the first blob
916 * because all blobs of a vnode must have the same teamid */
917 str = uip->cs_blobs->csb_teamid;
918 out:
919 vnode_unlock(vp);
920
921 return str;
922 }
923
924 /*
925 * Function: csfg_get_prod_signed
926 *
927 * Description: Returns 1 if code is not signed with a developer identity.
928 * Note the inverted meaning from the cs_flag to make the error case safer.
929 * Will go away with rdar://problem/28322552.
930 */
931 int
932 csfg_get_prod_signed(struct fileglob *fg)
933 {
934 struct ubc_info *uip;
935 vnode_t vp;
936 int prod_signed = 0;
937
938 if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE) {
939 return 0;
940 }
941
942 vp = (struct vnode *)fg->fg_data;
943 if (vp == NULL) {
944 return 0;
945 }
946
947 vnode_lock(vp);
948 if (!UBCINFOEXISTS(vp)) {
949 goto out;
950 }
951
952 uip = vp->v_ubcinfo;
953 if (uip == NULL) {
954 goto out;
955 }
956
957 if (uip->cs_blobs == NULL) {
958 goto out;
959 }
960
961 /* It is OK to extract the flag from the first blob
962 * because all blobs of a vnode must have the same cs_flags */
963 prod_signed = (uip->cs_blobs->csb_flags & CS_DEV_CODE) == 0;
964 out:
965 vnode_unlock(vp);
966
967 return prod_signed;
968 }
969
970 /*
971 * Function: csfg_get_identity
972 *
973 * Description: This function returns the codesign identity
974 * for the fileglob
975 */
976 const char *
977 csfg_get_identity(struct fileglob *fg, off_t offset)
978 {
979 vnode_t vp;
980 struct cs_blob *csblob = NULL;
981
982 if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE) {
983 return NULL;
984 }
985
986 vp = (struct vnode *)fg->fg_data;
987 if (vp == NULL) {
988 return NULL;
989 }
990
991 csblob = ubc_cs_blob_get(vp, -1, offset);
992 if (csblob == NULL) {
993 return NULL;
994 }
995
996 return csblob_get_identity(csblob);
997 }
998
999 /*
1000 * Function: csfg_get_platform_identifier
1001 *
1002 * Description: This function returns the codesign platform
1003 * identifier for the fileglob. Assumes the fileproc
1004 * is being held busy to keep the fileglob consistent.
1005 */
1006 uint8_t
1007 csfg_get_platform_identifier(struct fileglob *fg, off_t offset)
1008 {
1009 vnode_t vp;
1010
1011 if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE) {
1012 return 0;
1013 }
1014
1015 vp = (struct vnode *)fg->fg_data;
1016 if (vp == NULL) {
1017 return 0;
1018 }
1019
1020 return csvnode_get_platform_identifier(vp, offset);
1021 }
1022
1023 /*
1024 * Function: csvnode_get_platform_identifier
1025 *
1026 * Description: This function returns the codesign platform
1027 * identifier for the vnode. Assumes a vnode reference
1028 * is held.
1029 */
1030 uint8_t
1031 csvnode_get_platform_identifier(struct vnode *vp, off_t offset)
1032 {
1033 struct cs_blob *csblob;
1034 const CS_CodeDirectory *code_dir;
1035
1036 csblob = ubc_cs_blob_get(vp, -1, offset);
1037 if (csblob == NULL) {
1038 return 0;
1039 }
1040
1041 code_dir = csblob->csb_cd;
1042 if (code_dir == NULL || ntohl(code_dir->length) < 8) {
1043 return 0;
1044 }
1045
1046 return code_dir->platform;
1047 }
1048
1049 /*
1050 * Function: csproc_get_platform_identifier
1051 *
1052 * Description: This function returns the codesign platform
1053 * identifier for the proc. Assumes proc will remain
1054 * valid through call.
1055 */
1056 uint8_t
1057 csproc_get_platform_identifier(struct proc *p)
1058 {
1059 if (NULL == p->p_textvp) {
1060 return 0;
1061 }
1062
1063 return csvnode_get_platform_identifier(p->p_textvp, p->p_textoff);
1064 }
1065
1066 uint32_t
1067 cs_entitlement_flags(struct proc *p)
1068 {
1069 return p->p_csflags & CS_ENTITLEMENT_FLAGS;
1070 }
1071
1072 int
1073 cs_restricted(struct proc *p)
1074 {
1075 return (p->p_csflags & CS_RESTRICT) ? 1 : 0;
1076 }
1077
1078 int
1079 csproc_hardened_runtime(struct proc* p)
1080 {
1081 return (p->p_csflags & CS_RUNTIME) ? 1 : 0;
1082 }
1083
1084 /*
1085 * Function: csfg_get_path
1086 *
1087 * Description: This populates the buffer passed in
1088 * with the path of the vnode
1089 * When calling this, the fileglob
1090 * cannot go away. The caller must have a
1091 * a reference on the fileglob or fileproc
1092 */
1093 int
1094 csfg_get_path(struct fileglob *fg, char *path, int *len)
1095 {
1096 vnode_t vp = NULL;
1097
1098 if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE) {
1099 return -1;
1100 }
1101
1102 vp = (struct vnode *)fg->fg_data;
1103
1104 /* vn_getpath returns 0 for success,
1105 * or an error code */
1106 return vn_getpath(vp, path, len);
1107 }
1108
1109 /* Retrieve the entitlements blob for a process.
1110 * Returns:
1111 * EINVAL no text vnode associated with the process
1112 * EBADEXEC invalid code signing data
1113 * 0 no error occurred
1114 *
1115 * On success, out_start and out_length will point to the
1116 * entitlements blob if found; or will be set to NULL/zero
1117 * if there were no entitlements.
1118 */
1119
1120 int
1121 cs_entitlements_blob_get(proc_t p, void **out_start, size_t *out_length)
1122 {
1123 struct cs_blob *csblob;
1124
1125 *out_start = NULL;
1126 *out_length = 0;
1127
1128 if ((p->p_csflags & CS_SIGNED) == 0) {
1129 return 0;
1130 }
1131
1132 if (NULL == p->p_textvp) {
1133 return EINVAL;
1134 }
1135
1136 if ((csblob = ubc_cs_blob_get(p->p_textvp, -1, p->p_textoff)) == NULL) {
1137 return 0;
1138 }
1139
1140 return csblob_get_entitlements(csblob, out_start, out_length);
1141 }
1142
1143
1144 /* Retrieve the cached entitlements for a process
1145 * Returns:
1146 * EINVAL no text vnode associated with the process
1147 * EBADEXEC invalid code signing data
1148 * 0 no error occurred
1149 *
1150 * Note: the entitlements may be NULL if there is nothing cached.
1151 */
1152
1153 int
1154 cs_entitlements_dictionary_copy(proc_t p, void **entitlements)
1155 {
1156 struct cs_blob *csblob;
1157
1158 *entitlements = NULL;
1159
1160 if ((p->p_csflags & CS_SIGNED) == 0) {
1161 return 0;
1162 }
1163
1164 if (NULL == p->p_textvp) {
1165 return EINVAL;
1166 }
1167
1168 if ((csblob = ubc_cs_blob_get(p->p_textvp, -1, p->p_textoff)) == NULL) {
1169 return 0;
1170 }
1171
1172 *entitlements = csblob_entitlements_dictionary_copy(csblob);
1173 return 0;
1174 }
1175
1176 /* Retrieve the codesign identity for a process.
1177 * Returns:
1178 * NULL an error occured
1179 * string the cs_identity
1180 */
1181
1182 const char *
1183 cs_identity_get(proc_t p)
1184 {
1185 struct cs_blob *csblob;
1186
1187 if ((p->p_csflags & CS_SIGNED) == 0) {
1188 return NULL;
1189 }
1190
1191 if (NULL == p->p_textvp) {
1192 return NULL;
1193 }
1194
1195 if ((csblob = ubc_cs_blob_get(p->p_textvp, -1, p->p_textoff)) == NULL) {
1196 return NULL;
1197 }
1198
1199 return csblob_get_identity(csblob);
1200 }
1201
1202 /*
1203 * DO NOT USE THIS FUNCTION!
1204 * Use the properly guarded csproc_get_blob instead.
1205 *
1206 * This is currently here to allow detached signatures to work
1207 * properly. The only user of this function is also checking
1208 * for CS_VALID.
1209 */
1210
1211 int
1212 cs_blob_get(proc_t p, void **out_start, size_t *out_length)
1213 {
1214 struct cs_blob *csblob;
1215
1216 *out_start = NULL;
1217 *out_length = 0;
1218
1219 if (NULL == p->p_textvp) {
1220 return EINVAL;
1221 }
1222
1223 if ((csblob = ubc_cs_blob_get(p->p_textvp, -1, p->p_textoff)) == NULL) {
1224 return 0;
1225 }
1226
1227 *out_start = (void *)csblob->csb_mem_kaddr;
1228 *out_length = csblob->csb_mem_size;
1229
1230 return 0;
1231 }
1232
1233 /*
1234 * return cshash of a process, cdhash is of size CS_CDHASH_LEN
1235 */
1236
1237 uint8_t *
1238 cs_get_cdhash(struct proc *p)
1239 {
1240 struct cs_blob *csblob;
1241
1242 if ((p->p_csflags & CS_SIGNED) == 0) {
1243 return NULL;
1244 }
1245
1246 if (NULL == p->p_textvp) {
1247 return NULL;
1248 }
1249
1250 if ((csblob = ubc_cs_blob_get(p->p_textvp, -1, p->p_textoff)) == NULL) {
1251 return NULL;
1252 }
1253
1254 return csblob->csb_cdhash;
1255 }