int cs_force_hard = 0;
int cs_debug = 0;
#if SECURE_KERNEL
-const int cs_enforcement_enable=1;
-const int cs_library_val_enable=1;
-#else
+const int cs_enforcement_enable = 1;
+const int cs_library_val_enable = 1;
+#else /* !SECURE_KERNEL */
+int cs_enforcement_panic=0;
+
#if CONFIG_ENFORCE_SIGNED_CODE
-int cs_enforcement_enable=1;
+int cs_enforcement_enable = 1;
#else
-int cs_enforcement_enable=0;
-#endif /* CONFIG_ENFORCE_SIGNED_CODE */
+int cs_enforcement_enable = 0;
+#endif
#if CONFIG_ENFORCE_LIBRARY_VALIDATION
int cs_library_val_enable = 1;
#else
int cs_library_val_enable = 0;
-#endif /* CONFIG_ENFORCE_LIBRARY_VALIDATION */
+#endif
-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, "");
#if !SECURE_KERNEL
SYSCTL_INT(_vm, OID_AUTO, cs_enforcement, CTLFLAG_RW | CTLFLAG_LOCKED, &cs_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_RW | CTLFLAG_LOCKED, &cs_library_val_enable, 0, "");
#endif
+#endif /* !SECURE_KERNEL */
int panic_on_cs_killed = 0;
void
}
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);
}
int
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;
-
-SYSCTL_INT(_vm, OID_AUTO, sigpup_disable, CTLFLAG_RW | CTLFLAG_LOCKED, &csr_state.disabled, 0, "");
-
-static int
-vnsize(vfs_context_t vfs, vnode_t vp, uint64_t *size)
-{
- struct vnode_attr va;
- int error;
-
- VATTR_INIT(&va);
- VATTR_WANTED(&va, va_data_size);
-
- error = vnode_getattr(vp, &va, vfs);
- if (error)
- return error;
- *size = va.va_data_size;
- return 0;
-}
-
-int
-sigpup_install(user_addr_t argsp)
-{
- 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);
-
- /* 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;
- }
-
- /* 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;
- }
-
- error = vnsize(vfs, vp, &size);
- if (error)
- goto cleanup;
-
- control = ubc_getobject(vp, 0);
- if (control == MEMORY_OBJECT_CONTROL_NULL) {
- error = EINVAL;
- goto cleanup;
- }
-
- 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;
- }
-
- 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;
- }
-
- if (cs_debug > 10)
- printf("table loaded %ld bytes\n", (long)csr_state.csr_map_size);
-
-cleanup:
- lck_rw_unlock_exclusive(SigPUPLock);
-
- 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);
-
-
- return error;
-}
-
-int
-sigpup_drop(void)
-{
-
- 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);
-
- return 0;
-}
-
-void sigpup_attach_vnode(vnode_t); /* XXX */
-
-void
-sigpup_attach_vnode(vnode_t vp)
-{
- const void *csblob;
- size_t cslen;
-
- if (!cs_enforcement_enable || csr_state.funcs == NULL || csr_state.csr_map_base == 0 || csr_state.disabled)
- return;
-
- /* 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;
-
- 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;
- }
- 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;
-}
-
/*
* Library validation functions
*/
}
/*
- * Function: csblob_get_teamid
+ * Function: csblob_get_platform_binary
*
- * 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 true if the binary is
+ * in the trust cache.
*/
-const char *
-csblob_get_teamid(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)
- return NULL;
+int
+csblob_get_platform_binary(struct cs_blob *blob)
+{
+ if (blob && blob->csb_platform_binary)
+ return 1;
+ return 0;
+}
- if (ntohl(cd->teamOffset) == 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);
+/*
+ * Function: csblob_get_flags
+ *
+ * Description: This function returns the flags for a given blob
+*/
- return name;
+unsigned int
+csblob_get_flags(struct cs_blob *blob)
+{
+ if (blob)
+ return blob->csb_flags;
+ return 0;
}
/*
* Description: This function returns the cs_blob
* for the process p
*/
-static struct cs_blob *
+struct cs_blob *
csproc_get_blob(struct proc *p)
{
if (NULL == p)
return ubc_cs_blob_get(p->p_textvp, -1, p->p_textoff);
}
+/*
+ * Function: csproc_get_blob
+ *
+ * Description: This function returns the cs_blob
+ * for the vnode vp
+ */
+struct cs_blob *
+csvnode_get_blob(struct vnode *vp, off_t offset)
+{
+ return ubc_cs_blob_get(vp, -1, offset);
+}
+
+/*
+ * Function: csblob_get_teamid
+ *
+ * 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;
+
+ cd = (const CS_CodeDirectory *)csblob_find_blob(csblob, CSSLOT_CODEDIRECTORY, CSMAGIC_CODEDIRECTORY);
+ if (cd == NULL)
+ return NULL;
+
+ if (cd->identOffset == 0)
+ return NULL;
+
+ return ((const char *)cd) + ntohl(cd->identOffset);
+}
+
+/*
+ * Function: csblob_get_cdhash
+ *
+ * Description: This function returns a pointer to the
+ * cdhash of csblob (20 byte array)
+ */
+const uint8_t *
+csblob_get_cdhash(struct cs_blob *csblob)
+{
+ return csblob->csb_cdhash;
+}
+
/*
* Function: csproc_get_teamid
*
struct cs_blob *csblob;
csblob = csproc_get_blob(p);
+ if (csblob == NULL)
+ return NULL;
- return (csblob == NULL) ? NULL : csblob->csb_teamid;
+ return csblob_get_teamid(csblob);
}
/*
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);
}
/*
return (csblob == NULL) ? 0 : csblob->csb_platform_binary;
}
+int
+csproc_get_platform_path(struct proc *p)
+{
+ struct cs_blob *csblob = csproc_get_blob(p);
+
+ return (csblob == NULL) ? 0 : csblob->csb_platform_path;
+}
+
/*
* Function: csfg_get_platform_binary
*
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_teamid
*
return (p->p_csflags & CS_ENTITLEMENT_FLAGS);
}
+int
+cs_restricted(struct proc *p)
+{
+ return (p->p_csflags & CS_RESTRICT) ? 1 : 0;
+}
+
/*
* Function: csfg_get_path
*
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 (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 (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);
+}
+
+
+/* Retrieve the codesign blob for a process.
+ * Returns:
+ * EINVAL no text vnode associated with the process
+ * 0 no error occurred
+ *
+ * On success, out_start and out_length will point to the
+ * cms blob if found; or will be set to NULL/zero
+ * if there were no blob.
+ */
+
+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 (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;
+}