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