2 * Copyright (c) 2000-2012 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
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>
39 #include <sys/fcntl.h>
41 #include <sys/file_internal.h>
42 #include <sys/kauth.h>
43 #include <sys/mount.h>
46 #include <sys/socketvar.h>
47 #include <sys/vnode.h>
48 #include <sys/vnode_internal.h>
51 #include <sys/ubc_internal.h>
53 #include <security/mac.h>
54 #include <security/mac_policy.h>
55 #include <security/mac_framework.h>
57 #include <mach/mach_types.h>
58 #include <mach/vm_map.h>
59 #include <mach/mach_vm.h>
61 #include <kern/kern_types.h>
62 #include <kern/startup.h>
63 #include <kern/task.h>
65 #include <vm/vm_map.h>
66 #include <vm/vm_kern.h>
69 #include <kern/assert.h>
71 #include <pexpert/pexpert.h>
73 #include <mach/shared_region.h>
75 #include <libkern/section_keywords.h>
76 #include <libkern/ptrauth_utils.h>
79 unsigned long cs_procs_killed
= 0;
80 unsigned long cs_procs_invalidated
= 0;
82 int cs_force_kill
= 0;
83 int cs_force_hard
= 0;
85 // If set, AMFI will error out early on unsigned code, before evaluation the normal policy.
86 int cs_debug_fail_on_unsigned_code
= 0;
87 // If the previous mode is enabled, we count the resulting failures here.
88 unsigned int cs_debug_unsigned_exec_failures
= 0;
89 unsigned int cs_debug_unsigned_mmap_failures
= 0;
91 #if CONFIG_ENFORCE_SIGNED_CODE
92 #define DEFAULT_CS_SYSTEM_ENFORCEMENT_ENABLE 1
93 #define DEFAULT_CS_PROCESS_ENFORCEMENT_ENABLE 1
95 #define DEFAULT_CS_SYSTEM_ENFORCEMENT_ENABLE 1
96 #define DEFAULT_CS_PROCESS_ENFORCEMENT_ENABLE 0
99 #if CONFIG_ENFORCE_LIBRARY_VALIDATION
100 #define DEFAULT_CS_LIBRARY_VA_ENABLE 1
102 #define DEFAULT_CS_LIBRARY_VA_ENABLE 0
108 * Here we split cs_enforcement_enable into cs_system_enforcement_enable and cs_process_enforcement_enable
110 * cs_system_enforcement_enable governs whether or not system level code signing enforcement mechanisms
111 * are applied on the system. Today, the only such mechanism is code signing enforcement of the dyld shared
114 * cs_process_enforcement_enable governs whether code signing enforcement mechanisms are applied to all
115 * processes or only those that opt into such enforcement.
117 * (On iOS and related, both of these are set by default. On macOS, only cs_system_enforcement_enable
118 * is set by default. Processes can then be opted into code signing enforcement on a case by case basis.)
120 SECURITY_READ_ONLY_EARLY(int) cs_system_enforcement_enable
= DEFAULT_CS_SYSTEM_ENFORCEMENT_ENABLE
;
121 SECURITY_READ_ONLY_EARLY(int) cs_process_enforcement_enable
= DEFAULT_CS_PROCESS_ENFORCEMENT_ENABLE
;
122 SECURITY_READ_ONLY_EARLY(int) cs_library_val_enable
= DEFAULT_CS_LIBRARY_VA_ENABLE
;
124 #else /* !SECURE_KERNEL */
125 int cs_enforcement_panic
= 0;
126 int cs_relax_platform_task_ports
= 0;
128 SECURITY_READ_ONLY_LATE(int) cs_system_enforcement_enable
= DEFAULT_CS_SYSTEM_ENFORCEMENT_ENABLE
;
129 SECURITY_READ_ONLY_LATE(int) cs_process_enforcement_enable
= DEFAULT_CS_PROCESS_ENFORCEMENT_ENABLE
;
131 SECURITY_READ_ONLY_LATE(int) cs_library_val_enable
= DEFAULT_CS_LIBRARY_VA_ENABLE
;
133 #endif /* !SECURE_KERNEL */
134 int cs_all_vnodes
= 0;
136 static lck_grp_t
*cs_lockgrp
;
138 SYSCTL_INT(_vm
, OID_AUTO
, cs_force_kill
, CTLFLAG_RW
| CTLFLAG_LOCKED
, &cs_force_kill
, 0, "");
139 SYSCTL_INT(_vm
, OID_AUTO
, cs_force_hard
, CTLFLAG_RW
| CTLFLAG_LOCKED
, &cs_force_hard
, 0, "");
140 SYSCTL_INT(_vm
, OID_AUTO
, cs_debug
, CTLFLAG_RW
| CTLFLAG_LOCKED
, &cs_debug
, 0, "");
141 SYSCTL_INT(_vm
, OID_AUTO
, cs_debug_fail_on_unsigned_code
, CTLFLAG_RW
| CTLFLAG_LOCKED
,
142 &cs_debug_fail_on_unsigned_code
, 0, "");
143 SYSCTL_UINT(_vm
, OID_AUTO
, cs_debug_unsigned_exec_failures
, CTLFLAG_RD
| CTLFLAG_LOCKED
,
144 &cs_debug_unsigned_exec_failures
, 0, "");
145 SYSCTL_UINT(_vm
, OID_AUTO
, cs_debug_unsigned_mmap_failures
, CTLFLAG_RD
| CTLFLAG_LOCKED
,
146 &cs_debug_unsigned_mmap_failures
, 0, "");
148 SYSCTL_INT(_vm
, OID_AUTO
, cs_all_vnodes
, CTLFLAG_RW
| CTLFLAG_LOCKED
, &cs_all_vnodes
, 0, "");
151 SYSCTL_INT(_vm
, OID_AUTO
, cs_system_enforcement
, CTLFLAG_RD
| CTLFLAG_LOCKED
, &cs_system_enforcement_enable
, 0, "");
152 SYSCTL_INT(_vm
, OID_AUTO
, cs_process_enforcement
, CTLFLAG_RW
| CTLFLAG_LOCKED
, &cs_process_enforcement_enable
, 0, "");
153 SYSCTL_INT(_vm
, OID_AUTO
, cs_enforcement_panic
, CTLFLAG_RW
| CTLFLAG_LOCKED
, &cs_enforcement_panic
, 0, "");
155 #if !CONFIG_ENFORCE_LIBRARY_VALIDATION
156 SYSCTL_INT(_vm
, OID_AUTO
, cs_library_validation
, CTLFLAG_RD
| CTLFLAG_LOCKED
, &cs_library_val_enable
, 0, "");
158 #endif /* !SECURE_KERNEL */
160 int panic_on_cs_killed
= 0;
167 #if PLATFORM_WatchOS || __x86_64__
168 panic_on_cs_killed
= 1;
169 #endif /* watchos || x86_64 */
170 #endif /* MACH_ASSERT */
171 PE_parse_boot_argn("panic_on_cs_killed", &panic_on_cs_killed
,
172 sizeof(panic_on_cs_killed
));
174 int disable_cs_enforcement
= 0;
175 PE_parse_boot_argn("cs_enforcement_disable", &disable_cs_enforcement
,
176 sizeof(disable_cs_enforcement
));
177 if (disable_cs_enforcement
&& PE_i_can_has_debugger(NULL
) != 0) {
178 cs_system_enforcement_enable
= 0;
179 cs_process_enforcement_enable
= 0;
182 PE_parse_boot_argn("cs_enforcement_panic", &panic
, sizeof(panic
));
183 cs_enforcement_panic
= (panic
!= 0);
186 PE_parse_boot_argn("cs_relax_platform_task_ports",
187 &cs_relax_platform_task_ports
,
188 sizeof(cs_relax_platform_task_ports
));
190 PE_parse_boot_argn("cs_debug", &cs_debug
, sizeof(cs_debug
));
192 #if !CONFIG_ENFORCE_LIBRARY_VALIDATION
193 PE_parse_boot_argn("cs_library_val_enable", &cs_library_val_enable
,
194 sizeof(cs_library_val_enable
));
196 #endif /* !SECURE_KERNEL */
198 lck_grp_attr_t
*attr
= lck_grp_attr_alloc_init();
199 cs_lockgrp
= lck_grp_alloc_init("KERNCS", attr
);
200 lck_grp_attr_free(attr
);
202 STARTUP(CODESIGNING
, STARTUP_RANK_FIRST
, cs_init
);
205 cs_allow_invalid(struct proc
*p
)
208 lck_mtx_assert(&p
->p_mlock
, LCK_MTX_ASSERT_NOTOWNED
);
211 /* There needs to be a MAC policy to implement this hook, or else the
212 * kill bits will be cleared here every time. If we have
213 * CONFIG_ENFORCE_SIGNED_CODE, we can assume there is a policy
214 * implementing the hook.
216 if (0 != mac_proc_check_run_cs_invalid(p
)) {
218 printf("CODE SIGNING: cs_allow_invalid() "
219 "not allowed: pid %d\n",
225 printf("CODE SIGNING: cs_allow_invalid() "
230 p
->p_csflags
&= ~(CS_KILL
| CS_HARD
);
231 if (p
->p_csflags
& CS_VALID
) {
232 p
->p_csflags
|= CS_DEBUGGED
;
236 /* allow a debugged process to hide some (debug-only!) memory */
237 task_set_memory_ownership_transfer(p
->task
, TRUE
);
239 vm_map_switch_protect(get_task_map(p
->task
), FALSE
);
241 return (p
->p_csflags
& (CS_KILL
| CS_HARD
)) == 0;
245 cs_invalid_page(addr64_t vaddr
, boolean_t
*cs_killed
)
248 int send_kill
= 0, retval
= 0, verbose
= cs_debug
;
253 printf("CODE SIGNING: cs_invalid_page(0x%llx): p=%d[%s]\n",
254 vaddr
, p
->p_pid
, p
->p_comm
);
259 /* XXX for testing */
261 p
->p_csflags
|= CS_KILL
;
264 p
->p_csflags
|= CS_HARD
;
267 /* CS_KILL triggers a kill signal, and no you can't have the page. Nothing else. */
268 if (p
->p_csflags
& CS_KILL
) {
269 p
->p_csflags
|= CS_KILLED
;
275 /* CS_HARD means fail the mapping operation so the process stays valid. */
276 if (p
->p_csflags
& CS_HARD
) {
279 if (p
->p_csflags
& CS_VALID
) {
280 p
->p_csflags
&= ~CS_VALID
;
281 cs_procs_invalidated
++;
283 cs_process_invalidated(NULL
);
289 printf("CODE SIGNING: cs_invalid_page(0x%llx): "
290 "p=%d[%s] final status 0x%x, %s page%s\n",
291 vaddr
, p
->p_pid
, p
->p_comm
, p
->p_csflags
,
292 retval
? "denying" : "allowing (remove VALID)",
293 send_kill
? " sending SIGKILL" : "");
297 /* We will set the exit reason for the thread later */
298 threadsignal(current_thread(), SIGKILL
, EXC_BAD_ACCESS
, FALSE
);
302 } else if (cs_killed
) {
310 * Called after a process got its CS_VALID bit removed, either by
311 * a previous call to cs_invalid_page, or through other means.
312 * Called from fault handler with vm object lock held.
313 * Called with proc lock held for current_proc or, if passed in, p,
314 * to ensure MACF hook can suspend the task before other threads
315 * can access the memory that is paged in after cs_invalid_page
316 * returns 0 due to missing CS_HARD|CS_KILL.
319 cs_process_invalidated(struct proc
* __unused p
)
325 mac_proc_notify_cs_invalidated(p
);
330 * Assumes p (if passed in) is locked with proc_lock().
334 cs_process_enforcement(struct proc
*p
)
336 if (cs_process_enforcement_enable
) {
344 if (p
!= NULL
&& (p
->p_csflags
& CS_ENFORCEMENT
)) {
352 cs_process_global_enforcement(void)
354 return cs_process_enforcement_enable
? 1 : 0;
358 cs_system_enforcement(void)
360 return cs_system_enforcement_enable
? 1 : 0;
364 cs_vm_supports_4k_translations(void)
371 * Returns whether a given process is still valid.
374 cs_valid(struct proc
*p
)
380 if (p
!= NULL
&& (p
->p_csflags
& CS_VALID
)) {
388 * Library validation functions
391 cs_require_lv(struct proc
*p
)
393 if (cs_library_val_enable
) {
401 if (p
!= NULL
&& (p
->p_csflags
& CS_REQUIRE_LV
)) {
409 csproc_forced_lv(struct proc
* p
)
414 if (p
!= NULL
&& (p
->p_csflags
& CS_FORCED_LV
)) {
421 * <rdar://problem/24634089> added to allow system level library
422 * validation check at mac_cred_label_update_execve time
425 cs_system_require_lv(void)
427 return cs_library_val_enable
? 1 : 0;
431 * Function: csblob_get_base_offset
433 * Description: This function returns the base offset into the (possibly universal) binary
438 csblob_get_base_offset(struct cs_blob
*blob
)
440 return blob
->csb_base_offset
;
444 * Function: csblob_get_size
446 * Description: This function returns the size of a given blob.
450 csblob_get_size(struct cs_blob
*blob
)
452 return blob
->csb_mem_size
;
456 * Function: csblob_get_addr
458 * Description: This function returns the address of a given blob.
462 csblob_get_addr(struct cs_blob
*blob
)
464 return blob
->csb_mem_kaddr
;
468 * Function: csblob_get_platform_binary
470 * Description: This function returns true if the binary is
471 * in the trust cache.
475 csblob_get_platform_binary(struct cs_blob
*blob
)
477 if (blob
&& blob
->csb_platform_binary
) {
484 * Function: csblob_get_flags
486 * Description: This function returns the flags for a given blob
490 csblob_get_flags(struct cs_blob
*blob
)
492 return blob
->csb_flags
;
496 * Function: csblob_get_hashtype
498 * Description: This function returns the hash type for a given blob
502 csblob_get_hashtype(struct cs_blob
const * const blob
)
504 return blob
->csb_hashtype
!= NULL
? cs_hash_type(blob
->csb_hashtype
) : 0;
508 * Function: csproc_get_blob
510 * Description: This function returns the cs_blob
514 csproc_get_blob(struct proc
*p
)
520 if (NULL
== p
->p_textvp
) {
524 if ((p
->p_csflags
& CS_SIGNED
) == 0) {
528 return ubc_cs_blob_get(p
->p_textvp
, -1, -1, p
->p_textoff
);
532 * Function: csvnode_get_blob
534 * Description: This function returns the cs_blob
538 csvnode_get_blob(struct vnode
*vp
, off_t offset
)
540 return ubc_cs_blob_get(vp
, -1, -1, offset
);
544 * Function: csblob_get_teamid
546 * Description: This function returns a pointer to the
550 csblob_get_teamid(struct cs_blob
*csblob
)
552 return csblob
->csb_teamid
;
556 * Function: csblob_get_identity
558 * Description: This function returns a pointer to the
562 csblob_get_identity(struct cs_blob
*csblob
)
564 const CS_CodeDirectory
*cd
;
566 cd
= (const CS_CodeDirectory
*)csblob_find_blob(csblob
, CSSLOT_CODEDIRECTORY
, CSMAGIC_CODEDIRECTORY
);
571 if (cd
->identOffset
== 0) {
575 return ((const char *)cd
) + ntohl(cd
->identOffset
);
579 * Function: csblob_get_cdhash
581 * Description: This function returns a pointer to the
582 * cdhash of csblob (20 byte array)
585 csblob_get_cdhash(struct cs_blob
*csblob
)
587 ptrauth_utils_auth_blob_generic(csblob
->csb_cdhash
,
588 sizeof(csblob
->csb_cdhash
),
589 OS_PTRAUTH_DISCRIMINATOR("cs_blob.csb_cd_signature"),
590 PTRAUTH_ADDR_DIVERSIFY
,
591 csblob
->csb_cdhash_signature
);
592 return csblob
->csb_cdhash
;
596 * Function: csblob_get_signer_type
598 * Description: This function returns the signer type
602 csblob_get_signer_type(struct cs_blob
*csblob
)
604 return csblob
->csb_signer_type
;
608 csblob_entitlements_dictionary_copy(struct cs_blob
*csblob
)
610 if (!csblob
->csb_entitlements
) {
613 osobject_retain(csblob
->csb_entitlements
);
614 return csblob
->csb_entitlements
;
618 csblob_entitlements_dictionary_set(struct cs_blob
*csblob
, void * entitlements
)
620 assert(csblob
->csb_entitlements
== NULL
);
622 osobject_retain(entitlements
);
624 csblob
->csb_entitlements
= entitlements
;
628 * Function: csproc_get_teamid
630 * Description: This function returns a pointer to the
631 * team id of the process p
634 csproc_get_teamid(struct proc
*p
)
636 struct cs_blob
*csblob
;
638 csblob
= csproc_get_blob(p
);
639 if (csblob
== NULL
) {
643 return csblob_get_teamid(csblob
);
647 csproc_get_identity(struct proc
*p
)
649 struct cs_blob
*csblob
= NULL
;
651 csblob
= csproc_get_blob(p
);
652 if (csblob
== NULL
) {
656 return csblob_get_identity(csblob
);
660 * Function: csproc_get_signer_type
662 * Description: This function returns the signer type
666 csproc_get_signer_type(struct proc
*p
)
668 struct cs_blob
*csblob
;
670 csblob
= csproc_get_blob(p
);
671 if (csblob
== NULL
) {
672 return CS_SIGNER_TYPE_UNKNOWN
;
675 return csblob_get_signer_type(csblob
);
679 * Function: csvnode_get_teamid
681 * Description: This function returns a pointer to the
682 * team id of the binary at the given offset in vnode vp
685 csvnode_get_teamid(struct vnode
*vp
, off_t offset
)
687 struct cs_blob
*csblob
;
693 csblob
= ubc_cs_blob_get(vp
, -1, -1, offset
);
694 if (csblob
== NULL
) {
698 return csblob_get_teamid(csblob
);
702 * Function: csproc_get_platform_binary
704 * Description: This function returns the value
705 * of the platform_binary field for proc p
708 csproc_get_platform_binary(struct proc
*p
)
710 struct cs_blob
*csblob
;
712 csblob
= csproc_get_blob(p
);
714 /* If there is no csblob this returns 0 because
715 * it is true that it is not a platform binary */
716 return (csblob
== NULL
) ? 0 : csblob
->csb_platform_binary
;
720 csproc_get_platform_path(struct proc
*p
)
722 struct cs_blob
*csblob
;
724 csblob
= csproc_get_blob(p
);
726 return (csblob
== NULL
) ? 0 : csblob
->csb_platform_path
;
729 #if DEVELOPMENT || DEBUG
731 csproc_clear_platform_binary(struct proc
*p
)
733 struct cs_blob
*csblob
= csproc_get_blob(p
);
735 if (csblob
== NULL
) {
740 printf("clearing platform binary on proc/task: pid = %d\n", p
->p_pid
);
743 csblob
->csb_platform_binary
= 0;
744 csblob
->csb_platform_path
= 0;
745 task_set_platform_binary(proc_task(p
), FALSE
);
750 csproc_disable_enforcement(struct proc
* __unused p
)
752 #if !CONFIG_ENFORCE_SIGNED_CODE
755 p
->p_csflags
&= (~CS_ENFORCEMENT
);
756 vm_map_cs_enforcement_set(get_task_map(p
->task
), FALSE
);
762 /* Function: csproc_mark_invalid_allowed
764 * Description: Mark the process as being allowed to go invalid. Called as part of
765 * task_for_pid and ptrace policy. Note CS_INVALID_ALLOWED only matters for
766 * processes that have been opted into CS_ENFORCEMENT.
769 csproc_mark_invalid_allowed(struct proc
* __unused p
)
771 #if !CONFIG_ENFORCE_SIGNED_CODE
774 p
->p_csflags
|= CS_INVALID_ALLOWED
;
781 * Function: csproc_check_invalid_allowed
783 * Description: Returns 1 if the process has been marked as allowed to go invalid
784 * because it gave its task port to an allowed process.
787 csproc_check_invalid_allowed(struct proc
* __unused p
)
789 #if !CONFIG_ENFORCE_SIGNED_CODE
794 if (p
!= NULL
&& (p
->p_csflags
& CS_INVALID_ALLOWED
)) {
802 * Function: csproc_get_prod_signed
804 * Description: Returns 1 if process is not signed with a developer identity.
805 * Note the inverted meaning from the cs_flag to make the error case safer.
806 * Will go away with rdar://problem/28322552.
809 csproc_get_prod_signed(struct proc
*p
)
811 return (p
->p_csflags
& CS_DEV_CODE
) == 0;
816 * Function: csfg_get_platform_binary
818 * Description: This function returns the
819 * platform binary field for the
823 csfg_get_platform_binary(struct fileglob
*fg
)
825 int platform_binary
= 0;
826 struct ubc_info
*uip
;
829 if (FILEGLOB_DTYPE(fg
) != DTYPE_VNODE
) {
833 vp
= (struct vnode
*)fg
->fg_data
;
839 if (!UBCINFOEXISTS(vp
)) {
848 if (uip
->cs_blobs
== NULL
) {
852 /* It is OK to extract the teamid from the first blob
853 * because all blobs of a vnode must have the same teamid */
854 platform_binary
= uip
->cs_blobs
->csb_platform_binary
;
858 return platform_binary
;
862 csfg_get_supplement_platform_binary(struct fileglob
*fg __unused
)
864 #if CONFIG_SUPPLEMENTAL_SIGNATURES
865 int platform_binary
= 0;
866 struct ubc_info
*uip
;
869 if (FILEGLOB_DTYPE(fg
) != DTYPE_VNODE
) {
873 vp
= (struct vnode
*)fg
->fg_data
;
879 if (!UBCINFOEXISTS(vp
)) {
888 if (uip
->cs_blob_supplement
== NULL
) {
892 platform_binary
= uip
->cs_blob_supplement
->csb_platform_binary
;
896 return platform_binary
;
898 // Supplemental signatures are only allowed in CONFIG_SUPPLEMENTAL_SIGNATURES
899 // Return false if anyone asks about them
905 csfg_get_cdhash(struct fileglob
*fg
, uint64_t offset
, size_t *cdhash_size
)
909 if (FILEGLOB_DTYPE(fg
) != DTYPE_VNODE
) {
913 vp
= (struct vnode
*)fg
->fg_data
;
918 struct cs_blob
*csblob
= NULL
;
919 if ((csblob
= ubc_cs_blob_get(vp
, -1, -1, offset
)) == NULL
) {
924 *cdhash_size
= CS_CDHASH_LEN
;
926 ptrauth_utils_auth_blob_generic(csblob
->csb_cdhash
,
927 sizeof(csblob
->csb_cdhash
),
928 OS_PTRAUTH_DISCRIMINATOR("cs_blob.csb_cd_signature"),
929 PTRAUTH_ADDR_DIVERSIFY
,
930 csblob
->csb_cdhash_signature
);
931 return csblob
->csb_cdhash
;
935 csfg_get_supplement_cdhash(struct fileglob
*fg __unused
, uint64_t offset __unused
, size_t *cdhash_size __unused
)
937 #if CONFIG_SUPPLEMENTAL_SIGNATURES
940 if (FILEGLOB_DTYPE(fg
) != DTYPE_VNODE
) {
944 vp
= (struct vnode
*)fg
->fg_data
;
949 struct cs_blob
*csblob
= NULL
;
950 if ((csblob
= ubc_cs_blob_get_supplement(vp
, offset
)) == NULL
) {
955 *cdhash_size
= CS_CDHASH_LEN
;
957 ptrauth_utils_auth_blob_generic(csblob
->csb_cdhash
,
958 sizeof(csblob
->csb_cdhash
),
959 OS_PTRAUTH_DISCRIMINATOR("cs_blob.csb_cd_signature"),
960 PTRAUTH_ADDR_DIVERSIFY
,
961 csblob
->csb_cdhash_signature
);
962 return csblob
->csb_cdhash
;
964 // Supplemental signatures are only available in CONFIG_SUPPLEMENTAL_SIGNATURES
965 // return NULL if anyone asks about them
971 csfg_get_supplement_linkage_cdhash(struct fileglob
*fg __unused
, uint64_t offset __unused
, size_t *cdhash_size __unused
)
973 #if CONFIG_SUPPLEMENTAL_SIGNATURES
976 if (FILEGLOB_DTYPE(fg
) != DTYPE_VNODE
) {
980 vp
= (struct vnode
*)fg
->fg_data
;
985 struct cs_blob
*csblob
= NULL
;
986 if ((csblob
= ubc_cs_blob_get_supplement(vp
, offset
)) == NULL
) {
991 *cdhash_size
= CS_CDHASH_LEN
;
994 return csblob
->csb_linkage
;
996 // Supplemental signatures are only available in CONFIG_SUPPLEMENTAL_SIGNATURES
997 // return NULL if anyone asks about them
1003 * Function: csfg_get_signer_type
1005 * Description: This returns the signer type
1006 * for the fileglob fg
1009 csfg_get_signer_type(struct fileglob
*fg
)
1011 struct ubc_info
*uip
;
1012 unsigned int signer_type
= CS_SIGNER_TYPE_UNKNOWN
;
1015 if (FILEGLOB_DTYPE(fg
) != DTYPE_VNODE
) {
1016 return CS_SIGNER_TYPE_UNKNOWN
;
1019 vp
= (struct vnode
*)fg
->fg_data
;
1021 return CS_SIGNER_TYPE_UNKNOWN
;
1025 if (!UBCINFOEXISTS(vp
)) {
1029 uip
= vp
->v_ubcinfo
;
1034 if (uip
->cs_blobs
== NULL
) {
1038 /* It is OK to extract the signer type from the first blob,
1039 * because all blobs of a vnode must have the same signer type. */
1040 signer_type
= uip
->cs_blobs
->csb_signer_type
;
1048 csfg_get_supplement_signer_type(struct fileglob
*fg __unused
)
1050 #if CONFIG_SUPPLEMENTAL_SIGNATURES
1051 struct ubc_info
*uip
;
1052 unsigned int signer_type
= CS_SIGNER_TYPE_UNKNOWN
;
1055 if (FILEGLOB_DTYPE(fg
) != DTYPE_VNODE
) {
1056 return CS_SIGNER_TYPE_UNKNOWN
;
1059 vp
= (struct vnode
*)fg
->fg_data
;
1061 return CS_SIGNER_TYPE_UNKNOWN
;
1065 if (!UBCINFOEXISTS(vp
)) {
1069 uip
= vp
->v_ubcinfo
;
1074 if (uip
->cs_blob_supplement
== NULL
) {
1078 signer_type
= uip
->cs_blob_supplement
->csb_signer_type
;
1084 // Supplemental signatures are only available in CONFIG_SUPPLEMENTAL_SIGNATURES
1085 // Return unknown if anyone asks
1086 return CS_SIGNER_TYPE_UNKNOWN
;
1091 * Function: csfg_get_teamid
1093 * Description: This returns a pointer to
1094 * the teamid for the fileglob fg
1097 csfg_get_teamid(struct fileglob
*fg
)
1099 struct ubc_info
*uip
;
1100 const char *str
= NULL
;
1103 if (FILEGLOB_DTYPE(fg
) != DTYPE_VNODE
) {
1107 vp
= (struct vnode
*)fg
->fg_data
;
1113 if (!UBCINFOEXISTS(vp
)) {
1117 uip
= vp
->v_ubcinfo
;
1122 if (uip
->cs_blobs
== NULL
) {
1126 /* It is OK to extract the teamid from the first blob
1127 * because all blobs of a vnode must have the same teamid */
1128 str
= uip
->cs_blobs
->csb_teamid
;
1136 csfg_get_supplement_teamid(struct fileglob
*fg __unused
)
1138 #if CONFIG_SUPPLEMENTAL_SIGNATURES
1139 struct ubc_info
*uip
;
1140 const char *str
= NULL
;
1143 if (FILEGLOB_DTYPE(fg
) != DTYPE_VNODE
) {
1147 vp
= (struct vnode
*)fg
->fg_data
;
1153 if (!UBCINFOEXISTS(vp
)) {
1157 uip
= vp
->v_ubcinfo
;
1162 if (uip
->cs_blob_supplement
== NULL
) {
1166 str
= uip
->cs_blob_supplement
->csb_supplement_teamid
;
1172 // Supplemental Signatures are only available in CONFIG_SUPPLEMENTAL_SIGNATURES
1173 // Return NULL if anyone asks
1179 * Function: csfg_get_prod_signed
1181 * Description: Returns 1 if code is not signed with a developer identity.
1182 * Note the inverted meaning from the cs_flag to make the error case safer.
1183 * Will go away with rdar://problem/28322552.
1186 csfg_get_prod_signed(struct fileglob
*fg
)
1188 struct ubc_info
*uip
;
1190 int prod_signed
= 0;
1192 if (FILEGLOB_DTYPE(fg
) != DTYPE_VNODE
) {
1196 vp
= (struct vnode
*)fg
->fg_data
;
1202 if (!UBCINFOEXISTS(vp
)) {
1206 uip
= vp
->v_ubcinfo
;
1211 if (uip
->cs_blobs
== NULL
) {
1215 /* It is OK to extract the flag from the first blob
1216 * because all blobs of a vnode must have the same cs_flags */
1217 prod_signed
= (uip
->cs_blobs
->csb_flags
& CS_DEV_CODE
) == 0;
1225 csfg_get_supplement_prod_signed(struct fileglob
*fg __unused
)
1227 #if CONFIG_SUPPLEMENTAL_SIGNATURES
1228 struct ubc_info
*uip
;
1230 int prod_signed
= 0;
1232 if (FILEGLOB_DTYPE(fg
) != DTYPE_VNODE
) {
1236 vp
= (struct vnode
*)fg
->fg_data
;
1242 if (!UBCINFOEXISTS(vp
)) {
1246 uip
= vp
->v_ubcinfo
;
1251 if (uip
->cs_blob_supplement
== NULL
) {
1255 /* It is OK to extract the flag from the first blob
1256 * because all blobs of a vnode must have the same cs_flags */
1257 prod_signed
= (uip
->cs_blob_supplement
->csb_flags
& CS_DEV_CODE
) == 0;
1263 // Supplemental signatures are only available in CONFIG_SUPPLEMENTAL_SIGNATURES
1264 // Indicate development signed if anyone tries to ask about one.
1270 * Function: csfg_get_identity
1272 * Description: This function returns the codesign identity
1276 csfg_get_identity(struct fileglob
*fg
, off_t offset
)
1279 struct cs_blob
*csblob
= NULL
;
1281 if (FILEGLOB_DTYPE(fg
) != DTYPE_VNODE
) {
1285 vp
= (struct vnode
*)fg
->fg_data
;
1290 csblob
= ubc_cs_blob_get(vp
, -1, -1, offset
);
1291 if (csblob
== NULL
) {
1295 return csblob_get_identity(csblob
);
1299 * Function: csfg_get_platform_identifier
1301 * Description: This function returns the codesign platform
1302 * identifier for the fileglob. Assumes the fileproc
1303 * is being held busy to keep the fileglob consistent.
1306 csfg_get_platform_identifier(struct fileglob
*fg
, off_t offset
)
1310 if (FILEGLOB_DTYPE(fg
) != DTYPE_VNODE
) {
1314 vp
= (struct vnode
*)fg
->fg_data
;
1319 return csvnode_get_platform_identifier(vp
, offset
);
1323 * Function: csvnode_get_platform_identifier
1325 * Description: This function returns the codesign platform
1326 * identifier for the vnode. Assumes a vnode reference
1330 csvnode_get_platform_identifier(struct vnode
*vp
, off_t offset
)
1332 struct cs_blob
*csblob
;
1333 const CS_CodeDirectory
*code_dir
;
1335 csblob
= ubc_cs_blob_get(vp
, -1, -1, offset
);
1336 if (csblob
== NULL
) {
1340 code_dir
= csblob
->csb_cd
;
1341 if (code_dir
== NULL
|| ntohl(code_dir
->length
) < 8) {
1345 return code_dir
->platform
;
1349 * Function: csproc_get_platform_identifier
1351 * Description: This function returns the codesign platform
1352 * identifier for the proc. Assumes proc will remain
1353 * valid through call.
1356 csproc_get_platform_identifier(struct proc
*p
)
1358 if (NULL
== p
->p_textvp
) {
1362 return csvnode_get_platform_identifier(p
->p_textvp
, p
->p_textoff
);
1366 cs_entitlement_flags(struct proc
*p
)
1368 return p
->p_csflags
& CS_ENTITLEMENT_FLAGS
;
1372 cs_restricted(struct proc
*p
)
1374 return (p
->p_csflags
& CS_RESTRICT
) ? 1 : 0;
1378 csproc_hardened_runtime(struct proc
* p
)
1380 return (p
->p_csflags
& CS_RUNTIME
) ? 1 : 0;
1384 * Function: csfg_get_path
1386 * Description: This populates the buffer passed in
1387 * with the path of the vnode
1388 * When calling this, the fileglob
1389 * cannot go away. The caller must have a
1390 * a reference on the fileglob or fileproc
1393 csfg_get_path(struct fileglob
*fg
, char *path
, int *len
)
1397 if (FILEGLOB_DTYPE(fg
) != DTYPE_VNODE
) {
1401 vp
= (struct vnode
*)fg
->fg_data
;
1403 /* vn_getpath returns 0 for success,
1404 * or an error code */
1405 return vn_getpath(vp
, path
, len
);
1409 * Retrieve the entitlements blob for a vnode
1411 * EINVAL no text vnode associated with the process
1412 * EBADEXEC invalid code signing data
1413 * 0 no error occurred
1415 * On success, out_start and out_length will point to the
1416 * entitlements blob if found; or will be set to NULL/zero
1417 * if there were no entitlements.
1420 cs_entitlements_blob_get_vnode(vnode_t vnode
, off_t offset
, void **out_start
, size_t *out_length
)
1422 struct cs_blob
*csblob
;
1427 if (vnode
== NULL
) {
1431 if ((csblob
= ubc_cs_blob_get(vnode
, -1, -1, offset
)) == NULL
) {
1435 return csblob_get_entitlements(csblob
, out_start
, out_length
);
1439 * Retrieve the entitlements blob for a process.
1441 * EINVAL no text vnode associated with the process
1442 * EBADEXEC invalid code signing data
1443 * 0 no error occurred
1445 * On success, out_start and out_length will point to the
1446 * entitlements blob if found; or will be set to NULL/zero
1447 * if there were no entitlements.
1450 cs_entitlements_blob_get(proc_t p
, void **out_start
, size_t *out_length
)
1452 if ((p
->p_csflags
& CS_SIGNED
) == 0) {
1456 return cs_entitlements_blob_get_vnode(p
->p_textvp
, p
->p_textoff
, out_start
, out_length
);
1460 /* Retrieve the cached entitlements for a process
1462 * EINVAL no text vnode associated with the process
1463 * EBADEXEC invalid code signing data
1464 * 0 no error occurred
1466 * Note: the entitlements may be NULL if there is nothing cached.
1470 cs_entitlements_dictionary_copy(proc_t p
, void **entitlements
)
1472 struct cs_blob
*csblob
;
1474 *entitlements
= NULL
;
1476 if ((p
->p_csflags
& CS_SIGNED
) == 0) {
1480 if (NULL
== p
->p_textvp
) {
1484 if ((csblob
= ubc_cs_blob_get(p
->p_textvp
, -1, -1, p
->p_textoff
)) == NULL
) {
1488 *entitlements
= csblob_entitlements_dictionary_copy(csblob
);
1492 /* Retrieve the codesign identity for a process.
1494 * NULL an error occured
1495 * string the cs_identity
1499 cs_identity_get(proc_t p
)
1501 struct cs_blob
*csblob
;
1503 if ((p
->p_csflags
& CS_SIGNED
) == 0) {
1507 if (NULL
== p
->p_textvp
) {
1511 if ((csblob
= ubc_cs_blob_get(p
->p_textvp
, -1, -1, p
->p_textoff
)) == NULL
) {
1515 return csblob_get_identity(csblob
);
1519 * DO NOT USE THIS FUNCTION!
1520 * Use the properly guarded csproc_get_blob instead.
1522 * This is currently here to allow detached signatures to work
1523 * properly. The only user of this function is also checking
1528 cs_blob_get(proc_t p
, void **out_start
, size_t *out_length
)
1530 struct cs_blob
*csblob
;
1535 if (NULL
== p
->p_textvp
) {
1539 if ((csblob
= ubc_cs_blob_get(p
->p_textvp
, -1, -1, p
->p_textoff
)) == NULL
) {
1543 *out_start
= (void *)csblob
->csb_mem_kaddr
;
1544 *out_length
= csblob
->csb_mem_size
;
1550 * return cshash of a process, cdhash is of size CS_CDHASH_LEN
1554 cs_get_cdhash(struct proc
*p
)
1556 struct cs_blob
*csblob
;
1558 if ((p
->p_csflags
& CS_SIGNED
) == 0) {
1562 if (NULL
== p
->p_textvp
) {
1566 if ((csblob
= ubc_cs_blob_get(p
->p_textvp
, -1, -1, p
->p_textoff
)) == NULL
) {
1570 ptrauth_utils_auth_blob_generic(csblob
->csb_cdhash
,
1571 sizeof(csblob
->csb_cdhash
),
1572 OS_PTRAUTH_DISCRIMINATOR("cs_blob.csb_cd_signature"),
1573 PTRAUTH_ADDR_DIVERSIFY
,
1574 csblob
->csb_cdhash_signature
);
1575 return csblob
->csb_cdhash
;