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