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>
67 #include <vm/vm_kern.h>
70 #include <kern/assert.h>
72 #include <pexpert/pexpert.h>
74 #include <mach/shared_region.h>
76 #include <libkern/section_keywords.h>
77 #include <libkern/ptrauth_utils.h>
80 unsigned long cs_procs_killed
= 0;
81 unsigned long cs_procs_invalidated
= 0;
83 int cs_force_kill
= 0;
84 int cs_force_hard
= 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;
92 #if CONFIG_ENFORCE_SIGNED_CODE
93 #define DEFAULT_CS_SYSTEM_ENFORCEMENT_ENABLE 1
94 #define DEFAULT_CS_PROCESS_ENFORCEMENT_ENABLE 1
96 #define DEFAULT_CS_SYSTEM_ENFORCEMENT_ENABLE 1
97 #define DEFAULT_CS_PROCESS_ENFORCEMENT_ENABLE 0
100 #if CONFIG_ENFORCE_LIBRARY_VALIDATION
101 #define DEFAULT_CS_LIBRARY_VA_ENABLE 1
103 #define DEFAULT_CS_LIBRARY_VA_ENABLE 0
109 * Here we split cs_enforcement_enable into cs_system_enforcement_enable and cs_process_enforcement_enable
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
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.
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.)
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
;
125 #else /* !SECURE_KERNEL */
126 int cs_enforcement_panic
= 0;
127 int cs_relax_platform_task_ports
= 0;
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
;
132 SECURITY_READ_ONLY_LATE(int) cs_library_val_enable
= DEFAULT_CS_LIBRARY_VA_ENABLE
;
134 #endif /* !SECURE_KERNEL */
135 int cs_all_vnodes
= 0;
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, "");
147 SYSCTL_INT(_vm
, OID_AUTO
, cs_all_vnodes
, CTLFLAG_RW
| CTLFLAG_LOCKED
, &cs_all_vnodes
, 0, "");
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, "");
154 #if !CONFIG_ENFORCE_LIBRARY_VALIDATION
155 SYSCTL_INT(_vm
, OID_AUTO
, cs_library_validation
, CTLFLAG_RD
| CTLFLAG_LOCKED
, &cs_library_val_enable
, 0, "");
157 #endif /* !SECURE_KERNEL */
159 int panic_on_cs_killed
= 0;
166 #if PLATFORM_WatchOS || __x86_64__
167 panic_on_cs_killed
= 1;
168 #endif /* watchos || x86_64 */
169 #endif /* MACH_ASSERT */
170 PE_parse_boot_argn("panic_on_cs_killed", &panic_on_cs_killed
,
171 sizeof(panic_on_cs_killed
));
173 int disable_cs_enforcement
= 0;
174 PE_parse_boot_argn("cs_enforcement_disable", &disable_cs_enforcement
,
175 sizeof(disable_cs_enforcement
));
176 if (disable_cs_enforcement
&& PE_i_can_has_debugger(NULL
) != 0) {
177 cs_system_enforcement_enable
= 0;
178 cs_process_enforcement_enable
= 0;
181 PE_parse_boot_argn("cs_enforcement_panic", &panic
, sizeof(panic
));
182 cs_enforcement_panic
= (panic
!= 0);
185 PE_parse_boot_argn("cs_relax_platform_task_ports",
186 &cs_relax_platform_task_ports
,
187 sizeof(cs_relax_platform_task_ports
));
189 PE_parse_boot_argn("cs_debug", &cs_debug
, sizeof(cs_debug
));
191 #if !CONFIG_ENFORCE_LIBRARY_VALIDATION
192 PE_parse_boot_argn("cs_library_val_enable", &cs_library_val_enable
,
193 sizeof(cs_library_val_enable
));
195 #endif /* !SECURE_KERNEL */
197 STARTUP(CODESIGNING
, STARTUP_RANK_FIRST
, cs_init
);
200 cs_allow_invalid(struct proc
*p
)
203 lck_mtx_assert(&p
->p_mlock
, LCK_MTX_ASSERT_NOTOWNED
);
206 /* There needs to be a MAC policy to implement this hook, or else the
207 * kill bits will be cleared here every time. If we have
208 * CONFIG_ENFORCE_SIGNED_CODE, we can assume there is a policy
209 * implementing the hook.
211 if (0 != mac_proc_check_run_cs_invalid(p
)) {
213 printf("CODE SIGNING: cs_allow_invalid() "
214 "not allowed: pid %d\n",
220 printf("CODE SIGNING: cs_allow_invalid() "
225 p
->p_csflags
&= ~(CS_KILL
| CS_HARD
);
226 if (p
->p_csflags
& CS_VALID
) {
227 p
->p_csflags
|= CS_DEBUGGED
;
230 task_t procTask
= proc_task(p
);
232 vm_map_t proc_map
= get_task_map_reference(procTask
);
234 if (vm_map_cs_wx_enable(proc_map
) != KERN_SUCCESS
) {
235 printf("CODE SIGNING: cs_allow_invalid() not allowed by pmap: pid %d\n", p
->p_pid
);
237 vm_map_deallocate(proc_map
);
243 /* allow a debugged process to hide some (debug-only!) memory */
244 task_set_memory_ownership_transfer(p
->task
, TRUE
);
246 vm_map_switch_protect(get_task_map(p
->task
), FALSE
);
248 return (p
->p_csflags
& (CS_KILL
| CS_HARD
)) == 0;
252 cs_invalid_page(addr64_t vaddr
, boolean_t
*cs_killed
)
255 int send_kill
= 0, retval
= 0, verbose
= cs_debug
;
260 printf("CODE SIGNING: cs_invalid_page(0x%llx): p=%d[%s]\n",
261 vaddr
, p
->p_pid
, p
->p_comm
);
266 /* XXX for testing */
268 p
->p_csflags
|= CS_KILL
;
271 p
->p_csflags
|= CS_HARD
;
274 /* CS_KILL triggers a kill signal, and no you can't have the page. Nothing else. */
275 if (p
->p_csflags
& CS_KILL
) {
276 p
->p_csflags
|= CS_KILLED
;
282 /* CS_HARD means fail the mapping operation so the process stays valid. */
283 if (p
->p_csflags
& CS_HARD
) {
286 if (p
->p_csflags
& CS_VALID
) {
287 p
->p_csflags
&= ~CS_VALID
;
288 cs_procs_invalidated
++;
290 cs_process_invalidated(NULL
);
296 printf("CODE SIGNING: cs_invalid_page(0x%llx): "
297 "p=%d[%s] final status 0x%x, %s page%s\n",
298 vaddr
, p
->p_pid
, p
->p_comm
, p
->p_csflags
,
299 retval
? "denying" : "allowing (remove VALID)",
300 send_kill
? " sending SIGKILL" : "");
304 /* We will set the exit reason for the thread later */
305 threadsignal(current_thread(), SIGKILL
, EXC_BAD_ACCESS
, FALSE
);
309 } else if (cs_killed
) {
317 * Called after a process got its CS_VALID bit removed, either by
318 * a previous call to cs_invalid_page, or through other means.
319 * Called from fault handler with vm object lock held.
320 * Called with proc lock held for current_proc or, if passed in, p,
321 * to ensure MACF hook can suspend the task before other threads
322 * can access the memory that is paged in after cs_invalid_page
323 * returns 0 due to missing CS_HARD|CS_KILL.
326 cs_process_invalidated(struct proc
* __unused p
)
332 mac_proc_notify_cs_invalidated(p
);
337 * Assumes p (if passed in) is locked with proc_lock().
341 cs_process_enforcement(struct proc
*p
)
343 if (cs_process_enforcement_enable
) {
351 if (p
!= NULL
&& (p
->p_csflags
& CS_ENFORCEMENT
)) {
359 cs_process_global_enforcement(void)
361 return cs_process_enforcement_enable
? 1 : 0;
365 cs_system_enforcement(void)
367 return cs_system_enforcement_enable
? 1 : 0;
371 cs_vm_supports_4k_translations(void)
378 * Returns whether a given process is still valid.
381 cs_valid(struct proc
*p
)
387 if (p
!= NULL
&& (p
->p_csflags
& CS_VALID
)) {
395 * Library validation functions
398 cs_require_lv(struct proc
*p
)
400 if (cs_library_val_enable
) {
408 if (p
!= NULL
&& (p
->p_csflags
& CS_REQUIRE_LV
)) {
416 csproc_forced_lv(struct proc
* p
)
421 if (p
!= NULL
&& (p
->p_csflags
& CS_FORCED_LV
)) {
428 * <rdar://problem/24634089> added to allow system level library
429 * validation check at mac_cred_label_update_execve time
432 cs_system_require_lv(void)
434 return cs_library_val_enable
? 1 : 0;
438 * Function: csblob_get_base_offset
440 * Description: This function returns the base offset into the (possibly universal) binary
445 csblob_get_base_offset(struct cs_blob
*blob
)
447 return blob
->csb_base_offset
;
451 * Function: csblob_get_size
453 * Description: This function returns the size of a given blob.
457 csblob_get_size(struct cs_blob
*blob
)
459 return blob
->csb_mem_size
;
463 * Function: csblob_get_addr
465 * Description: This function returns the address of a given blob.
469 csblob_get_addr(struct cs_blob
*blob
)
471 return (vm_address_t
)blob
->csb_mem_kaddr
;
475 * Function: csblob_get_platform_binary
477 * Description: This function returns true if the binary is
478 * in the trust cache.
482 csblob_get_platform_binary(struct cs_blob
*blob
)
484 if (blob
&& blob
->csb_platform_binary
) {
491 * Function: csblob_get_flags
493 * Description: This function returns the flags for a given blob
497 csblob_get_flags(struct cs_blob
*blob
)
499 return blob
->csb_flags
;
503 * Function: csblob_get_hashtype
505 * Description: This function returns the hash type for a given blob
509 csblob_get_hashtype(struct cs_blob
const * const blob
)
511 return blob
->csb_hashtype
!= NULL
? cs_hash_type(blob
->csb_hashtype
) : 0;
515 * Function: csproc_get_blob
517 * Description: This function returns the cs_blob
521 csproc_get_blob(struct proc
*p
)
527 if (NULL
== p
->p_textvp
) {
531 if ((p
->p_csflags
& CS_SIGNED
) == 0) {
535 return ubc_cs_blob_get(p
->p_textvp
, -1, -1, p
->p_textoff
);
539 * Function: csvnode_get_blob
541 * Description: This function returns the cs_blob
545 csvnode_get_blob(struct vnode
*vp
, off_t offset
)
547 return ubc_cs_blob_get(vp
, -1, -1, offset
);
551 * Function: csblob_get_teamid
553 * Description: This function returns a pointer to the
557 csblob_get_teamid(struct cs_blob
*csblob
)
559 return csblob
->csb_teamid
;
563 * Function: csblob_get_identity
565 * Description: This function returns a pointer to the
569 csblob_get_identity(struct cs_blob
*csblob
)
571 const CS_CodeDirectory
*cd
;
573 cd
= (const CS_CodeDirectory
*)csblob_find_blob(csblob
, CSSLOT_CODEDIRECTORY
, CSMAGIC_CODEDIRECTORY
);
578 if (cd
->identOffset
== 0) {
582 return ((const char *)cd
) + ntohl(cd
->identOffset
);
586 * Function: csblob_get_cdhash
588 * Description: This function returns a pointer to the
589 * cdhash of csblob (20 byte array)
592 csblob_get_cdhash(struct cs_blob
*csblob
)
594 ptrauth_utils_auth_blob_generic(csblob
->csb_cdhash
,
595 sizeof(csblob
->csb_cdhash
),
596 OS_PTRAUTH_DISCRIMINATOR("cs_blob.csb_cd_signature"),
597 PTRAUTH_ADDR_DIVERSIFY
,
598 csblob
->csb_cdhash_signature
);
599 return csblob
->csb_cdhash
;
603 * Function: csblob_get_signer_type
605 * Description: This function returns the signer type
609 csblob_get_signer_type(struct cs_blob
*csblob
)
611 return csblob
->csb_signer_type
;
615 csblob_entitlements_dictionary_copy(struct cs_blob
*csblob
)
617 if (!csblob
->csb_entitlements
) {
620 osobject_retain(csblob
->csb_entitlements
);
621 return csblob
->csb_entitlements
;
625 csblob_entitlements_dictionary_set(struct cs_blob
*csblob
, void * entitlements
)
627 assert(csblob
->csb_entitlements
== NULL
);
629 osobject_retain(entitlements
);
631 csblob
->csb_entitlements
= entitlements
;
635 * Function: csproc_get_teamid
637 * Description: This function returns a pointer to the
638 * team id of the process p
641 csproc_get_teamid(struct proc
*p
)
643 struct cs_blob
*csblob
;
645 csblob
= csproc_get_blob(p
);
646 if (csblob
== NULL
) {
650 return csblob_get_teamid(csblob
);
654 csproc_get_identity(struct proc
*p
)
656 struct cs_blob
*csblob
= NULL
;
658 csblob
= csproc_get_blob(p
);
659 if (csblob
== NULL
) {
663 return csblob_get_identity(csblob
);
667 * Function: csproc_get_signer_type
669 * Description: This function returns the signer type
673 csproc_get_signer_type(struct proc
*p
)
675 struct cs_blob
*csblob
;
677 csblob
= csproc_get_blob(p
);
678 if (csblob
== NULL
) {
679 return CS_SIGNER_TYPE_UNKNOWN
;
682 return csblob_get_signer_type(csblob
);
686 * Function: csvnode_get_teamid
688 * Description: This function returns a pointer to the
689 * team id of the binary at the given offset in vnode vp
692 csvnode_get_teamid(struct vnode
*vp
, off_t offset
)
694 struct cs_blob
*csblob
;
700 csblob
= ubc_cs_blob_get(vp
, -1, -1, offset
);
701 if (csblob
== NULL
) {
705 return csblob_get_teamid(csblob
);
709 * Function: csproc_get_platform_binary
711 * Description: This function returns the value
712 * of the platform_binary field for proc p
715 csproc_get_platform_binary(struct proc
*p
)
717 struct cs_blob
*csblob
;
719 csblob
= csproc_get_blob(p
);
721 /* If there is no csblob this returns 0 because
722 * it is true that it is not a platform binary */
723 return (csblob
== NULL
) ? 0 : csblob
->csb_platform_binary
;
727 csproc_get_platform_path(struct proc
*p
)
729 struct cs_blob
*csblob
;
731 csblob
= csproc_get_blob(p
);
733 return (csblob
== NULL
) ? 0 : csblob
->csb_platform_path
;
736 #if DEVELOPMENT || DEBUG
738 csproc_clear_platform_binary(struct proc
*p
)
740 struct cs_blob
*csblob
= csproc_get_blob(p
);
742 if (csblob
== NULL
) {
747 printf("clearing platform binary on proc/task: pid = %d\n", p
->p_pid
);
750 csblob
->csb_platform_binary
= 0;
751 csblob
->csb_platform_path
= 0;
752 task_set_platform_binary(proc_task(p
), FALSE
);
757 csproc_disable_enforcement(struct proc
* __unused p
)
759 #if !CONFIG_ENFORCE_SIGNED_CODE
762 p
->p_csflags
&= (~CS_ENFORCEMENT
);
763 vm_map_cs_enforcement_set(get_task_map(p
->task
), FALSE
);
769 /* Function: csproc_mark_invalid_allowed
771 * Description: Mark the process as being allowed to go invalid. Called as part of
772 * task_for_pid and ptrace policy. Note CS_INVALID_ALLOWED only matters for
773 * processes that have been opted into CS_ENFORCEMENT.
776 csproc_mark_invalid_allowed(struct proc
* __unused p
)
778 #if !CONFIG_ENFORCE_SIGNED_CODE
781 p
->p_csflags
|= CS_INVALID_ALLOWED
;
788 * Function: csproc_check_invalid_allowed
790 * Description: Returns 1 if the process has been marked as allowed to go invalid
791 * because it gave its task port to an allowed process.
794 csproc_check_invalid_allowed(struct proc
* __unused p
)
796 #if !CONFIG_ENFORCE_SIGNED_CODE
801 if (p
!= NULL
&& (p
->p_csflags
& CS_INVALID_ALLOWED
)) {
809 * Function: csproc_get_prod_signed
811 * Description: Returns 1 if process is not signed with a developer identity.
812 * Note the inverted meaning from the cs_flag to make the error case safer.
813 * Will go away with rdar://problem/28322552.
816 csproc_get_prod_signed(struct proc
*p
)
818 return (p
->p_csflags
& CS_DEV_CODE
) == 0;
823 * Function: csfg_get_platform_binary
825 * Description: This function returns the
826 * platform binary field for the
830 csfg_get_platform_binary(struct fileglob
*fg
)
832 int platform_binary
= 0;
833 struct ubc_info
*uip
;
836 if (FILEGLOB_DTYPE(fg
) != DTYPE_VNODE
) {
840 vp
= (struct vnode
*)fg
->fg_data
;
846 if (!UBCINFOEXISTS(vp
)) {
855 if (uip
->cs_blobs
== NULL
) {
859 /* It is OK to extract the teamid from the first blob
860 * because all blobs of a vnode must have the same teamid */
861 platform_binary
= uip
->cs_blobs
->csb_platform_binary
;
865 return platform_binary
;
869 csfg_get_supplement_platform_binary(struct fileglob
*fg __unused
)
871 #if CONFIG_SUPPLEMENTAL_SIGNATURES
872 int platform_binary
= 0;
873 struct ubc_info
*uip
;
876 if (FILEGLOB_DTYPE(fg
) != DTYPE_VNODE
) {
880 vp
= (struct vnode
*)fg
->fg_data
;
886 if (!UBCINFOEXISTS(vp
)) {
895 if (uip
->cs_blob_supplement
== NULL
) {
899 platform_binary
= uip
->cs_blob_supplement
->csb_platform_binary
;
903 return platform_binary
;
905 // Supplemental signatures are only allowed in CONFIG_SUPPLEMENTAL_SIGNATURES
906 // Return false if anyone asks about them
912 csfg_get_cdhash(struct fileglob
*fg
, uint64_t offset
, size_t *cdhash_size
)
916 if (FILEGLOB_DTYPE(fg
) != DTYPE_VNODE
) {
920 vp
= (struct vnode
*)fg
->fg_data
;
925 struct cs_blob
*csblob
= NULL
;
926 if ((csblob
= ubc_cs_blob_get(vp
, -1, -1, offset
)) == NULL
) {
931 *cdhash_size
= CS_CDHASH_LEN
;
933 ptrauth_utils_auth_blob_generic(csblob
->csb_cdhash
,
934 sizeof(csblob
->csb_cdhash
),
935 OS_PTRAUTH_DISCRIMINATOR("cs_blob.csb_cd_signature"),
936 PTRAUTH_ADDR_DIVERSIFY
,
937 csblob
->csb_cdhash_signature
);
938 return csblob
->csb_cdhash
;
942 csfg_get_supplement_cdhash(struct fileglob
*fg __unused
, uint64_t offset __unused
, size_t *cdhash_size __unused
)
944 #if CONFIG_SUPPLEMENTAL_SIGNATURES
947 if (FILEGLOB_DTYPE(fg
) != DTYPE_VNODE
) {
951 vp
= (struct vnode
*)fg
->fg_data
;
956 struct cs_blob
*csblob
= NULL
;
957 if ((csblob
= ubc_cs_blob_get_supplement(vp
, offset
)) == NULL
) {
962 *cdhash_size
= CS_CDHASH_LEN
;
964 ptrauth_utils_auth_blob_generic(csblob
->csb_cdhash
,
965 sizeof(csblob
->csb_cdhash
),
966 OS_PTRAUTH_DISCRIMINATOR("cs_blob.csb_cd_signature"),
967 PTRAUTH_ADDR_DIVERSIFY
,
968 csblob
->csb_cdhash_signature
);
969 return csblob
->csb_cdhash
;
971 // Supplemental signatures are only available in CONFIG_SUPPLEMENTAL_SIGNATURES
972 // return NULL if anyone asks about them
978 csfg_get_supplement_linkage_cdhash(struct fileglob
*fg __unused
, uint64_t offset __unused
, size_t *cdhash_size __unused
)
980 #if CONFIG_SUPPLEMENTAL_SIGNATURES
983 if (FILEGLOB_DTYPE(fg
) != DTYPE_VNODE
) {
987 vp
= (struct vnode
*)fg
->fg_data
;
992 struct cs_blob
*csblob
= NULL
;
993 if ((csblob
= ubc_cs_blob_get_supplement(vp
, offset
)) == NULL
) {
998 *cdhash_size
= CS_CDHASH_LEN
;
1001 return csblob
->csb_linkage
;
1003 // Supplemental signatures are only available in CONFIG_SUPPLEMENTAL_SIGNATURES
1004 // return NULL if anyone asks about them
1010 * Function: csfg_get_signer_type
1012 * Description: This returns the signer type
1013 * for the fileglob fg
1016 csfg_get_signer_type(struct fileglob
*fg
)
1018 struct ubc_info
*uip
;
1019 unsigned int signer_type
= CS_SIGNER_TYPE_UNKNOWN
;
1022 if (FILEGLOB_DTYPE(fg
) != DTYPE_VNODE
) {
1023 return CS_SIGNER_TYPE_UNKNOWN
;
1026 vp
= (struct vnode
*)fg
->fg_data
;
1028 return CS_SIGNER_TYPE_UNKNOWN
;
1032 if (!UBCINFOEXISTS(vp
)) {
1036 uip
= vp
->v_ubcinfo
;
1041 if (uip
->cs_blobs
== NULL
) {
1045 /* It is OK to extract the signer type from the first blob,
1046 * because all blobs of a vnode must have the same signer type. */
1047 signer_type
= uip
->cs_blobs
->csb_signer_type
;
1055 csfg_get_supplement_signer_type(struct fileglob
*fg __unused
)
1057 #if CONFIG_SUPPLEMENTAL_SIGNATURES
1058 struct ubc_info
*uip
;
1059 unsigned int signer_type
= CS_SIGNER_TYPE_UNKNOWN
;
1062 if (FILEGLOB_DTYPE(fg
) != DTYPE_VNODE
) {
1063 return CS_SIGNER_TYPE_UNKNOWN
;
1066 vp
= (struct vnode
*)fg
->fg_data
;
1068 return CS_SIGNER_TYPE_UNKNOWN
;
1072 if (!UBCINFOEXISTS(vp
)) {
1076 uip
= vp
->v_ubcinfo
;
1081 if (uip
->cs_blob_supplement
== NULL
) {
1085 signer_type
= uip
->cs_blob_supplement
->csb_signer_type
;
1091 // Supplemental signatures are only available in CONFIG_SUPPLEMENTAL_SIGNATURES
1092 // Return unknown if anyone asks
1093 return CS_SIGNER_TYPE_UNKNOWN
;
1098 * Function: csfg_get_teamid
1100 * Description: This returns a pointer to
1101 * the teamid for the fileglob fg
1104 csfg_get_teamid(struct fileglob
*fg
)
1106 struct ubc_info
*uip
;
1107 const char *str
= NULL
;
1110 if (FILEGLOB_DTYPE(fg
) != DTYPE_VNODE
) {
1114 vp
= (struct vnode
*)fg
->fg_data
;
1120 if (!UBCINFOEXISTS(vp
)) {
1124 uip
= vp
->v_ubcinfo
;
1129 if (uip
->cs_blobs
== NULL
) {
1133 /* It is OK to extract the teamid from the first blob
1134 * because all blobs of a vnode must have the same teamid */
1135 str
= uip
->cs_blobs
->csb_teamid
;
1143 csfg_get_supplement_teamid(struct fileglob
*fg __unused
)
1145 #if CONFIG_SUPPLEMENTAL_SIGNATURES
1146 struct ubc_info
*uip
;
1147 const char *str
= NULL
;
1150 if (FILEGLOB_DTYPE(fg
) != DTYPE_VNODE
) {
1154 vp
= (struct vnode
*)fg
->fg_data
;
1160 if (!UBCINFOEXISTS(vp
)) {
1164 uip
= vp
->v_ubcinfo
;
1169 if (uip
->cs_blob_supplement
== NULL
) {
1173 str
= uip
->cs_blob_supplement
->csb_supplement_teamid
;
1179 // Supplemental Signatures are only available in CONFIG_SUPPLEMENTAL_SIGNATURES
1180 // Return NULL if anyone asks
1186 * Function: csfg_get_prod_signed
1188 * Description: Returns 1 if code is not signed with a developer identity.
1189 * Note the inverted meaning from the cs_flag to make the error case safer.
1190 * Will go away with rdar://problem/28322552.
1193 csfg_get_prod_signed(struct fileglob
*fg
)
1195 struct ubc_info
*uip
;
1197 int prod_signed
= 0;
1199 if (FILEGLOB_DTYPE(fg
) != DTYPE_VNODE
) {
1203 vp
= (struct vnode
*)fg
->fg_data
;
1209 if (!UBCINFOEXISTS(vp
)) {
1213 uip
= vp
->v_ubcinfo
;
1218 if (uip
->cs_blobs
== NULL
) {
1222 /* It is OK to extract the flag from the first blob
1223 * because all blobs of a vnode must have the same cs_flags */
1224 prod_signed
= (uip
->cs_blobs
->csb_flags
& CS_DEV_CODE
) == 0;
1232 csfg_get_supplement_prod_signed(struct fileglob
*fg __unused
)
1234 #if CONFIG_SUPPLEMENTAL_SIGNATURES
1235 struct ubc_info
*uip
;
1237 int prod_signed
= 0;
1239 if (FILEGLOB_DTYPE(fg
) != DTYPE_VNODE
) {
1243 vp
= (struct vnode
*)fg
->fg_data
;
1249 if (!UBCINFOEXISTS(vp
)) {
1253 uip
= vp
->v_ubcinfo
;
1258 if (uip
->cs_blob_supplement
== NULL
) {
1262 /* It is OK to extract the flag from the first blob
1263 * because all blobs of a vnode must have the same cs_flags */
1264 prod_signed
= (uip
->cs_blob_supplement
->csb_flags
& CS_DEV_CODE
) == 0;
1270 // Supplemental signatures are only available in CONFIG_SUPPLEMENTAL_SIGNATURES
1271 // Indicate development signed if anyone tries to ask about one.
1277 * Function: csfg_get_identity
1279 * Description: This function returns the codesign identity
1283 csfg_get_identity(struct fileglob
*fg
, off_t offset
)
1286 struct cs_blob
*csblob
= NULL
;
1288 if (FILEGLOB_DTYPE(fg
) != DTYPE_VNODE
) {
1292 vp
= (struct vnode
*)fg
->fg_data
;
1297 csblob
= ubc_cs_blob_get(vp
, -1, -1, offset
);
1298 if (csblob
== NULL
) {
1302 return csblob_get_identity(csblob
);
1306 * Function: csfg_get_platform_identifier
1308 * Description: This function returns the codesign platform
1309 * identifier for the fileglob. Assumes the fileproc
1310 * is being held busy to keep the fileglob consistent.
1313 csfg_get_platform_identifier(struct fileglob
*fg
, off_t offset
)
1317 if (FILEGLOB_DTYPE(fg
) != DTYPE_VNODE
) {
1321 vp
= (struct vnode
*)fg
->fg_data
;
1326 return csvnode_get_platform_identifier(vp
, offset
);
1330 * Function: csvnode_get_platform_identifier
1332 * Description: This function returns the codesign platform
1333 * identifier for the vnode. Assumes a vnode reference
1337 csvnode_get_platform_identifier(struct vnode
*vp
, off_t offset
)
1339 struct cs_blob
*csblob
;
1340 const CS_CodeDirectory
*code_dir
;
1342 csblob
= ubc_cs_blob_get(vp
, -1, -1, offset
);
1343 if (csblob
== NULL
) {
1347 code_dir
= csblob
->csb_cd
;
1348 if (code_dir
== NULL
|| ntohl(code_dir
->length
) < 8) {
1352 return code_dir
->platform
;
1356 * Function: csproc_get_platform_identifier
1358 * Description: This function returns the codesign platform
1359 * identifier for the proc. Assumes proc will remain
1360 * valid through call.
1363 csproc_get_platform_identifier(struct proc
*p
)
1365 if (NULL
== p
->p_textvp
) {
1369 return csvnode_get_platform_identifier(p
->p_textvp
, p
->p_textoff
);
1373 cs_entitlement_flags(struct proc
*p
)
1375 return p
->p_csflags
& CS_ENTITLEMENT_FLAGS
;
1379 cs_restricted(struct proc
*p
)
1381 return (p
->p_csflags
& CS_RESTRICT
) ? 1 : 0;
1385 csproc_hardened_runtime(struct proc
* p
)
1387 return (p
->p_csflags
& CS_RUNTIME
) ? 1 : 0;
1391 * Function: csfg_get_path
1393 * Description: This populates the buffer passed in
1394 * with the path of the vnode
1395 * When calling this, the fileglob
1396 * cannot go away. The caller must have a
1397 * a reference on the fileglob or fileproc
1400 csfg_get_path(struct fileglob
*fg
, char *path
, int *len
)
1404 if (FILEGLOB_DTYPE(fg
) != DTYPE_VNODE
) {
1408 vp
= (struct vnode
*)fg
->fg_data
;
1410 /* vn_getpath returns 0 for success,
1411 * or an error code */
1412 return vn_getpath(vp
, path
, len
);
1416 * Retrieve the entitlements blob for a vnode
1418 * EINVAL no text vnode associated with the process
1419 * EBADEXEC invalid code signing data
1420 * 0 no error occurred
1422 * On success, out_start and out_length will point to the
1423 * entitlements blob if found; or will be set to NULL/zero
1424 * if there were no entitlements.
1427 cs_entitlements_blob_get_vnode(vnode_t vnode
, off_t offset
, void **out_start
, size_t *out_length
)
1429 struct cs_blob
*csblob
;
1434 if (vnode
== NULL
) {
1438 if ((csblob
= ubc_cs_blob_get(vnode
, -1, -1, offset
)) == NULL
) {
1442 return csblob_get_entitlements(csblob
, out_start
, out_length
);
1446 * Retrieve the entitlements blob for a process.
1448 * EINVAL no text vnode associated with the process
1449 * EBADEXEC invalid code signing data
1450 * 0 no error occurred
1452 * On success, out_start and out_length will point to the
1453 * entitlements blob if found; or will be set to NULL/zero
1454 * if there were no entitlements.
1457 cs_entitlements_blob_get(proc_t p
, void **out_start
, size_t *out_length
)
1459 if ((p
->p_csflags
& CS_SIGNED
) == 0) {
1463 return cs_entitlements_blob_get_vnode(p
->p_textvp
, p
->p_textoff
, out_start
, out_length
);
1467 /* Retrieve the cached entitlements for a process
1469 * EINVAL no text vnode associated with the process
1470 * EBADEXEC invalid code signing data
1471 * 0 no error occurred
1473 * Note: the entitlements may be NULL if there is nothing cached.
1477 cs_entitlements_dictionary_copy(proc_t p
, void **entitlements
)
1479 struct cs_blob
*csblob
;
1481 *entitlements
= NULL
;
1483 if ((p
->p_csflags
& CS_SIGNED
) == 0) {
1487 if (NULL
== p
->p_textvp
) {
1491 if ((csblob
= ubc_cs_blob_get(p
->p_textvp
, -1, -1, p
->p_textoff
)) == NULL
) {
1495 *entitlements
= csblob_entitlements_dictionary_copy(csblob
);
1499 /* Retrieve the codesign identity for a process.
1501 * NULL an error occured
1502 * string the cs_identity
1506 cs_identity_get(proc_t p
)
1508 struct cs_blob
*csblob
;
1510 if ((p
->p_csflags
& CS_SIGNED
) == 0) {
1514 if (NULL
== p
->p_textvp
) {
1518 if ((csblob
= ubc_cs_blob_get(p
->p_textvp
, -1, -1, p
->p_textoff
)) == NULL
) {
1522 return csblob_get_identity(csblob
);
1526 * DO NOT USE THIS FUNCTION!
1527 * Use the properly guarded csproc_get_blob instead.
1529 * This is currently here to allow detached signatures to work
1530 * properly. The only user of this function is also checking
1535 cs_blob_get(proc_t p
, void **out_start
, size_t *out_length
)
1537 struct cs_blob
*csblob
;
1542 if (NULL
== p
->p_textvp
) {
1546 if ((csblob
= ubc_cs_blob_get(p
->p_textvp
, -1, -1, p
->p_textoff
)) == NULL
) {
1550 *out_start
= csblob
->csb_mem_kaddr
;
1551 *out_length
= csblob
->csb_mem_size
;
1557 * return cshash of a process, cdhash is of size CS_CDHASH_LEN
1561 cs_get_cdhash(struct proc
*p
)
1563 struct cs_blob
*csblob
;
1565 if ((p
->p_csflags
& CS_SIGNED
) == 0) {
1569 if (NULL
== p
->p_textvp
) {
1573 if ((csblob
= ubc_cs_blob_get(p
->p_textvp
, -1, -1, p
->p_textoff
)) == NULL
) {
1577 ptrauth_utils_auth_blob_generic(csblob
->csb_cdhash
,
1578 sizeof(csblob
->csb_cdhash
),
1579 OS_PTRAUTH_DISCRIMINATOR("cs_blob.csb_cd_signature"),
1580 PTRAUTH_ADDR_DIVERSIFY
,
1581 csblob
->csb_cdhash_signature
);
1582 return csblob
->csb_cdhash
;