X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/4a3eedf9ecc9bbe3f3a5c6ce5e53ad199d639d32..5ba3f43ea354af8ad55bea84372a2bc834d8757c:/security/mac_base.c diff --git a/security/mac_base.c b/security/mac_base.c index b65948131..ec5955df8 100644 --- a/security/mac_base.c +++ b/security/mac_base.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 Apple Inc. All rights reserved. + * Copyright (c) 2007-2016 Apple Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * @@ -79,7 +79,7 @@ #include #include #include -#include +#include #include #include #include @@ -88,6 +88,7 @@ #include #include +#include #include #include @@ -95,7 +96,6 @@ #include #include #include -#include #if CONFIG_MACF #include @@ -105,6 +105,10 @@ #include #endif +#if CONFIG_EMBEDDED +#include +#endif + /* * define MB_DEBUG to display run-time debugging information * #define MB_DEBUG 1 @@ -123,8 +127,6 @@ SYSCTL_NODE(, OID_AUTO, security, CTLFLAG_RW|CTLFLAG_LOCKED, 0, SYSCTL_NODE(_security, OID_AUTO, mac, CTLFLAG_RW|CTLFLAG_LOCKED, 0, "TrustedBSD MAC policy controls"); - - /* * Declare that the kernel provides MAC support, version 1. This permits * modules to refuse to be loaded if the necessary support isn't present, @@ -140,7 +142,7 @@ MODULE_VERSION(kernel_mac_support, 1); static unsigned int mac_max_slots = MAC_MAX_SLOTS; static unsigned int mac_slot_offsets_free = (1 << MAC_MAX_SLOTS) - 1; -SYSCTL_UINT(_security_mac, OID_AUTO, max_slots, CTLFLAG_RD, +SYSCTL_UINT(_security_mac, OID_AUTO, max_slots, CTLFLAG_RD | CTLFLAG_LOCKED, &mac_max_slots, 0, ""); /* @@ -161,94 +163,77 @@ int mac_late = 0; * already has to deal with uninitialized labels, this probably won't * be a problem. Note: currently no locking. Will this be a problem? */ -#if !defined(CONFIG_MACF_ALWAYS_LABEL_MBUF) && 0 -static int mac_labelmbufs = 0; +#if CONFIG_MACF_NET +unsigned int mac_label_mbufs = 1; +SYSCTL_UINT(_security_mac, OID_AUTO, label_mbufs, SECURITY_MAC_CTLFLAGS, + &mac_label_mbufs, 0, "Label all MBUFs"); #endif -unsigned int mac_mmap_revocation = 0; -SYSCTL_UINT(_security_mac, OID_AUTO, mmap_revocation, CTLFLAG_RW, - &mac_mmap_revocation, 0, "Revoke mmap access to files on subject " - "relabel"); -unsigned int mac_mmap_revocation_via_cow = 0; -SYSCTL_UINT(_security_mac, OID_AUTO, mmap_revocation_via_cow, CTLFLAG_RW, - &mac_mmap_revocation_via_cow, 0, "Revoke mmap access to files via " - "copy-on-write semantics, or by removing all write access"); +/* + * Flag to indicate whether or not we should allocate label storage for + * new vnodes. Since most dynamic policies we currently work with don't + * rely on vnode labeling, try to avoid paying the cost of mtag allocation + * unless specifically notified of interest. One result of this is + * that if a dynamically loaded policy requests vnode labels, it must + * be able to deal with a NULL label being returned on any vnodes that + * were already in flight when the policy was loaded. Since the policy + * already has to deal with uninitialized labels, this probably won't + * be a problem. + */ +unsigned int mac_label_vnodes = 0; +SYSCTL_UINT(_security_mac, OID_AUTO, labelvnodes, SECURITY_MAC_CTLFLAGS, + &mac_label_vnodes, 0, "Label all vnodes"); unsigned int mac_device_enforce = 1; -SYSCTL_UINT(_security_mac, OID_AUTO, device_enforce, CTLFLAG_RW, +SYSCTL_UINT(_security_mac, OID_AUTO, device_enforce, SECURITY_MAC_CTLFLAGS, &mac_device_enforce, 0, "Enforce MAC policy on device operations"); -unsigned int mac_file_enforce = 0; -SYSCTL_UINT(_security_mac, OID_AUTO, file_enforce, CTLFLAG_RW, - &mac_file_enforce, 0, "Enforce MAC policy on file operations"); - -unsigned int mac_iokit_enforce = 0; -SYSCTL_UINT(_security_mac, OID_AUTO, iokit_enforce, CTLFLAG_RW, - &mac_file_enforce, 0, "Enforce MAC policy on IOKit operations"); - unsigned int mac_pipe_enforce = 1; -SYSCTL_UINT(_security_mac, OID_AUTO, pipe_enforce, CTLFLAG_RW, +SYSCTL_UINT(_security_mac, OID_AUTO, pipe_enforce, SECURITY_MAC_CTLFLAGS, &mac_pipe_enforce, 0, "Enforce MAC policy on pipe operations"); unsigned int mac_posixsem_enforce = 1; -SYSCTL_UINT(_security_mac, OID_AUTO, posixsem_enforce, CTLFLAG_RW, +SYSCTL_UINT(_security_mac, OID_AUTO, posixsem_enforce, SECURITY_MAC_CTLFLAGS, &mac_posixsem_enforce, 0, "Enforce MAC policy on POSIX semaphores"); unsigned int mac_posixshm_enforce = 1; -SYSCTL_UINT(_security_mac, OID_AUTO, posixshm_enforce, CTLFLAG_RW, +SYSCTL_UINT(_security_mac, OID_AUTO, posixshm_enforce, SECURITY_MAC_CTLFLAGS, &mac_posixshm_enforce, 0, "Enforce MAC policy on Posix Shared Memory"); unsigned int mac_proc_enforce = 1; -SYSCTL_UINT(_security_mac, OID_AUTO, proc_enforce, CTLFLAG_RW, +SYSCTL_UINT(_security_mac, OID_AUTO, proc_enforce, SECURITY_MAC_CTLFLAGS, &mac_proc_enforce, 0, "Enforce MAC policy on process operations"); unsigned int mac_socket_enforce = 1; -SYSCTL_UINT(_security_mac, OID_AUTO, socket_enforce, CTLFLAG_RW, +SYSCTL_UINT(_security_mac, OID_AUTO, socket_enforce, SECURITY_MAC_CTLFLAGS, &mac_socket_enforce, 0, "Enforce MAC policy on socket operations"); unsigned int mac_system_enforce = 1; -SYSCTL_UINT(_security_mac, OID_AUTO, system_enforce, CTLFLAG_RW, +SYSCTL_UINT(_security_mac, OID_AUTO, system_enforce, SECURITY_MAC_CTLFLAGS, &mac_system_enforce, 0, "Enforce MAC policy on system-wide interfaces"); unsigned int mac_sysvmsg_enforce = 1; -SYSCTL_UINT(_security_mac, OID_AUTO, sysvmsg_enforce, CTLFLAG_RW, +SYSCTL_UINT(_security_mac, OID_AUTO, sysvmsg_enforce, SECURITY_MAC_CTLFLAGS, &mac_sysvmsg_enforce, 0, "Enforce MAC policy on System V IPC message queues"); unsigned int mac_sysvsem_enforce = 1; -SYSCTL_UINT(_security_mac, OID_AUTO, sysvsem_enforce, CTLFLAG_RW, +SYSCTL_UINT(_security_mac, OID_AUTO, sysvsem_enforce, SECURITY_MAC_CTLFLAGS, &mac_sysvsem_enforce, 0, "Enforce MAC policy on System V IPC semaphores"); unsigned int mac_sysvshm_enforce = 1; -SYSCTL_INT(_security_mac, OID_AUTO, sysvshm_enforce, CTLFLAG_RW, +SYSCTL_INT(_security_mac, OID_AUTO, sysvshm_enforce, SECURITY_MAC_CTLFLAGS, &mac_sysvshm_enforce, 0, "Enforce MAC policy on System V Shared Memory"); unsigned int mac_vm_enforce = 1; -SYSCTL_INT(_security_mac, OID_AUTO, vm_enforce, CTLFLAG_RW, +SYSCTL_INT(_security_mac, OID_AUTO, vm_enforce, SECURITY_MAC_CTLFLAGS, &mac_vm_enforce, 0, "Enforce MAC policy on VM operations"); unsigned int mac_vnode_enforce = 1; -SYSCTL_UINT(_security_mac, OID_AUTO, vnode_enforce, CTLFLAG_RW, +SYSCTL_UINT(_security_mac, OID_AUTO, vnode_enforce, SECURITY_MAC_CTLFLAGS, &mac_vnode_enforce, 0, "Enforce MAC policy on vnode operations"); - -#if CONFIG_MACF_MACH -unsigned int mac_port_enforce = 0; -SYSCTL_UINT(_security_mac, OID_AUTO, port_enforce, CTLFLAG_RW, - &mac_port_enforce, 0, "Enforce MAC policy on Mach port operations"); - -unsigned int mac_task_enforce = 0; -SYSCTL_UINT(_security_mac, OID_AUTO, task_enforce, CTLFLAG_RW, - &mac_task_enforce, 0, "Enforce MAC policy on Mach task operations"); -#endif - -#if CONFIG_MACF_NET -unsigned int mac_label_mbufs = 1; -SYSCTL_UINT(_security_mac, OID_AUTO, label_mbufs, CTLFLAG_RW, - &mac_label_mbufs, 0, "Label all MBUFs"); -#endif - -#if AUDIT +#if CONFIG_AUDIT /* * mac_audit_data_zone is the zone used for data pushed into the audit * record by policies. Using a zone simplifies memory management of this @@ -283,7 +268,12 @@ static lck_mtx_t *mac_policy_mtx; static int mac_policy_busy; +#if CONFIG_EMBEDDED +SECURITY_READ_ONLY_LATE(mac_policy_list_t) mac_policy_list; +SECURITY_READ_ONLY_LATE(static struct mac_policy_list_element) mac_policy_static_entries[MAC_POLICY_LIST_CHUNKSIZE]; +#else mac_policy_list_t mac_policy_list; +#endif /* * mac_label_element_list holds the master list of label namespaces for @@ -295,120 +285,6 @@ mac_policy_list_t mac_policy_list; struct mac_label_element_list_t mac_label_element_list; struct mac_label_element_list_t mac_static_label_element_list; -/* - * Journal of label operations that occur before policies are loaded. - */ -struct mac_label_journal_list_t mac_label_journal_list; - -int -mac_label_journal_add (struct label *l, int type) -{ - struct mac_label_journal *mlj; - - if (mac_label_journal_find(l)) - return (0); - - MALLOC(mlj, struct mac_label_journal *, - sizeof(struct mac_label_journal), M_MACTEMP, M_WAITOK); - mlj->l = l; - mlj->type = type; - TAILQ_INSERT_TAIL(&mac_label_journal_list, mlj, link); - - return (0); -} - -int -mac_label_journal_remove (struct label *l) -{ - struct mac_label_journal *mlj; - - mlj = mac_label_journal_find(l); - if (mlj == NULL) - return (-1); - - TAILQ_REMOVE(&mac_label_journal_list, mlj, link); - FREE(mlj, M_MACTEMP); - return (0); -} - -struct mac_label_journal * -mac_label_journal_find (struct label *l) -{ - struct mac_label_journal *mlj; - - TAILQ_FOREACH(mlj, &mac_label_journal_list, link) { - if (l == mlj->l) - return (mlj); - } - - return (NULL); -} - -int -mac_label_journal (struct label *l, int op, ...) -{ - struct mac_label_journal *mlj; - va_list ap; - - mlj = mac_label_journal_find(l); - if (mlj == NULL) { - printf("%s(): Label not in list!\n", __func__); - return (-1); - } - - if (op == MLJ_PORT_OP_UPDATE) { - va_start(ap, op); - mlj->kotype = va_arg(ap, int); - va_end(ap); - } - - mlj->ops |= op; - return (0); -} - -/* - * The assumption during replay is that the system is totally - * serialized and no additional tasks/ports will be created. - */ -void -mac_label_journal_replay (void) -{ - struct mac_label_journal *mlj; - - TAILQ_FOREACH(mlj, &mac_label_journal_list, link) { - switch (mlj->type) { - case MLJ_TYPE_PORT: - if (mlj->ops & MLJ_PORT_OP_INIT) - MAC_PERFORM(port_label_init, mlj->l); - if (mlj->ops & MLJ_PORT_OP_CREATE_K) - MAC_PERFORM(port_label_associate_kernel, mlj->l, 0); - if (mlj->ops & MLJ_PORT_OP_UPDATE) - MAC_PERFORM(port_label_update_kobject, mlj->l, - mlj->kotype); - break; - case MLJ_TYPE_TASK: - if (mlj->ops & MLJ_TASK_OP_INIT) - MAC_PERFORM(task_label_init, mlj->l); -#if 0 - /* Not enough context to replay. */ - if (mlj->ops & MLJ_TASK_OP_CREATE_K) - ; -#endif - break; - default: - break; - } - } - - /* Free list */ - while (!TAILQ_EMPTY(&mac_label_journal_list)) { - mlj = TAILQ_FIRST(&mac_label_journal_list); - TAILQ_REMOVE(&mac_label_journal_list, mlj, link); - FREE(mlj, M_MACTEMP); - } - return; -} - static __inline void mac_policy_grab_exclusive(void) { @@ -420,14 +296,6 @@ mac_policy_grab_exclusive(void) } } -static __inline void -mac_policy_assert_exclusive(void) -{ - lck_mtx_assert(mac_policy_mtx, LCK_MTX_ASSERT_OWNED); - KASSERT(mac_policy_busy == 0, - ("mac_policy_assert_exclusive(): not exclusive")); -} - static __inline void mac_policy_release_exclusive(void) { @@ -492,12 +360,16 @@ mac_policy_init(void) mac_policy_list.freehint = 0; mac_policy_list.chunks = 1; +#if CONFIG_EMBEDDED + mac_policy_list.entries = mac_policy_static_entries; +#else mac_policy_list.entries = kalloc(sizeof(struct mac_policy_list_element) * MAC_POLICY_LIST_CHUNKSIZE); +#endif + bzero(mac_policy_list.entries, sizeof(struct mac_policy_list_element) * MAC_POLICY_LIST_CHUNKSIZE); LIST_INIT(&mac_label_element_list); LIST_INIT(&mac_static_label_element_list); - TAILQ_INIT(&mac_label_journal_list); mac_lck_grp_attr = lck_grp_attr_alloc_init(); lck_grp_attr_setstat(mac_lck_grp_attr); @@ -512,6 +384,13 @@ mac_policy_init(void) mac_labelzone_init(); } +/* Function pointer set up for loading security extensions. + * It is set to an actual function after OSlibkernInit() + * has been called, and is set back to 0 by OSKextRemoveKextBootstrap() + * after bsd_init(). + */ +void (*load_security_extensions_function)(void) = 0; + /* * Init after early Mach startup, but before BSD */ @@ -526,11 +405,10 @@ mac_policy_initmach(void) * kernel startup. */ - load_security_extensions(); + if (load_security_extensions_function) { + load_security_extensions_function(); + } mac_late = 1; -#if CONFIG_MACF_MACH - mac_label_journal_replay(); -#endif } /* @@ -542,7 +420,7 @@ mac_policy_initbsd(void) struct mac_policy_conf *mpc; u_int i; -#if AUDIT +#if CONFIG_AUDIT mac_audit_data_zone = zinit(MAC_AUDIT_DATA_LIMIT, AQ_HIWATER * MAC_AUDIT_DATA_LIMIT, 8192, "mac_audit_data_zone"); @@ -719,26 +597,6 @@ mac_policy_removefrom_labellist(mac_policy_handle_t handle) static void mac_policy_updateflags(void) { -#if !defined(CONFIG_MACF_ALWAYS_LABEL_MBUF) && 0 /* port to new list style */ - - struct mac_policy_conf *tmpc; - int labelmbufs; - - mac_policy_assert_exclusive(); - - labelmbufs = 0; - - /* XXX - convert to new list structure */ - LIST_FOREACH(tmpc, &mac_static_policy_list, mpc_list) { - if (tmpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_LABELMBUFS) - labelmbufs++; - } - LIST_FOREACH(tmpc, &mac_policy_list, mpc_list) { - if (tmpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_LABELMBUFS) - labelmbufs++; - } - mac_labelmbufs = (labelmbufs != 0); -#endif } static __inline void @@ -783,7 +641,9 @@ int mac_policy_register(struct mac_policy_conf *mpc, mac_policy_handle_t *handlep, void *xd) { +#if !CONFIG_EMBEDDED struct mac_policy_list_element *tmac_policy_list_element; +#endif int error, slot, static_entry = 0; u_int i; @@ -815,6 +675,7 @@ mac_policy_register(struct mac_policy_conf *mpc, mac_policy_handle_t *handlep, } if (mac_policy_list.numloaded >= mac_policy_list.max) { +#if !CONFIG_EMBEDDED /* allocate new policy list array, zero new chunk */ tmac_policy_list_element = kalloc((sizeof(struct mac_policy_list_element) * @@ -838,6 +699,10 @@ mac_policy_register(struct mac_policy_conf *mpc, mac_policy_handle_t *handlep, /* Update maximums, etc */ mac_policy_list.max += MAC_POLICY_LIST_CHUNKSIZE; mac_policy_list.chunks++; +#else + printf("out of space in mac_policy_list.\n"); + return (ENOMEM); +#endif /* CONFIG_EMBEDDED */ } /* Check for policy with same name already loaded */ @@ -1062,26 +927,6 @@ mac_label_destroy(struct label *label) /* implicit: label->l_flags &= ~MAC_FLAG_INITIALIZED; */ } -int -mac_port_check_service (struct label *subj, struct label *obj, - const char *s, const char *p) -{ - int error; - - MAC_CHECK(port_check_service, subj, obj, s, p); - return (error); -} - -int -mac_port_label_compute(struct label *subj, struct label *obj, - const char *s, struct label *out) -{ - int error; - - MAC_CHECK(port_label_compute, subj, obj, s, out); - return error; -} - int mac_check_structmac_consistent(struct user_mac *mac) { @@ -1133,8 +978,8 @@ element_loop: mpc = mac_policy_list.entries[mll->mll_handle].mpc; if (mpc == NULL) continue; - mpo_externalize = *(typeof(mpo_externalize) *) - ((char *)mpc->mpc_ops + mpo_externalize_off); + mpo_externalize = *(const typeof(mpo_externalize) *) + ((const char *)mpc->mpc_ops + mpo_externalize_off); if (mpo_externalize == NULL) continue; error = sbuf_printf(sb, "%s/", name); @@ -1181,17 +1026,43 @@ done: /* * Get the external forms of labels from all policies, for all label * namespaces contained in a list. + * + * XXX This may be leaking an sbuf. */ int mac_externalize(size_t mpo_externalize_off, struct label *label, const char *elementlist, char *outbuf, size_t outbuflen) { char *element; + char *scratch_base; + char *scratch; struct sbuf sb; int error = 0, len; - sbuf_new(&sb, outbuf, outbuflen, SBUF_FIXEDLEN); - while ((element = strsep(&elementlist, ",")) != NULL) { + /* allocate a scratch buffer the size of the string */ + MALLOC(scratch_base, char *, strlen(elementlist)+1, M_MACTEMP, M_WAITOK); + if (scratch_base == NULL) { + error = ENOMEM; + goto out; + } + + /* copy the elementlist to the scratch buffer */ + strlcpy(scratch_base, elementlist, strlen(elementlist)+1); + + /* + * set up a temporary pointer that can be used to iterate the + * scratch buffer without losing the allocation address + */ + scratch = scratch_base; + + /* get an sbuf */ + if (sbuf_new(&sb, outbuf, outbuflen, SBUF_FIXEDLEN) == NULL) { + /* could not allocate interior buffer */ + error = ENOMEM; + goto out; + } + /* iterate the scratch buffer; NOTE: buffer contents modified! */ + while ((element = strsep(&scratch, ",")) != NULL) { error = mac_label_externalize(mpo_externalize_off, label, element, &sb); if (error) @@ -1200,6 +1071,11 @@ mac_externalize(size_t mpo_externalize_off, struct label *label, if ((len = sbuf_len(&sb)) > 0) sbuf_setpos(&sb, len - 1); /* trim trailing comma */ sbuf_finish(&sb); + +out: + if (scratch_base != NULL) + FREE(scratch_base, M_MACTEMP); + return (error); } @@ -1231,8 +1107,8 @@ element_loop: mpc = mac_policy_list.entries[mll->mll_handle].mpc; if (mpc == NULL) continue; - mpo_internalize = *(typeof(mpo_internalize) *) - ((char *)mpc->mpc_ops + mpo_internalize_off); + mpo_internalize = *(const typeof(mpo_internalize) *) + ((const char *)mpc->mpc_ops + mpo_internalize_off); if (mpo_internalize == NULL) continue; error = mpo_internalize(label, element_name, @@ -1279,7 +1155,7 @@ mac_internalize(size_t mpo_internalize_off, struct label *label, /* system calls */ int -__mac_get_pid(struct proc *p, struct __mac_get_pid_args *uap, register_t *ret __unused) +__mac_get_pid(struct proc *p, struct __mac_get_pid_args *uap, int *ret __unused) { char *elements, *buffer; struct user_mac mac; @@ -1290,12 +1166,15 @@ __mac_get_pid(struct proc *p, struct __mac_get_pid_args *uap, register_t *ret __ AUDIT_ARG(pid, uap->pid); if (IS_64BIT_PROCESS(p)) { - error = copyin(uap->mac_p, &mac, sizeof(mac)); + struct user64_mac mac64; + error = copyin(uap->mac_p, &mac64, sizeof(mac64)); + mac.m_buflen = mac64.m_buflen; + mac.m_string = mac64.m_string; } else { - struct mac mac32; + struct user32_mac mac32; error = copyin(uap->mac_p, &mac32, sizeof(mac32)); mac.m_buflen = mac32.m_buflen; - mac.m_string = CAST_USER_ADDR_T(mac32.m_string); + mac.m_string = mac32.m_string; } if (error) return (error); @@ -1332,7 +1211,7 @@ __mac_get_pid(struct proc *p, struct __mac_get_pid_args *uap, register_t *ret __ } int -__mac_get_proc(proc_t p, struct __mac_get_proc_args *uap, register_t *ret __unused) +__mac_get_proc(proc_t p, struct __mac_get_proc_args *uap, int *ret __unused) { char *elements, *buffer; struct user_mac mac; @@ -1341,12 +1220,15 @@ __mac_get_proc(proc_t p, struct __mac_get_proc_args *uap, register_t *ret __unus size_t ulen; if (IS_64BIT_PROCESS(p)) { - error = copyin(uap->mac_p, &mac, sizeof(mac)); + struct user64_mac mac64; + error = copyin(uap->mac_p, &mac64, sizeof(mac64)); + mac.m_buflen = mac64.m_buflen; + mac.m_string = mac64.m_string; } else { - struct mac mac32; + struct user32_mac mac32; error = copyin(uap->mac_p, &mac32, sizeof(mac32)); mac.m_buflen = mac32.m_buflen; - mac.m_string = CAST_USER_ADDR_T(mac32.m_string); + mac.m_string = mac32.m_string; } if (error) return (error); @@ -1377,14 +1259,9 @@ __mac_get_proc(proc_t p, struct __mac_get_proc_args *uap, register_t *ret __unus return (error); } -/* - * MPSAFE - */ - int -__mac_set_proc(proc_t p, struct __mac_set_proc_args *uap, register_t *ret __unused) +__mac_set_proc(proc_t p, struct __mac_set_proc_args *uap, int *ret __unused) { - kauth_cred_t newcred, oldcred; struct label *intlabel; struct user_mac mac; char *buffer; @@ -1392,12 +1269,15 @@ __mac_set_proc(proc_t p, struct __mac_set_proc_args *uap, register_t *ret __unus size_t ulen; if (IS_64BIT_PROCESS(p)) { - error = copyin(uap->mac_p, &mac, sizeof(mac)); + struct user64_mac mac64; + error = copyin(uap->mac_p, &mac64, sizeof(mac64)); + mac.m_buflen = mac64.m_buflen; + mac.m_string = mac64.m_string; } else { - struct mac mac32; + struct user32_mac mac32; error = copyin(uap->mac_p, &mac32, sizeof(mac32)); mac.m_buflen = mac32.m_buflen; - mac.m_string = CAST_USER_ADDR_T(mac32.m_string); + mac.m_string = mac32.m_string; } if (error) return (error); @@ -1429,209 +1309,13 @@ __mac_set_proc(proc_t p, struct __mac_set_proc_args *uap, register_t *ret __unus if (error) goto out; - newcred = kauth_cred_proc_ref(p); - mac_task_label_update_cred(newcred, p->task); - -#if 0 - if (mac_vm_enforce) { - mutex_lock(Giant); /* XXX FUNNEL? */ - mac_cred_mmapped_drop_perms(p, newcred); - mutex_unlock(Giant); /* XXX FUNNEL? */ - } -#endif - - kauth_cred_unref(&newcred); out: mac_cred_label_free(intlabel); return (error); } -#if CONFIG_LCTX -int -__mac_get_lcid(proc_t p, struct __mac_get_lcid_args *uap, register_t *ret __unused) -{ - char *elements, *buffer; - struct user_mac mac; - struct lctx *l; - int error; - size_t ulen; - - AUDIT_ARG(value, uap->lcid); - if (IS_64BIT_PROCESS(p)) { - error = copyin(uap->mac_p, &mac, sizeof(mac)); - } else { - struct mac mac32; - error = copyin(uap->mac_p, &mac32, sizeof(mac32)); - mac.m_buflen = mac32.m_buflen; - mac.m_string = CAST_USER_ADDR_T(mac32.m_string); - } - - if (error) - return (error); - - error = mac_check_structmac_consistent(&mac); - if (error) - return (error); - - l = lcfind(uap->lcid); - if (l == NULL) - return (ESRCH); - - MALLOC(elements, char *, mac.m_buflen, M_MACTEMP, M_WAITOK); - error = copyinstr(mac.m_string, elements, mac.m_buflen, &ulen); - if (error) { - LCTX_UNLOCK(l); - FREE(elements, M_MACTEMP); - return (error); - } - AUDIT_ARG(mac_string, elements); - MALLOC(buffer, char *, mac.m_buflen, M_MACTEMP, M_WAITOK); - error = mac_lctx_label_externalize(l->lc_label, elements, - buffer, mac.m_buflen); - if (error == 0) - error = copyout(buffer, mac.m_string, strlen(buffer)+1); - - LCTX_UNLOCK(l); - FREE(buffer, M_MACTEMP); - FREE(elements, M_MACTEMP); - return (error); -} - int -__mac_get_lctx(proc_t p, struct __mac_get_lctx_args *uap, register_t *ret __unused) -{ - char *elements, *buffer; - struct user_mac mac; - int error; - size_t ulen; - - if (IS_64BIT_PROCESS(p)) { - error = copyin(uap->mac_p, &mac, sizeof(mac)); - } else { - struct mac mac32; - error = copyin(uap->mac_p, &mac32, sizeof(mac32)); - mac.m_buflen = mac32.m_buflen; - mac.m_string = CAST_USER_ADDR_T(mac32.m_string); - } - - if (error) - return (error); - - error = mac_check_structmac_consistent(&mac); - if (error) - return (error); - - MALLOC(elements, char *, mac.m_buflen, M_MACTEMP, M_WAITOK); - error = copyinstr(mac.m_string, elements, mac.m_buflen, &ulen); - if (error) { - FREE(elements, M_MACTEMP); - return (error); - } - AUDIT_ARG(mac_string, elements); - MALLOC(buffer, char *, mac.m_buflen, M_MACTEMP, M_WAITOK); - - proc_lock(p); - if (p->p_lctx == NULL) { - proc_unlock(p); - error = ENOENT; - goto out; - } - - error = mac_lctx_label_externalize(p->p_lctx->lc_label, - elements, buffer, mac.m_buflen); - proc_unlock(p); - if (error == 0) - error = copyout(buffer, mac.m_string, strlen(buffer)+1); - -out: - FREE(buffer, M_MACTEMP); - FREE(elements, M_MACTEMP); - return (error); -} - -int -__mac_set_lctx(proc_t p, struct __mac_set_lctx_args *uap, register_t *ret __unused) -{ - struct user_mac mac; - struct label *intlabel; - char *buffer; - int error; - size_t ulen; - - if (IS_64BIT_PROCESS(p)) { - error = copyin(uap->mac_p, &mac, sizeof(mac)); - } else { - struct mac mac32; - error = copyin(uap->mac_p, &mac32, sizeof(mac32)); - mac.m_buflen = mac32.m_buflen; - mac.m_string = CAST_USER_ADDR_T(mac32.m_string); - } - if (error) - return (error); - - error = mac_check_structmac_consistent(&mac); - if (error) - return (error); - - MALLOC(buffer, char *, mac.m_buflen, M_MACTEMP, M_WAITOK); - error = copyinstr(mac.m_string, buffer, mac.m_buflen, &ulen); - if (error) { - FREE(buffer, M_MACTEMP); - return (error); - } - AUDIT_ARG(mac_string, buffer); - - intlabel = mac_lctx_label_alloc(); - error = mac_lctx_label_internalize(intlabel, buffer); - FREE(buffer, M_MACTEMP); - if (error) - goto out; - - proc_lock(p); - if (p->p_lctx == NULL) { - proc_unlock(p); - error = ENOENT; - goto out; - } - - error = mac_lctx_check_label_update(p->p_lctx, intlabel); - if (error) { - proc_unlock(p); - goto out; - } - mac_lctx_label_update(p->p_lctx, intlabel); - proc_unlock(p); -out: - mac_lctx_label_free(intlabel); - return (error); -} - -#else /* LCTX */ - -int -__mac_get_lcid(proc_t p __unused, struct __mac_get_lcid_args *uap __unused, register_t *ret __unused) -{ - - return (ENOSYS); -} - -int -__mac_get_lctx(proc_t p __unused, struct __mac_get_lctx_args *uap __unused, register_t *ret __unused) -{ - - return (ENOSYS); -} - -int -__mac_set_lctx(proc_t p __unused, struct __mac_set_lctx_args *uap __unused, register_t *ret __unused) -{ - - return (ENOSYS); -} -#endif /* !LCTX */ - -int -__mac_get_fd(proc_t p, struct __mac_get_fd_args *uap, register_t *ret __unused) +__mac_get_fd(proc_t p, struct __mac_get_fd_args *uap, int *ret __unused) { struct fileproc *fp; struct vnode *vp; @@ -1648,12 +1332,15 @@ __mac_get_fd(proc_t p, struct __mac_get_fd_args *uap, register_t *ret __unused) AUDIT_ARG(fd, uap->fd); if (IS_64BIT_PROCESS(p)) { - error = copyin(uap->mac_p, &mac, sizeof(mac)); + struct user64_mac mac64; + error = copyin(uap->mac_p, &mac64, sizeof(mac64)); + mac.m_buflen = mac64.m_buflen; + mac.m_string = mac64.m_string; } else { - struct mac mac32; + struct user32_mac mac32; error = copyin(uap->mac_p, &mac32, sizeof(mac32)); mac.m_buflen = mac32.m_buflen; - mac.m_string = CAST_USER_ADDR_T(mac32.m_string); + mac.m_string = mac32.m_string; } if (error) @@ -1689,12 +1376,14 @@ __mac_get_fd(proc_t p, struct __mac_get_fd_args *uap, register_t *ret __unused) return (error); } - switch (fp->f_fglob->fg_type) { + switch (FILEGLOB_DTYPE(fp->f_fglob)) { case DTYPE_VNODE: - intlabel = mac_vnode_label_alloc(); + if (intlabel == NULL) { + error = ENOMEM; + break; + } vp = (struct vnode *)fp->f_fglob->fg_data; - error = vnode_getwithref(vp); if (error == 0) { mac_vnode_label_copy(vp->v_label, intlabel); @@ -1721,6 +1410,8 @@ __mac_get_fd(proc_t p, struct __mac_get_fd_args *uap, register_t *ret __unused) case DTYPE_PIPE: case DTYPE_KQUEUE: case DTYPE_FSEVENTS: + case DTYPE_ATALK: + case DTYPE_NETPOLICY: default: error = ENOSYS; // only sockets/vnodes so far break; @@ -1735,9 +1426,6 @@ __mac_get_fd(proc_t p, struct __mac_get_fd_args *uap, register_t *ret __unused) return (error); } -/* - * MPSAFE - */ static int mac_get_filelink(proc_t p, user_addr_t mac_p, user_addr_t path_p, int follow) { @@ -1751,12 +1439,15 @@ mac_get_filelink(proc_t p, user_addr_t mac_p, user_addr_t path_p, int follow) size_t ulen; if (IS_64BIT_PROCESS(p)) { - error = copyin(mac_p, &mac, sizeof(mac)); + struct user64_mac mac64; + error = copyin(mac_p, &mac64, sizeof(mac64)); + mac.m_buflen = mac64.m_buflen; + mac.m_string = mac64.m_string; } else { - struct mac mac32; + struct user32_mac mac32; error = copyin(mac_p, &mac32, sizeof(mac32)); mac.m_buflen = mac32.m_buflen; - mac.m_string = CAST_USER_ADDR_T(mac32.m_string); + mac.m_string = mac32.m_string; } if (error) @@ -1767,8 +1458,11 @@ mac_get_filelink(proc_t p, user_addr_t mac_p, user_addr_t path_p, int follow) return (error); MALLOC(elements, char *, mac.m_buflen, M_MACTEMP, M_WAITOK); + MALLOC(buffer, char *, mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); + error = copyinstr(mac.m_string, elements, mac.m_buflen, &ulen); if (error) { + FREE(buffer, M_MACTEMP); FREE(elements, M_MACTEMP); return (error); } @@ -1776,11 +1470,12 @@ mac_get_filelink(proc_t p, user_addr_t mac_p, user_addr_t path_p, int follow) ctx = vfs_context_current(); - NDINIT(&nd, LOOKUP, + NDINIT(&nd, LOOKUP, OP_LOOKUP, LOCKLEAF | (follow ? FOLLOW : NOFOLLOW) | AUDITVNPATH1, UIO_USERSPACE, path_p, ctx); error = namei(&nd); if (error) { + FREE(buffer, M_MACTEMP); FREE(elements, M_MACTEMP); return (error); } @@ -1790,25 +1485,23 @@ mac_get_filelink(proc_t p, user_addr_t mac_p, user_addr_t path_p, int follow) intlabel = mac_vnode_label_alloc(); mac_vnode_label_copy(vp->v_label, intlabel); - - MALLOC(buffer, char *, mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); error = mac_vnode_label_externalize(intlabel, elements, buffer, - mac.m_buflen, M_WAITOK); - FREE(elements, M_MACTEMP); - + mac.m_buflen, M_WAITOK); + mac_vnode_label_free(intlabel); if (error == 0) error = copyout(buffer, mac.m_string, strlen(buffer) + 1); - FREE(buffer, M_MACTEMP); vnode_put(vp); - mac_vnode_label_free(intlabel); + + FREE(buffer, M_MACTEMP); + FREE(elements, M_MACTEMP); return (error); } int __mac_get_file(proc_t p, struct __mac_get_file_args *uap, - register_t *ret __unused) + int *ret __unused) { return (mac_get_filelink(p, uap->mac_p, uap->path_p, 1)); @@ -1816,14 +1509,14 @@ __mac_get_file(proc_t p, struct __mac_get_file_args *uap, int __mac_get_link(proc_t p, struct __mac_get_link_args *uap, - register_t *ret __unused) + int *ret __unused) { return (mac_get_filelink(p, uap->mac_p, uap->path_p, 0)); } int -__mac_set_fd(proc_t p, struct __mac_set_fd_args *uap, register_t *ret __unused) +__mac_set_fd(proc_t p, struct __mac_set_fd_args *uap, int *ret __unused) { struct fileproc *fp; @@ -1841,12 +1534,15 @@ __mac_set_fd(proc_t p, struct __mac_set_fd_args *uap, register_t *ret __unused) AUDIT_ARG(fd, uap->fd); if (IS_64BIT_PROCESS(p)) { - error = copyin(uap->mac_p, &mac, sizeof(mac)); + struct user64_mac mac64; + error = copyin(uap->mac_p, &mac64, sizeof(mac64)); + mac.m_buflen = mac64.m_buflen; + mac.m_string = mac64.m_string; } else { - struct mac mac32; + struct user32_mac mac32; error = copyin(uap->mac_p, &mac32, sizeof(mac32)); mac.m_buflen = mac32.m_buflen; - mac.m_string = CAST_USER_ADDR_T(mac32.m_string); + mac.m_string = mac32.m_string; } if (error) return (error); @@ -1877,9 +1573,14 @@ __mac_set_fd(proc_t p, struct __mac_set_fd_args *uap, register_t *ret __unused) return (error); } - switch (fp->f_fglob->fg_type) { + switch (FILEGLOB_DTYPE(fp->f_fglob)) { case DTYPE_VNODE: + if (mac_label_vnodes == 0) { + error = ENOSYS; + break; + } + intlabel = mac_vnode_label_alloc(); error = mac_vnode_label_internalize(intlabel, buffer); @@ -1917,6 +1618,8 @@ __mac_set_fd(proc_t p, struct __mac_set_fd_args *uap, register_t *ret __unused) case DTYPE_PIPE: case DTYPE_KQUEUE: case DTYPE_FSEVENTS: + case DTYPE_ATALK: + case DTYPE_NETPOLICY: default: error = ENOSYS; // only sockets/vnodes so far break; @@ -1927,14 +1630,11 @@ __mac_set_fd(proc_t p, struct __mac_set_fd_args *uap, register_t *ret __unused) return (error); } -/* - * MPSAFE - */ static int mac_set_filelink(proc_t p, user_addr_t mac_p, user_addr_t path_p, int follow) { - register struct vnode *vp; + struct vnode *vp; struct vfs_context *ctx = vfs_context_current(); struct label *intlabel; struct nameidata nd; @@ -1943,13 +1643,19 @@ mac_set_filelink(proc_t p, user_addr_t mac_p, user_addr_t path_p, int error; size_t ulen; + if (mac_label_vnodes == 0) + return ENOSYS; + if (IS_64BIT_PROCESS(p)) { - error = copyin(mac_p, &mac, sizeof(mac)); + struct user64_mac mac64; + error = copyin(mac_p, &mac64, sizeof(mac64)); + mac.m_buflen = mac64.m_buflen; + mac.m_string = mac64.m_string; } else { - struct mac mac32; + struct user32_mac mac32; error = copyin(mac_p, &mac32, sizeof(mac32)); mac.m_buflen = mac32.m_buflen; - mac.m_string = CAST_USER_ADDR_T(mac32.m_string); + mac.m_string = mac32.m_string; } if (error) return (error); @@ -1976,7 +1682,7 @@ mac_set_filelink(proc_t p, user_addr_t mac_p, user_addr_t path_p, return (error); } - NDINIT(&nd, LOOKUP, + NDINIT(&nd, LOOKUP, OP_LOOKUP, LOCKLEAF | (follow ? FOLLOW : NOFOLLOW) | AUDITVNPATH1, UIO_USERSPACE, path_p, ctx); error = namei(&nd); @@ -1997,7 +1703,7 @@ mac_set_filelink(proc_t p, user_addr_t mac_p, user_addr_t path_p, int __mac_set_file(proc_t p, struct __mac_set_file_args *uap, - register_t *ret __unused) + int *ret __unused) { return (mac_set_filelink(p, uap->mac_p, uap->path_p, 1)); @@ -2005,18 +1711,29 @@ __mac_set_file(proc_t p, struct __mac_set_file_args *uap, int __mac_set_link(proc_t p, struct __mac_set_link_args *uap, - register_t *ret __unused) + int *ret __unused) { return (mac_set_filelink(p, uap->mac_p, uap->path_p, 0)); } /* - * MPSAFE + * __mac_syscall: Perform a MAC policy system call + * + * Parameters: p Process calling this routine + * uap User argument descriptor (see below) + * retv (Unused) + * + * Indirect: uap->policy Name of target MAC policy + * uap->call MAC policy-specific system call to perform + * uap->arg MAC policy-specific system call arguments + * + * Returns: 0 Success + * !0 Not success + * */ - int -__mac_syscall(proc_t p, struct __mac_syscall_args *uap, register_t *retv __unused) +__mac_syscall(proc_t p, struct __mac_syscall_args *uap, int *retv __unused) { struct mac_policy_conf *mpc; char target[MAC_MAX_POLICY_NAME]; @@ -2027,7 +1744,7 @@ __mac_syscall(proc_t p, struct __mac_syscall_args *uap, register_t *retv __unuse error = copyinstr(uap->policy, target, sizeof(target), &ulen); if (error) return (error); - AUDIT_ARG(value, uap->call); + AUDIT_ARG(value32, uap->call); AUDIT_ARG(mac_string, target); error = ENOPOLICY; @@ -2074,12 +1791,15 @@ mac_mount_label_get(struct mount *mp, user_addr_t mac_p) size_t ulen; if (IS_64BIT_PROCESS(current_proc())) { - error = copyin(mac_p, &mac, sizeof(mac)); + struct user64_mac mac64; + error = copyin(mac_p, &mac64, sizeof(mac64)); + mac.m_buflen = mac64.m_buflen; + mac.m_string = mac64.m_string; } else { - struct mac mac32; + struct user32_mac mac32; error = copyin(mac_p, &mac32, sizeof(mac32)); mac.m_buflen = mac32.m_buflen; - mac.m_string = CAST_USER_ADDR_T(mac32.m_string); + mac.m_string = mac32.m_string; } if (error) return (error); @@ -2109,29 +1829,102 @@ mac_mount_label_get(struct mount *mp, user_addr_t mac_p) return (error); } +/* + * __mac_get_mount: Get mount point label information for a given pathname + * + * Parameters: p (ignored) + * uap User argument descriptor (see below) + * ret (ignored) + * + * Indirect: uap->path Pathname + * uap->mac_p MAC info + * + * Returns: 0 Success + * !0 Not success + */ int __mac_get_mount(proc_t p __unused, struct __mac_get_mount_args *uap, - register_t *ret __unused) + int *ret __unused) { struct nameidata nd; struct vfs_context *ctx = vfs_context_current(); struct mount *mp; int error; - NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNPATH1, + NDINIT(&nd, LOOKUP, OP_LOOKUP, FOLLOW | AUDITVNPATH1, UIO_USERSPACE, uap->path, ctx); error = namei(&nd); if (error) { return (error); } mp = nd.ni_vp->v_mount; + vnode_put(nd.ni_vp); nameidone(&nd); return mac_mount_label_get(mp, uap->mac_p); } +/* + * mac_schedule_userret() + * + * Schedule a callback to the mpo_thread_userret hook. The mpo_thread_userret + * hook is called just before the thread exit from the kernel in ast_taken(). + * + * Returns: 0 Success + * !0 Not successful + */ +int +mac_schedule_userret(void) +{ + + act_set_astmacf(current_thread()); + return (0); +} + +/* + * mac_do_machexc() + * + * Do a Mach exception. This should only be done in the mpo_thread_userret + * callback. + * + * params: code exception code + * subcode exception subcode + * flags flags: + * MAC_DOEXCF_TRACED Only do exception if being + * ptrace()'ed. + * + * + * Returns: 0 Success + * !0 Not successful + */ +int +mac_do_machexc(int64_t code, int64_t subcode, uint32_t flags) +{ + mach_exception_data_type_t codes[EXCEPTION_CODE_MAX]; + proc_t p = current_proc(); + + /* Only allow execption codes in MACF's reserved range. */ + if ((code < EXC_MACF_MIN) || (code > EXC_MACF_MAX)) + return (1); + + if (flags & MAC_DOEXCF_TRACED && + !(p->p_lflag & P_LTRACED && (p->p_lflag & P_LPPWAIT) == 0)) + return (0); + + + /* Send the Mach exception */ + codes[0] = (mach_exception_data_type_t)code; + codes[1] = (mach_exception_data_type_t)subcode; + + return (bsd_exception(EXC_SOFTWARE, codes, 2) != KERN_SUCCESS); +} + #else /* MAC */ +void (*load_security_extensions_function)(void) = 0; + +struct sysctl_oid_list sysctl__security_mac_children; + int mac_policy_register(struct mac_policy_conf *mpc __unused, mac_policy_handle_t *handlep __unused, void *xd __unused) @@ -2154,12 +1947,6 @@ mac_audit_text(char *text __unused, mac_policy_handle_t handle __unused) return (0); } -int -mac_mount_label_get(struct mount *mp __unused, user_addr_t mac_p __unused) -{ - return (ENOSYS); -} - int mac_vnop_setxattr(struct vnode *vp __unused, const char *name __unused, char *buf __unused, size_t len __unused) { @@ -2183,101 +1970,60 @@ mac_vnop_removexattr(struct vnode *vp __unused, const char *name __unused) } int -__mac_get_pid(proc_t p __unused, struct __mac_get_pid_args *uap __unused, register_t *ret __unused) -{ - - return (ENOSYS); -} - -int -__mac_get_proc(proc_t p __unused, struct __mac_get_proc_args *uap __unused, register_t *ret __unused) +mac_file_setxattr(struct fileglob *fg __unused, const char *name __unused, char *buf __unused, size_t len __unused) { - return (ENOSYS); -} - -int -__mac_set_proc(proc_t p __unused, struct __mac_set_proc_args *uap __unused, register_t *ret __unused) -{ - - return (ENOSYS); -} - -int -__mac_get_file(proc_t p __unused, struct __mac_get_file_args *uap __unused, register_t *ret __unused) -{ - - return (ENOSYS); + return (ENOENT); } int -__mac_get_link(proc_t p __unused, struct __mac_get_link_args *uap __unused, register_t *ret __unused) +mac_file_getxattr(struct fileglob *fg __unused, const char *name __unused, + char *buf __unused, size_t len __unused, size_t *attrlen __unused) { - return (ENOSYS); + return (ENOENT); } int -__mac_set_file(proc_t p __unused, struct __mac_set_file_args *uap __unused, register_t *ret __unused) +mac_file_removexattr(struct fileglob *fg __unused, const char *name __unused) { - return (ENOSYS); + return (ENOENT); } -int -__mac_set_link(proc_t p __unused, struct __mac_set_link_args *uap __unused, register_t *ret __unused) +intptr_t mac_label_get(struct label *l __unused, int slot __unused) { - - return (ENOSYS); + return 0; } -int -__mac_get_fd(proc_t p __unused, struct __mac_get_fd_args *uap __unused, register_t *ret __unused) +void mac_label_set(struct label *l __unused, int slot __unused, intptr_t v __unused) { - - return (ENOSYS); + return; } -int -__mac_set_fd(proc_t p __unused, struct __mac_set_fd_args *uap __unused, register_t *ret __unused) +int mac_iokit_check_hid_control(kauth_cred_t cred __unused); +int mac_iokit_check_hid_control(kauth_cred_t cred __unused) { - - return (ENOSYS); + return 0; } -int -__mac_syscall(proc_t p __unused, struct __mac_syscall_args *uap __unused, register_t *ret __unused) -{ - return (ENOSYS); -} - -int -__mac_get_lcid(proc_t p __unused, struct __mac_get_lcid_args *uap __unused, register_t *ret __unused) +int mac_iokit_check_nvram_delete(kauth_cred_t cred __unused, const char *name __unused); +int mac_iokit_check_nvram_delete(kauth_cred_t cred __unused, const char *name __unused) { - - return (ENOSYS); + return 0; } -int -__mac_get_lctx(proc_t p __unused, struct __mac_get_lctx_args *uap __unused, register_t *ret __unused) +int mac_iokit_check_nvram_get(kauth_cred_t cred __unused, const char *name __unused); +int mac_iokit_check_nvram_get(kauth_cred_t cred __unused, const char *name __unused) { - - return (ENOSYS); + return 0; } -int -__mac_set_lctx(proc_t p __unused, struct __mac_set_lctx_args *uap __unused, register_t *ret __unused) +int mac_iokit_check_nvram_set(kauth_cred_t cred __unused, const char *name __unused, io_object_t value __unused); +int mac_iokit_check_nvram_set(kauth_cred_t cred __unused, const char *name __unused, io_object_t value __unused) { - - return (ENOSYS); + return 0; } -int -__mac_get_mount(proc_t p __unused, - struct __mac_get_mount_args *uap __unused, register_t *ret __unused) -{ - - return (ENOSYS); -} #endif /* !MAC */