]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/kern/kern_cs.c
xnu-4903.241.1.tar.gz
[apple/xnu.git] / bsd / kern / kern_cs.c
index 66af46613e287e362ced16438f6a762dee3c8be1..2b40cea3e43f610f7222fb3271d4e59298d119cd 100644 (file)
 
 #include <mach/shared_region.h>
 
+#include <libkern/section_keywords.h>
+
 unsigned long cs_procs_killed = 0;
 unsigned long cs_procs_invalidated = 0;
 
 int cs_force_kill = 0;
 int cs_force_hard = 0;
 int cs_debug = 0;
+// If set, AMFI will error out early on unsigned code, before evaluation the normal policy.
+int cs_debug_fail_on_unsigned_code = 0;
+// If the previous mode is enabled, we count the resulting failures here.
+unsigned int cs_debug_unsigned_exec_failures = 0;
+unsigned int cs_debug_unsigned_mmap_failures = 0;
+
 #if SECURE_KERNEL
-const int cs_enforcement_enable=1;
-const int cs_library_val_enable=1;
-#else
+/*
+Here we split cs_enforcement_enable into cs_system_enforcement_enable and cs_process_enforcement_enable
+
+cs_system_enforcement_enable governs whether or not system level code signing enforcement mechanisms
+are applied on the system. Today, the only such mechanism is code signing enforcement of the dyld shared
+cache.
+
+cs_process_enforcement_enable governs whether code signing enforcement mechanisms are applied to all
+processes or only those that opt into such enforcement.
+
+(On iOS and related, both of these are set by default. On macOS, only cs_system_enforcement_enable
+is set by default. Processes can then be opted into code signing enforcement on a case by case basis.)
+ */
+const int cs_system_enforcement_enable = 1;
+const int cs_process_enforcement_enable = 1;
+const int cs_library_val_enable = 1;
+#else /* !SECURE_KERNEL */
+int cs_enforcement_panic=0;
+int cs_relax_platform_task_ports = 0;
+
 #if CONFIG_ENFORCE_SIGNED_CODE
-int cs_enforcement_enable=1;
+#define DEFAULT_CS_SYSTEM_ENFORCEMENT_ENABLE 1
+#define DEFAULT_CS_PROCESS_ENFORCEMENT_ENABLE 1
 #else
-int cs_enforcement_enable=0;
-#endif /* CONFIG_ENFORCE_SIGNED_CODE */
+#define DEFAULT_CS_SYSTEM_ENFORCEMENT_ENABLE 1
+#define DEFAULT_CS_PROCESS_ENFORCEMENT_ENABLE 0
+#endif
+SECURITY_READ_ONLY_LATE(int) cs_system_enforcement_enable = DEFAULT_CS_SYSTEM_ENFORCEMENT_ENABLE;
+SECURITY_READ_ONLY_LATE(int) cs_process_enforcement_enable = DEFAULT_CS_PROCESS_ENFORCEMENT_ENABLE;
 
 #if CONFIG_ENFORCE_LIBRARY_VALIDATION
-int cs_library_val_enable = 1;
+#define DEFAULT_CS_LIBRARY_VA_ENABLE 1
 #else
-int cs_library_val_enable = 0;
-#endif /* CONFIG_ENFORCE_LIBRARY_VALIDATION */
+#define DEFAULT_CS_LIBRARY_VA_ENABLE 0
+#endif
+SECURITY_READ_ONLY_LATE(int) cs_library_val_enable = DEFAULT_CS_LIBRARY_VA_ENABLE;
 
-int cs_enforcement_panic=0;
-#endif /* SECURE_KERNEL */
+#endif /* !SECURE_KERNEL */
 int cs_all_vnodes = 0;
 
 static lck_grp_t *cs_lockgrp;
-static lck_rw_t * SigPUPLock;
 
 SYSCTL_INT(_vm, OID_AUTO, cs_force_kill, CTLFLAG_RW | CTLFLAG_LOCKED, &cs_force_kill, 0, "");
 SYSCTL_INT(_vm, OID_AUTO, cs_force_hard, CTLFLAG_RW | CTLFLAG_LOCKED, &cs_force_hard, 0, "");
 SYSCTL_INT(_vm, OID_AUTO, cs_debug, CTLFLAG_RW | CTLFLAG_LOCKED, &cs_debug, 0, "");
+SYSCTL_INT(_vm, OID_AUTO, cs_debug_fail_on_unsigned_code, CTLFLAG_RW | CTLFLAG_LOCKED,
+                          &cs_debug_fail_on_unsigned_code, 0, "");
+SYSCTL_UINT(_vm, OID_AUTO, cs_debug_unsigned_exec_failures, CTLFLAG_RD | CTLFLAG_LOCKED,
+                          &cs_debug_unsigned_exec_failures, 0, "");
+SYSCTL_UINT(_vm, OID_AUTO, cs_debug_unsigned_mmap_failures, CTLFLAG_RD | CTLFLAG_LOCKED,
+                          &cs_debug_unsigned_mmap_failures, 0, "");
 
 SYSCTL_INT(_vm, OID_AUTO, cs_all_vnodes, CTLFLAG_RW | CTLFLAG_LOCKED, &cs_all_vnodes, 0, "");
 
 #if !SECURE_KERNEL
-SYSCTL_INT(_vm, OID_AUTO, cs_enforcement, CTLFLAG_RW | CTLFLAG_LOCKED, &cs_enforcement_enable, 0, "");
+SYSCTL_INT(_vm, OID_AUTO, cs_system_enforcement, CTLFLAG_RD | CTLFLAG_LOCKED, &cs_system_enforcement_enable, 0, "");
+SYSCTL_INT(_vm, OID_AUTO, cs_process_enforcement, CTLFLAG_RW | CTLFLAG_LOCKED, &cs_process_enforcement_enable, 0, "");
 SYSCTL_INT(_vm, OID_AUTO, cs_enforcement_panic, CTLFLAG_RW | CTLFLAG_LOCKED, &cs_enforcement_panic, 0, "");
+
+#if !CONFIG_ENFORCE_LIBRARY_VALIDATION
+SYSCTL_INT(_vm, OID_AUTO, cs_library_validation, CTLFLAG_RD | CTLFLAG_LOCKED, &cs_library_val_enable, 0, "");
 #endif
+#endif /* !SECURE_KERNEL */
 
 int panic_on_cs_killed = 0;
+
 void
 cs_init(void)
 {
-#if MACH_ASSERT && __x86_64__
+#if MACH_ASSERT
+#if PLATFORM_WatchOS || __x86_64__
        panic_on_cs_killed = 1;
-#endif /* MACH_ASSERT && __x86_64__ */
+#endif /* watchos || x86_64 */
+#endif /* MACH_ASSERT */
        PE_parse_boot_argn("panic_on_cs_killed", &panic_on_cs_killed,
                           sizeof (panic_on_cs_killed));
 #if !SECURE_KERNEL
        int disable_cs_enforcement = 0;
        PE_parse_boot_argn("cs_enforcement_disable", &disable_cs_enforcement, 
                           sizeof (disable_cs_enforcement));
-       if (disable_cs_enforcement) {
-               cs_enforcement_enable = 0;
+       if (disable_cs_enforcement && PE_i_can_has_debugger(NULL) != 0) {
+               cs_system_enforcement_enable = 0;
+               cs_process_enforcement_enable = 0;
        } else {
                int panic = 0;
                PE_parse_boot_argn("cs_enforcement_panic", &panic, sizeof(panic));
                cs_enforcement_panic = (panic != 0);
        }
 
+       PE_parse_boot_argn("cs_relax_platform_task_ports",
+                       &cs_relax_platform_task_ports,
+                       sizeof(cs_relax_platform_task_ports));
+
        PE_parse_boot_argn("cs_debug", &cs_debug, sizeof (cs_debug));
+
+#if !CONFIG_ENFORCE_LIBRARY_VALIDATION
+       PE_parse_boot_argn("cs_library_val_enable", &cs_library_val_enable,
+                          sizeof (cs_library_val_enable));
 #endif
+#endif /* !SECURE_KERNEL */
+
        lck_grp_attr_t *attr = lck_grp_attr_alloc_init();
        cs_lockgrp = lck_grp_alloc_init("KERNCS", attr);
-       SigPUPLock = lck_rw_alloc_init(cs_lockgrp, NULL);
+       lck_grp_attr_free(attr);
 }
 
 int
@@ -145,7 +198,7 @@ cs_allow_invalid(struct proc *p)
 #if MACH_ASSERT
        lck_mtx_assert(&p->p_mlock, LCK_MTX_ASSERT_NOTOWNED);
 #endif
-#if CONFIG_MACF && CONFIG_ENFORCE_SIGNED_CODE
+#if CONFIG_MACF
        /* There needs to be a MAC policy to implement this hook, or else the
         * kill bits will be cleared here every time. If we have 
         * CONFIG_ENFORCE_SIGNED_CODE, we can assume there is a policy
@@ -162,15 +215,20 @@ cs_allow_invalid(struct proc *p)
                            p->p_pid);
        proc_lock(p);
        p->p_csflags &= ~(CS_KILL | CS_HARD);
+       if (p->p_csflags & CS_VALID)
+       {
+               p->p_csflags |= CS_DEBUGGED;
+       }
+       
        proc_unlock(p);
+       
        vm_map_switch_protect(get_task_map(p->task), FALSE);
 #endif
        return (p->p_csflags & (CS_KILL | CS_HARD)) == 0;
 }
 
 int
-cs_invalid_page(
-       addr64_t vaddr)
+cs_invalid_page(addr64_t vaddr, boolean_t *cs_killed)
 {
        struct proc     *p;
        int             send_kill = 0, retval = 0, verbose = cs_debug;
@@ -192,25 +250,12 @@ cs_invalid_page(
 
        /* CS_KILL triggers a kill signal, and no you can't have the page. Nothing else. */
        if (p->p_csflags & CS_KILL) {
-               if (panic_on_cs_killed &&
-                   vaddr >= SHARED_REGION_BASE &&
-                   vaddr < SHARED_REGION_BASE + SHARED_REGION_SIZE) {
-                       panic("<rdar://14393620> cs_invalid_page(va=0x%llx): killing p=%p\n", (uint64_t) vaddr, p);
-               }
                p->p_csflags |= CS_KILLED;
                cs_procs_killed++;
                send_kill = 1;
                retval = 1;
        }
        
-#if __x86_64__
-       if (panic_on_cs_killed &&
-           vaddr >= SHARED_REGION_BASE &&
-           vaddr < SHARED_REGION_BASE + SHARED_REGION_SIZE) {
-               panic("<rdar://14393620> cs_invalid_page(va=0x%llx): cs error p=%p\n", (uint64_t) vaddr, p);
-       }
-#endif /* __x86_64__ */
-
        /* CS_HARD means fail the mapping operation so the process stays valid. */
        if (p->p_csflags & CS_HARD) {
                retval = 1;
@@ -231,8 +276,15 @@ cs_invalid_page(
                       retval ? "denying" : "allowing (remove VALID)",
                       send_kill ? " sending SIGKILL" : "");
 
-       if (send_kill)
-               threadsignal(current_thread(), SIGKILL, EXC_BAD_ACCESS);
+       if (send_kill) {
+               /* We will set the exit reason for the thread later */
+               threadsignal(current_thread(), SIGKILL, EXC_BAD_ACCESS, FALSE);
+               if (cs_killed) {
+                       *cs_killed = TRUE;
+               }
+       } else if (cs_killed) {
+               *cs_killed = FALSE;
+       }
 
 
        return retval;
@@ -243,10 +295,10 @@ cs_invalid_page(
  */
 
 int
-cs_enforcement(struct proc *p)
+cs_process_enforcement(struct proc *p)
 {
 
-       if (cs_enforcement_enable)
+       if (cs_process_enforcement_enable)
                return 1;
        
        if (p == NULL)
@@ -258,300 +310,256 @@ cs_enforcement(struct proc *p)
        return 0;
 }
 
-static struct {
-       struct cscsr_functions *funcs;
-       vm_map_offset_t csr_map_base;
-       vm_map_size_t csr_map_size;
-       int inuse;
-       int disabled;
-} csr_state;
+int
+cs_process_global_enforcement(void)
+{
+       return cs_process_enforcement_enable ? 1 : 0;
+}
 
-SYSCTL_INT(_vm, OID_AUTO, sigpup_disable, CTLFLAG_RW | CTLFLAG_LOCKED, &csr_state.disabled, 0, "");
+int
+cs_system_enforcement(void)
+{
+       return cs_system_enforcement_enable ? 1 : 0;
+}
 
-static int
-vnsize(vfs_context_t vfs, vnode_t vp, uint64_t *size)
+/*
+ * Returns whether a given process is still valid.
+ */
+int
+cs_valid(struct proc *p)
 {
-       struct vnode_attr va;
-       int error;
 
-       VATTR_INIT(&va);
-       VATTR_WANTED(&va, va_data_size);
+       if (p == NULL)
+               p = current_proc();
+
+       if (p != NULL && (p->p_csflags & CS_VALID))
+               return 1;
 
-       error = vnode_getattr(vp, &va, vfs);
-       if (error)
-               return error;
-       *size = va.va_data_size;
        return 0;
 }
 
+/*
+ * Library validation functions 
+ */
 int
-sigpup_install(user_addr_t argsp)
+cs_require_lv(struct proc *p)
 {
-       struct sigpup_install_table args;
-       memory_object_control_t control;
-       kern_return_t result;
-       vfs_context_t vfs = NULL;
-       struct vnode_attr va;
-       vnode_t vp = NULL;
-        char *buf = NULL;
-       uint64_t size;
-       size_t len = 0;
-       int error = 0;
        
-       if (!cs_enforcement_enable || csr_state.funcs == NULL)
-               return ENOTSUP;
-
-       lck_rw_lock_exclusive(SigPUPLock);
-
-       if (kauth_cred_issuser(kauth_cred_get()) == 0) {
-               error = EPERM;
-               goto cleanup;
-       }
-
-       if (cs_debug > 10)
-               printf("sigpup install\n");
-
-       if (csr_state.csr_map_base != 0 || csr_state.inuse) {
-               error = EPERM;
-               goto cleanup;
-       }
-
-       if (USER_ADDR_NULL == argsp) {
-               error = EINVAL;
-               goto cleanup;
-       }
-       if ((error = copyin(argsp, &args, sizeof(args))) != 0)
-               goto cleanup;
-
-       if (cs_debug > 10)
-               printf("sigpup install with args\n");
-
-       MALLOC(buf, char *, MAXPATHLEN, M_TEMP, M_WAITOK);
-       if (buf == NULL) {
-               error = ENOMEM;
-               goto cleanup;
-       }
-       if ((error = copyinstr((user_addr_t)args.path, buf, MAXPATHLEN, &len)) != 0)
-               goto cleanup;
-
-       if ((vfs = vfs_context_create(NULL)) == NULL) {
-               error = ENOMEM;
-               goto cleanup;
-       }
-
-       if ((error = vnode_lookup(buf, VNODE_LOOKUP_NOFOLLOW, &vp, vfs)) != 0)
-               goto cleanup;
-
-       if (cs_debug > 10)
-               printf("sigpup found file: %s\n", buf);
+       if (cs_library_val_enable)
+               return 1;
 
-       /* make sure vnode is on the process's root volume */
-       if (rootvnode->v_mount != vp->v_mount) {
-               if (cs_debug) printf("sigpup csr no on root volume\n");
-               error = EPERM;
-               goto cleanup;
-       }
+       if (p == NULL)
+               p = current_proc();
+       
+       if (p != NULL && (p->p_csflags & CS_REQUIRE_LV))
+               return 1;
+       
+       return 0;
+}
 
-       /* make sure vnode is owned by "root" */
-       VATTR_INIT(&va);
-       VATTR_WANTED(&va, va_uid);
-       error = vnode_getattr(vp, &va, vfs);
-       if (error)
-               goto cleanup;
-
-       if (va.va_uid != 0) {
-               if (cs_debug) printf("sigpup: csr file not owned by root\n");
-               error = EPERM;
-               goto cleanup;
+int
+csproc_forced_lv(struct proc* p)
+{
+       if (p == NULL) {
+               p = current_proc();
        }
-
-       error = vnsize(vfs, vp, &size);
-       if (error)
-               goto cleanup;
-
-       control = ubc_getobject(vp, 0);
-       if (control == MEMORY_OBJECT_CONTROL_NULL) {
-               error = EINVAL;
-               goto cleanup;
+       if (p != NULL && (p->p_csflags & CS_FORCED_LV)) {
+               return 1;
        }
+       return 0;
+}
 
-       csr_state.csr_map_size = mach_vm_round_page(size);
-
-       if (cs_debug > 10)
-               printf("mmap!\n");
-
-       result = vm_map_enter_mem_object_control(kernel_map,
-                                                &csr_state.csr_map_base,
-                                                csr_state.csr_map_size,
-                                                0, VM_FLAGS_ANYWHERE,
-                                                control, 0 /* file offset */,
-                                                0 /* cow */,
-                                                VM_PROT_READ,
-                                                VM_PROT_READ, 
-                                                VM_INHERIT_DEFAULT);
-       if (result != KERN_SUCCESS) {
-               error = EINVAL;
-               goto cleanup;
-       }
+/*
+ * <rdar://problem/24634089> added to allow system level library
+ *  validation check at mac_cred_label_update_execve time
+ */
+int
+cs_system_require_lv(void)
+{
+       return cs_library_val_enable ? 1 : 0;
+}
 
-       error = csr_state.funcs->csr_validate_header((const uint8_t *)csr_state.csr_map_base,
-           csr_state.csr_map_size);
-       if (error) {
-               if (cs_debug > 10)
-                       printf("sigpup header invalid, dropping mapping");
-               sigpup_drop();
-               goto cleanup;
-       }
+/*
+ * Function: csblob_get_base_offset
+ *
+ * Description: This function returns the base offset into the (possibly universal) binary
+ *             for a given blob.
+*/
 
-       if (cs_debug > 10)
-               printf("table loaded %ld bytes\n", (long)csr_state.csr_map_size);
+off_t
+csblob_get_base_offset(struct cs_blob *blob)
+{
+    return blob->csb_base_offset;
+}
 
-cleanup:
-       lck_rw_unlock_exclusive(SigPUPLock);
+/*
+ * Function: csblob_get_size
+ *
+ * Description: This function returns the size of a given blob.
+*/
 
-        if (buf)
-                FREE(buf, M_TEMP);
-       if (vp)
-               (void)vnode_put(vp);
-       if (vfs)
-               (void)vfs_context_rele(vfs);
-        
-       if (error)
-               printf("sigpup: load failed with error: %d\n", error);
+vm_size_t
+csblob_get_size(struct cs_blob *blob)
+{
+    return blob->csb_mem_size;
+}
 
+/*
+ * Function: csblob_get_addr
+ *
+ * Description: This function returns the address of a given blob.
+*/
 
-       return error;
+vm_address_t
+csblob_get_addr(struct cs_blob *blob)
+{
+    return blob->csb_mem_kaddr;
 }
 
+/*
+ * Function: csblob_get_platform_binary
+ *
+ * Description: This function returns true if the binary is
+ *             in the trust cache.
+*/
+
 int
-sigpup_drop(void)
+csblob_get_platform_binary(struct cs_blob *blob)
 {
+    if (blob && blob->csb_platform_binary)
+       return 1;
+    return 0;
+}
 
-       if (kauth_cred_issuser(kauth_cred_get()) == 0)
-               return EPERM;
-
-       lck_rw_lock_exclusive(SigPUPLock);
-
-       if (csr_state.csr_map_base == 0 || csr_state.inuse) {
-               printf("failed to unload the sigpup database\n");
-               lck_rw_unlock_exclusive(SigPUPLock);
-               return EINVAL;
-       }
-
-       if (cs_debug > 10)
-               printf("sigpup: unloading\n");
-
-       (void)mach_vm_deallocate(kernel_map,
-           csr_state.csr_map_base, csr_state.csr_map_size);
-
-       csr_state.csr_map_base = 0;
-       csr_state.csr_map_size = 0;
-
-       lck_rw_unlock_exclusive(SigPUPLock);
+/*
+ * Function: csblob_get_flags
+ *
+ * Description: This function returns the flags for a given blob
+*/
 
-       return 0;
+unsigned int
+csblob_get_flags(struct cs_blob *blob)
+{
+    return blob->csb_flags;
 }
 
-void   sigpup_attach_vnode(vnode_t); /* XXX */
+/*
+ * Function: csblob_get_hashtype
+ *
+ * Description: This function returns the hash type for a given blob
+*/
 
-void
-sigpup_attach_vnode(vnode_t vp)
+uint8_t
+csblob_get_hashtype(struct cs_blob const * const blob)
 {
-       const void *csblob;
-       size_t cslen;
+    return blob->csb_hashtype != NULL ? cs_hash_type(blob->csb_hashtype) : 0;
+}
 
-       if (!cs_enforcement_enable || csr_state.funcs == NULL || csr_state.csr_map_base == 0 || csr_state.disabled)
-               return;
+/*
+ * Function: csproc_get_blob
+ *
+ * Description: This function returns the cs_blob
+ *             for the process p
+ */
+struct cs_blob *
+csproc_get_blob(struct proc *p)
+{
+       if (NULL == p)
+               return NULL;
 
-       /* if the file is not on the root volumes or already been check, skip */
-       if (vp->v_mount != rootvnode->v_mount || (vp->v_flag & VNOCS))
-               return;
+       if (NULL == p->p_textvp)
+               return NULL;
 
-       csblob = csr_state.funcs->csr_find_file_codedirectory(vp, (const uint8_t *)csr_state.csr_map_base,
-           (size_t)csr_state.csr_map_size, &cslen);
-       if (csblob) {
-               ubc_cs_sigpup_add(vp, (vm_address_t)csblob, (vm_size_t)cslen);
-               csr_state.inuse = 1;
+       if ((p->p_csflags & CS_SIGNED) == 0) {
+               return NULL;
        }
-       vp->v_flag |= VNOCS;
-}
 
-void
-cs_register_cscsr(struct cscsr_functions *funcs)
-{
-       if (csr_state.funcs || funcs->csr_version < CSCSR_VERSION)
-               return;
-       csr_state.funcs = funcs;
+       return ubc_cs_blob_get(p->p_textvp, -1, p->p_textoff);
 }
 
 /*
- * Library validation functions 
+ * Function: csvnode_get_blob
+ *
+ * Description: This function returns the cs_blob
+ *             for the vnode vp
  */
-int
-cs_require_lv(struct proc *p)
+struct cs_blob *
+csvnode_get_blob(struct vnode *vp, off_t offset)
 {
-       
-       if (cs_library_val_enable)
-               return 1;
-
-       if (p == NULL)
-               p = current_proc();
-       
-       if (p != NULL && (p->p_csflags & CS_REQUIRE_LV))
-               return 1;
-       
-       return 0;
+       return ubc_cs_blob_get(vp, -1, offset);
 }
 
 /*
  * Function: csblob_get_teamid
  *
- * Description: This function returns a pointer to the team id
-               stored within the codedirectory of the csblob.
-               If the codedirectory predates team-ids, it returns
-               NULL.
-               This does not copy the name but returns a pointer to
-               it within the CD. Subsequently, the CD must be 
-               available when this is used.
+ * Description: This function returns a pointer to the
+ *             team id of csblob
 */
 const char *
 csblob_get_teamid(struct cs_blob *csblob)
+{
+       return csblob->csb_teamid;
+}
+
+/*
+ * Function: csblob_get_identity
+ *
+ * Description: This function returns a pointer to the
+ *             identity string
+ */
+const char *
+csblob_get_identity(struct cs_blob *csblob)
 {
        const CS_CodeDirectory *cd;
 
-       if ((cd = (const CS_CodeDirectory *)cs_find_blob(
-                                               csblob, CSSLOT_CODEDIRECTORY, CSMAGIC_CODEDIRECTORY)) == NULL)
-               return NULL;
-       
-       if (ntohl(cd->version) < CS_SUPPORTSTEAMID)
+       cd = (const CS_CodeDirectory *)csblob_find_blob(csblob, CSSLOT_CODEDIRECTORY, CSMAGIC_CODEDIRECTORY);
+       if (cd == NULL)
                return NULL;
 
-       if (ntohl(cd->teamOffset) == 0)
+       if (cd->identOffset == 0)
                return NULL;
-       
-       const char *name = ((const char *)cd) + ntohl(cd->teamOffset);
-       if (cs_debug > 1)
-               printf("found team-id %s in cdblob\n", name);
 
-       return name;
+       return ((const char *)cd) + ntohl(cd->identOffset);
 }
 
 /*
- * Function: csproc_get_blob
+ * Function: csblob_get_cdhash
  *
- * Description: This function returns the cs_blob
- *             for the process p
+ * Description: This function returns a pointer to the
+ *             cdhash of csblob (20 byte array)
  */
-static struct cs_blob *
-csproc_get_blob(struct proc *p)
+const uint8_t *
+csblob_get_cdhash(struct cs_blob *csblob)
 {
-       if (NULL == p)
-               return NULL;
+       return csblob->csb_cdhash;
+}
 
-       if (NULL == p->p_textvp)
-               return NULL;
+/*
+ * Function: csblob_get_signer_type
+ *
+ * Description: This function returns the signer type
+ *             as an integer
+ */
+unsigned int
+csblob_get_signer_type(struct cs_blob *csblob)
+{
+       return csblob->csb_signer_type;
+}
 
-       return ubc_cs_blob_get(p->p_textvp, -1, p->p_textoff);
+void *
+csblob_entitlements_dictionary_copy(struct cs_blob *csblob)
+{
+    if (!csblob->csb_entitlements) return NULL;
+    osobject_retain(csblob->csb_entitlements);
+    return csblob->csb_entitlements;
+}
+
+void
+csblob_entitlements_dictionary_set(struct cs_blob *csblob, void * entitlements)
+{
+    assert(csblob->csb_entitlements == NULL);
+    if (entitlements) osobject_retain(entitlements);
+    csblob->csb_entitlements = entitlements;
 }
 
 /*
@@ -566,8 +574,28 @@ csproc_get_teamid(struct proc *p)
        struct cs_blob *csblob;
 
        csblob = csproc_get_blob(p);
+       if (csblob == NULL)
+           return NULL;
+
+       return csblob_get_teamid(csblob);
+}
+
+/*
+ * Function: csproc_get_signer_type 
+ *
+ * Description: This function returns the signer type
+ *             of the process p
+*/
+unsigned int
+csproc_get_signer_type(struct proc *p)
+{
+       struct cs_blob *csblob;
+
+       csblob = csproc_get_blob(p);
+       if (csblob == NULL)
+           return CS_SIGNER_TYPE_UNKNOWN;
 
-       return (csblob == NULL) ? NULL : csblob->csb_teamid;
+       return csblob_get_signer_type(csblob);
 }
 
 /*
@@ -585,8 +613,10 @@ csvnode_get_teamid(struct vnode *vp, off_t offset)
                return NULL;
 
        csblob = ubc_cs_blob_get(vp, -1, offset);
+       if (csblob == NULL)
+           return NULL;
 
-       return (csblob == NULL) ? NULL : csblob->csb_teamid;
+       return csblob_get_teamid(csblob);
 }
 
 /*
@@ -607,6 +637,100 @@ csproc_get_platform_binary(struct proc *p)
        return (csblob == NULL) ? 0 : csblob->csb_platform_binary;
 }
 
+int
+csproc_get_platform_path(struct proc *p)
+{
+       struct cs_blob *csblob;
+
+    csblob = csproc_get_blob(p);
+
+       return (csblob == NULL) ? 0 : csblob->csb_platform_path;
+}
+
+#if DEVELOPMENT || DEBUG
+void
+csproc_clear_platform_binary(struct proc *p)
+{
+       struct cs_blob *csblob = csproc_get_blob(p);
+
+       if (csblob == NULL) {
+               return;
+       }
+
+       if (cs_debug) {
+               printf("clearing platform binary on proc/task: pid = %d\n", p->p_pid);
+       }
+
+       csblob->csb_platform_binary = 0;
+       csblob->csb_platform_path = 0;
+       task_set_platform_binary(proc_task(p), FALSE);
+}
+#endif
+
+void
+csproc_disable_enforcement(struct proc* __unused p)
+{
+#if !CONFIG_ENFORCE_SIGNED_CODE
+       if (p != NULL) {
+               proc_lock(p);
+               p->p_csflags &= (~CS_ENFORCEMENT);
+               proc_unlock(p);
+       }
+#endif
+}
+
+/* Function: csproc_mark_invalid_allowed
+ *
+ * Description: Mark the process as being allowed to go invalid. Called as part of
+ *             task_for_pid and ptrace policy. Note CS_INVALID_ALLOWED only matters for
+ *             processes that have been opted into CS_ENFORCEMENT.
+ */
+void
+csproc_mark_invalid_allowed(struct proc* __unused p)
+{
+#if !CONFIG_ENFORCE_SIGNED_CODE
+       if (p != NULL) {
+               proc_lock(p);
+               p->p_csflags |= CS_INVALID_ALLOWED;
+               proc_unlock(p);
+       }
+#endif
+}
+
+/*
+ * Function: csproc_check_invalid_allowed
+ *
+ * Description: Returns 1 if the process has been marked as allowed to go invalid
+ *             because it gave its task port to an allowed process.
+ */
+int
+csproc_check_invalid_allowed(struct proc* __unused p)
+{
+#if !CONFIG_ENFORCE_SIGNED_CODE
+       if (p == NULL) {
+               p = current_proc();
+       }
+
+       if (p != NULL && (p->p_csflags & CS_INVALID_ALLOWED))
+               return 1;
+#endif
+       return 0;
+}
+
+/*
+ * Function: csproc_get_prod_signed
+ *
+ * Description: Returns 1 if process is not signed with a developer identity.
+ *             Note the inverted meaning from the cs_flag to make the error case safer.
+ *             Will go away with rdar://problem/28322552.
+ */
+int
+csproc_get_prod_signed(struct proc *p)
+{
+       return ((p->p_csflags & CS_DEV_CODE) == 0);
+}
+
+
 /*
  * Function: csfg_get_platform_binary
  *
@@ -648,6 +772,68 @@ out:
        return platform_binary;
 }
 
+uint8_t *
+csfg_get_cdhash(struct fileglob *fg, uint64_t offset, size_t *cdhash_size)
+{
+       vnode_t vp;
+
+       if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE)
+               return NULL;
+
+       vp = (struct vnode *)fg->fg_data;
+       if (vp == NULL)
+               return NULL;
+
+       struct cs_blob *csblob = NULL;
+       if ((csblob = ubc_cs_blob_get(vp, -1, offset)) == NULL) 
+               return NULL;
+
+       if (cdhash_size)
+               *cdhash_size = CS_CDHASH_LEN;
+
+       return csblob->csb_cdhash;
+}
+
+/*
+ * Function: csfg_get_signer_type
+ *
+ * Description: This returns the signer type
+ *             for the fileglob fg
+ */
+unsigned int
+csfg_get_signer_type(struct fileglob *fg)
+{
+       struct ubc_info *uip;
+       unsigned int signer_type = CS_SIGNER_TYPE_UNKNOWN;
+       vnode_t vp;
+
+       if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE)
+               return CS_SIGNER_TYPE_UNKNOWN;
+       
+       vp = (struct vnode *)fg->fg_data;
+       if (vp == NULL)
+               return CS_SIGNER_TYPE_UNKNOWN;
+
+       vnode_lock(vp);
+       if (!UBCINFOEXISTS(vp))
+               goto out;
+       
+       uip = vp->v_ubcinfo;
+       if (uip == NULL)
+               goto out;
+       
+       if (uip->cs_blobs == NULL)
+               goto out;
+
+       /* It is OK to extract the signer type from the first blob,
+          because all blobs of a vnode must have the same signer type. */      
+       signer_type = uip->cs_blobs->csb_signer_type;
+out:
+       vnode_unlock(vp);
+
+       return signer_type;
+}
+
 /*
  * Function: csfg_get_teamid
  *
@@ -688,12 +874,153 @@ out:
        return str;
 }
 
+/*
+ * Function: csfg_get_prod_signed
+ *
+ * Description: Returns 1 if code is not signed with a developer identity.
+ *             Note the inverted meaning from the cs_flag to make the error case safer.
+ *             Will go away with rdar://problem/28322552.
+ */
+int
+csfg_get_prod_signed(struct fileglob *fg)
+{
+       struct ubc_info *uip;
+       vnode_t vp;
+       int prod_signed = 0;
+
+       if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE)
+               return 0;
+       
+       vp = (struct vnode *)fg->fg_data;
+       if (vp == NULL)
+               return 0;
+
+       vnode_lock(vp);
+       if (!UBCINFOEXISTS(vp))
+               goto out;
+       
+       uip = vp->v_ubcinfo;
+       if (uip == NULL)
+               goto out;
+       
+       if (uip->cs_blobs == NULL)
+               goto out;
+
+       /* It is OK to extract the flag from the first blob
+          because all blobs of a vnode must have the same cs_flags */  
+       prod_signed = (uip->cs_blobs->csb_flags & CS_DEV_CODE) == 0;
+out:
+       vnode_unlock(vp);
+
+       return prod_signed;
+}
+
+/*
+ * Function: csfg_get_identity
+ *
+ * Description: This function returns the codesign identity
+ *             for the fileglob
+ */
+const char *
+csfg_get_identity(struct fileglob *fg, off_t offset)
+{
+       vnode_t vp;
+       struct cs_blob *csblob = NULL;
+
+       if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE)
+               return NULL;
+
+       vp = (struct vnode *)fg->fg_data;
+       if (vp == NULL)
+               return NULL;
+
+       csblob = ubc_cs_blob_get(vp, -1, offset);
+       if (csblob == NULL)
+               return NULL;
+
+       return csblob_get_identity(csblob);
+}
+
+/*
+ * Function: csfg_get_platform_identifier
+ *
+ * Description: This function returns the codesign platform
+ *             identifier for the fileglob.  Assumes the fileproc
+ *             is being held busy to keep the fileglob consistent.
+ */
+uint8_t
+csfg_get_platform_identifier(struct fileglob *fg, off_t offset)
+{
+       vnode_t vp;
+
+       if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE)
+               return 0;
+
+       vp = (struct vnode *)fg->fg_data;
+       if (vp == NULL)
+               return 0;
+
+       return csvnode_get_platform_identifier(vp, offset);
+}
+
+/*
+ * Function: csvnode_get_platform_identifier
+ *
+ * Description: This function returns the codesign platform
+ *             identifier for the vnode.  Assumes a vnode reference
+ *             is held.
+ */
+uint8_t
+csvnode_get_platform_identifier(struct vnode *vp, off_t offset)
+{
+       struct cs_blob *csblob;
+       const CS_CodeDirectory *code_dir;
+
+       csblob = ubc_cs_blob_get(vp, -1, offset);
+       if (csblob == NULL)
+               return 0;
+
+       code_dir = csblob->csb_cd;
+       if (code_dir == NULL || ntohl(code_dir->length) < 8)
+               return 0;
+
+       return code_dir->platform;
+}
+
+/*
+ * Function: csproc_get_platform_identifier
+ *
+ * Description: This function returns the codesign platform
+ *             identifier for the proc.  Assumes proc will remain
+ *             valid through call.
+ */
+uint8_t
+csproc_get_platform_identifier(struct proc *p)
+{
+       if (NULL == p->p_textvp)
+               return 0;
+
+       return csvnode_get_platform_identifier(p->p_textvp, p->p_textoff);
+}
+
 uint32_t
 cs_entitlement_flags(struct proc *p)
 {
        return (p->p_csflags & CS_ENTITLEMENT_FLAGS);
 }
 
+int
+cs_restricted(struct proc *p)
+{
+       return (p->p_csflags & CS_RESTRICT) ? 1 : 0;
+}
+
+int
+csproc_hardened_runtime(struct proc* p)
+{
+       return (p->p_csflags & CS_RUNTIME) ? 1 : 0;
+}
+
 /*
  * Function: csfg_get_path
  *
@@ -717,3 +1044,110 @@ csfg_get_path(struct fileglob *fg, char *path, int *len)
           or an error code */
        return vn_getpath(vp, path, len);
 }
+
+/* Retrieve the entitlements blob for a process.
+ * Returns:
+ *   EINVAL    no text vnode associated with the process
+ *   EBADEXEC   invalid code signing data
+ *   0         no error occurred
+ *
+ * On success, out_start and out_length will point to the
+ * entitlements blob if found; or will be set to NULL/zero
+ * if there were no entitlements.
+ */
+
+int
+cs_entitlements_blob_get(proc_t p, void **out_start, size_t *out_length)
+{
+       struct cs_blob *csblob;
+
+       *out_start = NULL;
+       *out_length = 0;
+
+       if ((p->p_csflags & CS_SIGNED) == 0) {
+               return 0;
+       }
+
+       if (NULL == p->p_textvp)
+               return EINVAL;
+
+       if ((csblob = ubc_cs_blob_get(p->p_textvp, -1, p->p_textoff)) == NULL)
+               return 0;
+
+       return csblob_get_entitlements(csblob, out_start, out_length);
+}
+
+/* Retrieve the codesign identity for a process.
+ * Returns:
+ *   NULL      an error occured
+ *   string    the cs_identity
+ */
+
+const char *
+cs_identity_get(proc_t p)
+{
+       struct cs_blob *csblob;
+
+       if ((p->p_csflags & CS_SIGNED) == 0) {
+               return NULL;
+       }
+
+       if (NULL == p->p_textvp)
+               return NULL;
+
+       if ((csblob = ubc_cs_blob_get(p->p_textvp, -1, p->p_textoff)) == NULL)
+               return NULL;
+
+       return csblob_get_identity(csblob);
+}
+
+/*
+ * DO NOT USE THIS FUNCTION!
+ * Use the properly guarded csproc_get_blob instead.
+ *
+ * This is currently here to allow detached signatures to work
+ * properly. The only user of this function is also checking
+ * for CS_VALID.
+ */
+
+int
+cs_blob_get(proc_t p, void **out_start, size_t *out_length)
+{
+       struct cs_blob *csblob;
+
+       *out_start = NULL;
+       *out_length = 0;
+
+       if (NULL == p->p_textvp)
+               return EINVAL;
+
+       if ((csblob = ubc_cs_blob_get(p->p_textvp, -1, p->p_textoff)) == NULL)
+               return 0;
+
+       *out_start = (void *)csblob->csb_mem_kaddr;
+       *out_length = csblob->csb_mem_size;
+
+       return 0;
+}
+
+/*
+ * return cshash of a process, cdhash is of size CS_CDHASH_LEN
+ */
+
+uint8_t *
+cs_get_cdhash(struct proc *p)
+{
+       struct cs_blob *csblob;
+
+       if ((p->p_csflags & CS_SIGNED) == 0) {
+               return NULL;
+       }
+
+       if (NULL == p->p_textvp)
+               return NULL;
+
+       if ((csblob = ubc_cs_blob_get(p->p_textvp, -1, p->p_textoff)) == NULL)
+               return NULL;
+
+       return csblob->csb_cdhash;
+}