Index: head/sys/kern/kern_mac.c =================================================================== --- head/sys/kern/kern_mac.c (revision 125292) +++ head/sys/kern/kern_mac.c (revision 125293) @@ -1,1209 +1,1209 @@ /*- * Copyright (c) 1999, 2000, 2001, 2002 Robert N. M. Watson * Copyright (c) 2001 Ilmar S. Habibulin * Copyright (c) 2001, 2002, 2003 Networks Associates Technology, Inc. * All rights reserved. * * This software was developed by Robert Watson and Ilmar Habibulin for the * TrustedBSD Project. * * This software was developed for the FreeBSD Project in part by Network * Associates Laboratories, the Security Research Division of Network * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), * as part of the DARPA CHATS research program. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /*- * Framework for extensible kernel access control. This file contains * Kernel and userland interface to the framework, policy registration * and composition. Per-object interfaces, controls, and labeling may be * found in src/sys/mac/. Sample policies may be found in src/sys/mac*. */ #include __FBSDID("$FreeBSD$"); #include "opt_mac.h" #include "opt_devfs.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef MAC /* * Declare that the kernel provides MAC support, version 1. This permits * modules to refuse to be loaded if the necessary support isn't present, * even if it's pre-boot. */ MODULE_VERSION(kernel_mac_support, 1); SYSCTL_NODE(_security, OID_AUTO, mac, CTLFLAG_RW, 0, "TrustedBSD MAC policy controls"); #if MAC_MAX_SLOTS > 32 #error "MAC_MAX_SLOTS too large" #endif 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, &mac_max_slots, 0, ""); /* * Has the kernel started generating labeled objects yet? All read/write * access to this variable is serialized during the boot process. Following * the end of serialization, we don't update this flag; no locking. */ int mac_late = 0; /* * Flag to indicate whether or not we should allocate label storage for * new mbufs. Since most dynamic policies we currently work with don't * rely on mbuf 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 mbuf labels, it must * be able to deal with a NULL label being returned on any mbufs 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. Note: currently no locking. Will this be a problem? */ #ifndef MAC_ALWAYS_LABEL_MBUF int mac_labelmbufs = 0; #endif #ifdef MAC_DEBUG SYSCTL_NODE(_security_mac, OID_AUTO, debug, CTLFLAG_RW, 0, "TrustedBSD MAC debug info"); SYSCTL_NODE(_security_mac_debug, OID_AUTO, counters, CTLFLAG_RW, 0, "TrustedBSD MAC object counters"); static unsigned int nmactemp; SYSCTL_UINT(_security_mac_debug_counters, OID_AUTO, temp, CTLFLAG_RD, &nmactemp, 0, "number of temporary labels in use"); #endif static int mac_policy_register(struct mac_policy_conf *mpc); static int mac_policy_unregister(struct mac_policy_conf *mpc); MALLOC_DEFINE(M_MACTEMP, "mactemp", "MAC temporary label storage"); /* * mac_static_policy_list holds a list of policy modules that are not * loaded while the system is "live", and cannot be unloaded. These * policies can be invoked without holding the busy count. * * mac_policy_list stores the list of dynamic policies. A busy count is * maintained for the list, stored in mac_policy_busy. The busy count * is protected by mac_policy_mtx; the list may be modified only * while the busy count is 0, requiring that the lock be held to * prevent new references to the list from being acquired. For almost * all operations, incrementing the busy count is sufficient to * guarantee consistency, as the list cannot be modified while the * busy count is elevated. For a few special operations involving a * change to the list of active policies, the mtx itself must be held. * A condition variable, mac_policy_cv, is used to signal potential * exclusive consumers that they should try to acquire the lock if a * first attempt at exclusive access fails. */ static struct mtx mac_policy_mtx; static struct cv mac_policy_cv; static int mac_policy_count; struct mac_policy_list_head mac_policy_list; struct mac_policy_list_head mac_static_policy_list; /* * We manually invoke WITNESS_WARN() to allow Witness to generate * warnings even if we don't end up ever triggering the wait at * run-time. The consumer of the exclusive interface must not hold * any locks (other than potentially Giant) since we may sleep for * long (potentially indefinite) periods of time waiting for the * framework to become quiescent so that a policy list change may * be made. */ void mac_policy_grab_exclusive(void) { WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, "mac_policy_grab_exclusive() at %s:%d", __FILE__, __LINE__); mtx_lock(&mac_policy_mtx); while (mac_policy_count != 0) cv_wait(&mac_policy_cv, &mac_policy_mtx); } void mac_policy_assert_exclusive(void) { mtx_assert(&mac_policy_mtx, MA_OWNED); KASSERT(mac_policy_count == 0, ("mac_policy_assert_exclusive(): not exclusive")); } void mac_policy_release_exclusive(void) { KASSERT(mac_policy_count == 0, ("mac_policy_release_exclusive(): not exclusive")); mtx_unlock(&mac_policy_mtx); cv_signal(&mac_policy_cv); } void mac_policy_list_busy(void) { mtx_lock(&mac_policy_mtx); mac_policy_count++; mtx_unlock(&mac_policy_mtx); } int mac_policy_list_conditional_busy(void) { int ret; mtx_lock(&mac_policy_mtx); if (!LIST_EMPTY(&mac_policy_list)) { mac_policy_count++; ret = 1; } else ret = 0; mtx_unlock(&mac_policy_mtx); return (ret); } void mac_policy_list_unbusy(void) { mtx_lock(&mac_policy_mtx); mac_policy_count--; KASSERT(mac_policy_count >= 0, ("MAC_POLICY_LIST_LOCK")); if (mac_policy_count == 0) cv_signal(&mac_policy_cv); mtx_unlock(&mac_policy_mtx); } /* * Initialize the MAC subsystem, including appropriate SMP locks. */ static void mac_init(void) { LIST_INIT(&mac_static_policy_list); LIST_INIT(&mac_policy_list); mac_labelzone_init(); mtx_init(&mac_policy_mtx, "mac_policy_mtx", NULL, MTX_DEF); cv_init(&mac_policy_cv, "mac_policy_cv"); } /* * For the purposes of modules that want to know if they were loaded * "early", set the mac_late flag once we've processed modules either * linked into the kernel, or loaded before the kernel startup. */ static void mac_late_init(void) { mac_late = 1; } /* * After the policy list has changed, walk the list to update any global * flags. Currently, we support only one flag, and it's conditionally * defined; as a result, the entire function is conditional. Eventually, * the #else case might also iterate across the policies. */ static void mac_policy_updateflags(void) { #ifndef MAC_ALWAYS_LABEL_MBUF struct mac_policy_conf *tmpc; int labelmbufs; mac_policy_assert_exclusive(); labelmbufs = 0; 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 } /* * Allow MAC policy modules to register during boot, etc. */ int mac_policy_modevent(module_t mod, int type, void *data) { struct mac_policy_conf *mpc; int error; error = 0; mpc = (struct mac_policy_conf *) data; switch (type) { case MOD_LOAD: if (mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_NOTLATE && mac_late) { printf("mac_policy_modevent: can't load %s policy " "after booting\n", mpc->mpc_name); error = EBUSY; break; } error = mac_policy_register(mpc); break; case MOD_UNLOAD: /* Don't unregister the module if it was never registered. */ if ((mpc->mpc_runtime_flags & MPC_RUNTIME_FLAG_REGISTERED) != 0) error = mac_policy_unregister(mpc); else error = 0; break; default: break; } return (error); } static int mac_policy_register(struct mac_policy_conf *mpc) { struct mac_policy_conf *tmpc; int error, slot, static_entry; error = 0; /* * We don't technically need exclusive access while !mac_late, * but hold it for assertion consistency. */ mac_policy_grab_exclusive(); /* * If the module can potentially be unloaded, or we're loading * late, we have to stick it in the non-static list and pay * an extra performance overhead. Otherwise, we can pay a * light locking cost and stick it in the static list. */ static_entry = (!mac_late && !(mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_UNLOADOK)); if (static_entry) { LIST_FOREACH(tmpc, &mac_static_policy_list, mpc_list) { if (strcmp(tmpc->mpc_name, mpc->mpc_name) == 0) { error = EEXIST; goto out; } } } else { LIST_FOREACH(tmpc, &mac_policy_list, mpc_list) { if (strcmp(tmpc->mpc_name, mpc->mpc_name) == 0) { error = EEXIST; goto out; } } } if (mpc->mpc_field_off != NULL) { slot = ffs(mac_slot_offsets_free); if (slot == 0) { error = ENOMEM; goto out; } slot--; mac_slot_offsets_free &= ~(1 << slot); *mpc->mpc_field_off = slot; } mpc->mpc_runtime_flags |= MPC_RUNTIME_FLAG_REGISTERED; /* * If we're loading a MAC module after the framework has * initialized, it has to go into the dynamic list. If * we're loading it before we've finished initializing, * it can go into the static list with weaker locker * requirements. */ if (static_entry) LIST_INSERT_HEAD(&mac_static_policy_list, mpc, mpc_list); else LIST_INSERT_HEAD(&mac_policy_list, mpc, mpc_list); /* Per-policy initialization. */ if (mpc->mpc_ops->mpo_init != NULL) (*(mpc->mpc_ops->mpo_init))(mpc); mac_policy_updateflags(); printf("Security policy loaded: %s (%s)\n", mpc->mpc_fullname, mpc->mpc_name); out: mac_policy_release_exclusive(); return (error); } static int mac_policy_unregister(struct mac_policy_conf *mpc) { /* * If we fail the load, we may get a request to unload. Check * to see if we did the run-time registration, and if not, * silently succeed. */ mac_policy_grab_exclusive(); if ((mpc->mpc_runtime_flags & MPC_RUNTIME_FLAG_REGISTERED) == 0) { mac_policy_release_exclusive(); return (0); } #if 0 /* * Don't allow unloading modules with private data. */ if (mpc->mpc_field_off != NULL) { MAC_POLICY_LIST_UNLOCK(); return (EBUSY); } #endif /* * Only allow the unload to proceed if the module is unloadable * by its own definition. */ if ((mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_UNLOADOK) == 0) { mac_policy_release_exclusive(); return (EBUSY); } if (mpc->mpc_ops->mpo_destroy != NULL) (*(mpc->mpc_ops->mpo_destroy))(mpc); LIST_REMOVE(mpc, mpc_list); mpc->mpc_runtime_flags &= ~MPC_RUNTIME_FLAG_REGISTERED; mac_policy_updateflags(); mac_policy_release_exclusive(); printf("Security policy unload: %s (%s)\n", mpc->mpc_fullname, mpc->mpc_name); return (0); } /* * Define an error value precedence, and given two arguments, selects the * value with the higher precedence. */ int mac_error_select(int error1, int error2) { /* Certain decision-making errors take top priority. */ if (error1 == EDEADLK || error2 == EDEADLK) return (EDEADLK); /* Invalid arguments should be reported where possible. */ if (error1 == EINVAL || error2 == EINVAL) return (EINVAL); /* Precedence goes to "visibility", with both process and file. */ if (error1 == ESRCH || error2 == ESRCH) return (ESRCH); if (error1 == ENOENT || error2 == ENOENT) return (ENOENT); /* Precedence goes to DAC/MAC protections. */ if (error1 == EACCES || error2 == EACCES) return (EACCES); /* Precedence goes to privilege. */ if (error1 == EPERM || error2 == EPERM) return (EPERM); /* Precedence goes to error over success; otherwise, arbitrary. */ if (error1 != 0) return (error1); return (error2); } void mac_init_label(struct label *label) { bzero(label, sizeof(*label)); label->l_flags = MAC_FLAG_INITIALIZED; } void mac_destroy_label(struct label *label) { KASSERT(label->l_flags & MAC_FLAG_INITIALIZED, ("destroying uninitialized label")); bzero(label, sizeof(*label)); /* implicit: label->l_flags &= ~MAC_FLAG_INITIALIZED; */ } int mac_check_structmac_consistent(struct mac *mac) { if (mac->m_buflen < 0 || mac->m_buflen > MAC_MAX_LABEL_BUF_LEN) return (EINVAL); return (0); } /* * MPSAFE */ int __mac_get_pid(struct thread *td, struct __mac_get_pid_args *uap) { char *elements, *buffer; struct mac mac; struct proc *tproc; struct ucred *tcred; int error; error = copyin(uap->mac_p, &mac, sizeof(mac)); if (error) return (error); error = mac_check_structmac_consistent(&mac); if (error) return (error); tproc = pfind(uap->pid); if (tproc == NULL) return (ESRCH); tcred = NULL; /* Satisfy gcc. */ error = p_cansee(td, tproc); if (error == 0) tcred = crhold(tproc->p_ucred); PROC_UNLOCK(tproc); if (error) return (error); elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL); if (error) { free(elements, M_MACTEMP); crfree(tcred); return (error); } buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); error = mac_externalize_cred_label(tcred->cr_label, elements, buffer, mac.m_buflen); if (error == 0) error = copyout(buffer, mac.m_string, strlen(buffer)+1); free(buffer, M_MACTEMP); free(elements, M_MACTEMP); crfree(tcred); return (error); } /* * MPSAFE */ int __mac_get_proc(struct thread *td, struct __mac_get_proc_args *uap) { char *elements, *buffer; struct mac mac; int error; error = copyin(uap->mac_p, &mac, sizeof(mac)); if (error) return (error); error = mac_check_structmac_consistent(&mac); if (error) return (error); elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL); if (error) { free(elements, M_MACTEMP); return (error); } buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); error = mac_externalize_cred_label(td->td_ucred->cr_label, elements, buffer, mac.m_buflen); if (error == 0) error = copyout(buffer, mac.m_string, strlen(buffer)+1); free(buffer, M_MACTEMP); free(elements, M_MACTEMP); return (error); } /* * MPSAFE */ int __mac_set_proc(struct thread *td, struct __mac_set_proc_args *uap) { struct ucred *newcred, *oldcred; struct label *intlabel; struct proc *p; struct mac mac; char *buffer; int error; error = copyin(uap->mac_p, &mac, sizeof(mac)); if (error) return (error); error = mac_check_structmac_consistent(&mac); if (error) return (error); buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL); if (error) { free(buffer, M_MACTEMP); return (error); } intlabel = mac_cred_label_alloc(); error = mac_internalize_cred_label(intlabel, buffer); free(buffer, M_MACTEMP); if (error) goto out; newcred = crget(); p = td->td_proc; PROC_LOCK(p); oldcred = p->p_ucred; error = mac_check_cred_relabel(oldcred, intlabel); if (error) { PROC_UNLOCK(p); crfree(newcred); goto out; } setsugid(p); crcopy(newcred, oldcred); mac_relabel_cred(newcred, intlabel); p->p_ucred = newcred; /* * Grab additional reference for use while revoking mmaps, prior * to releasing the proc lock and sharing the cred. */ crhold(newcred); PROC_UNLOCK(p); if (mac_enforce_vm) { mtx_lock(&Giant); mac_cred_mmapped_drop_perms(td, newcred); mtx_unlock(&Giant); } crfree(newcred); /* Free revocation reference. */ crfree(oldcred); out: mac_cred_label_free(intlabel); return (error); } /* * MPSAFE */ int __mac_get_fd(struct thread *td, struct __mac_get_fd_args *uap) { char *elements, *buffer; struct label *intlabel; struct file *fp; struct mac mac; struct vnode *vp; struct pipe *pipe; struct socket *so; short label_type; int error; error = copyin(uap->mac_p, &mac, sizeof(mac)); if (error) return (error); error = mac_check_structmac_consistent(&mac); if (error) return (error); elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL); if (error) { free(elements, M_MACTEMP); return (error); } buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); error = fget(td, uap->fd, &fp); if (error) goto out; label_type = fp->f_type; switch (fp->f_type) { case DTYPE_FIFO: case DTYPE_VNODE: vp = fp->f_vnode; intlabel = mac_vnode_label_alloc(); mtx_lock(&Giant); /* VFS */ vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); mac_copy_vnode_label(vp->v_label, intlabel); VOP_UNLOCK(vp, 0, td); mtx_unlock(&Giant); /* VFS */ error = mac_externalize_vnode_label(intlabel, elements, buffer, mac.m_buflen); mac_vnode_label_free(intlabel); break; case DTYPE_PIPE: pipe = fp->f_data; intlabel = mac_pipe_label_alloc(); PIPE_LOCK(pipe); - mac_copy_pipe_label(pipe->pipe_label, intlabel); + mac_copy_pipe_label(pipe->pipe_pair->pp_label, intlabel); PIPE_UNLOCK(pipe); error = mac_externalize_pipe_label(intlabel, elements, buffer, mac.m_buflen); mac_pipe_label_free(intlabel); break; case DTYPE_SOCKET: so = fp->f_data; intlabel = mac_socket_label_alloc(M_WAITOK); mtx_lock(&Giant); /* Sockets */ /* XXX: Socket lock here. */ mac_copy_socket_label(so->so_label, intlabel); /* XXX: Socket unlock here. */ mtx_unlock(&Giant); /* Sockets */ error = mac_externalize_socket_label(intlabel, elements, buffer, mac.m_buflen); mac_socket_label_free(intlabel); break; default: error = EINVAL; } fdrop(fp, td); if (error == 0) error = copyout(buffer, mac.m_string, strlen(buffer)+1); out: free(buffer, M_MACTEMP); free(elements, M_MACTEMP); return (error); } /* * MPSAFE */ int __mac_get_file(struct thread *td, struct __mac_get_file_args *uap) { char *elements, *buffer; struct nameidata nd; struct label *intlabel; struct mac mac; int error; error = copyin(uap->mac_p, &mac, sizeof(mac)); if (error) return (error); error = mac_check_structmac_consistent(&mac); if (error) return (error); elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL); if (error) { free(elements, M_MACTEMP); return (error); } buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); mtx_lock(&Giant); /* VFS */ NDINIT(&nd, LOOKUP, LOCKLEAF | FOLLOW, UIO_USERSPACE, uap->path_p, td); error = namei(&nd); if (error) goto out; intlabel = mac_vnode_label_alloc(); mac_copy_vnode_label(nd.ni_vp->v_label, intlabel); error = mac_externalize_vnode_label(intlabel, elements, buffer, mac.m_buflen); NDFREE(&nd, 0); mac_vnode_label_free(intlabel); if (error == 0) error = copyout(buffer, mac.m_string, strlen(buffer)+1); out: mtx_unlock(&Giant); /* VFS */ free(buffer, M_MACTEMP); free(elements, M_MACTEMP); return (error); } /* * MPSAFE */ int __mac_get_link(struct thread *td, struct __mac_get_link_args *uap) { char *elements, *buffer; struct nameidata nd; struct label *intlabel; struct mac mac; int error; error = copyin(uap->mac_p, &mac, sizeof(mac)); if (error) return (error); error = mac_check_structmac_consistent(&mac); if (error) return (error); elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL); if (error) { free(elements, M_MACTEMP); return (error); } buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); mtx_lock(&Giant); /* VFS */ NDINIT(&nd, LOOKUP, LOCKLEAF | NOFOLLOW, UIO_USERSPACE, uap->path_p, td); error = namei(&nd); if (error) goto out; intlabel = mac_vnode_label_alloc(); mac_copy_vnode_label(nd.ni_vp->v_label, intlabel); error = mac_externalize_vnode_label(intlabel, elements, buffer, mac.m_buflen); NDFREE(&nd, 0); mac_vnode_label_free(intlabel); if (error == 0) error = copyout(buffer, mac.m_string, strlen(buffer)+1); out: mtx_unlock(&Giant); /* VFS */ free(buffer, M_MACTEMP); free(elements, M_MACTEMP); return (error); } /* * MPSAFE */ int __mac_set_fd(struct thread *td, struct __mac_set_fd_args *uap) { struct label *intlabel; struct pipe *pipe; struct socket *so; struct file *fp; struct mount *mp; struct vnode *vp; struct mac mac; char *buffer; int error; error = copyin(uap->mac_p, &mac, sizeof(mac)); if (error) return (error); error = mac_check_structmac_consistent(&mac); if (error) return (error); buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL); if (error) { free(buffer, M_MACTEMP); return (error); } error = fget(td, uap->fd, &fp); if (error) goto out; switch (fp->f_type) { case DTYPE_FIFO: case DTYPE_VNODE: intlabel = mac_vnode_label_alloc(); error = mac_internalize_vnode_label(intlabel, buffer); if (error) { mac_vnode_label_free(intlabel); break; } vp = fp->f_vnode; mtx_lock(&Giant); /* VFS */ error = vn_start_write(vp, &mp, V_WAIT | PCATCH); if (error != 0) { mtx_unlock(&Giant); /* VFS */ mac_vnode_label_free(intlabel); break; } vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); error = vn_setlabel(vp, intlabel, td->td_ucred); VOP_UNLOCK(vp, 0, td); vn_finished_write(mp); mtx_unlock(&Giant); /* VFS */ mac_vnode_label_free(intlabel); break; case DTYPE_PIPE: intlabel = mac_pipe_label_alloc(); error = mac_internalize_pipe_label(intlabel, buffer); if (error == 0) { pipe = fp->f_data; PIPE_LOCK(pipe); - error = mac_pipe_label_set(td->td_ucred, pipe, - intlabel); + error = mac_pipe_label_set(td->td_ucred, + pipe->pipe_pair, intlabel); PIPE_UNLOCK(pipe); } mac_pipe_label_free(intlabel); break; case DTYPE_SOCKET: intlabel = mac_socket_label_alloc(M_WAITOK); error = mac_internalize_socket_label(intlabel, buffer); if (error == 0) { so = fp->f_data; mtx_lock(&Giant); /* Sockets */ /* XXX: Socket lock here. */ error = mac_socket_label_set(td->td_ucred, so, intlabel); /* XXX: Socket unlock here. */ mtx_unlock(&Giant); /* Sockets */ } mac_socket_label_free(intlabel); break; default: error = EINVAL; } fdrop(fp, td); out: free(buffer, M_MACTEMP); return (error); } /* * MPSAFE */ int __mac_set_file(struct thread *td, struct __mac_set_file_args *uap) { struct label *intlabel; struct nameidata nd; struct mount *mp; struct mac mac; char *buffer; int error; error = copyin(uap->mac_p, &mac, sizeof(mac)); if (error) return (error); error = mac_check_structmac_consistent(&mac); if (error) return (error); buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL); if (error) { free(buffer, M_MACTEMP); return (error); } intlabel = mac_vnode_label_alloc(); error = mac_internalize_vnode_label(intlabel, buffer); free(buffer, M_MACTEMP); if (error) goto out; mtx_lock(&Giant); /* VFS */ NDINIT(&nd, LOOKUP, LOCKLEAF | FOLLOW, UIO_USERSPACE, uap->path_p, td); error = namei(&nd); if (error == 0) { error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH); if (error == 0) error = vn_setlabel(nd.ni_vp, intlabel, td->td_ucred); vn_finished_write(mp); } NDFREE(&nd, 0); mtx_unlock(&Giant); /* VFS */ out: mac_vnode_label_free(intlabel); return (error); } /* * MPSAFE */ int __mac_set_link(struct thread *td, struct __mac_set_link_args *uap) { struct label *intlabel; struct nameidata nd; struct mount *mp; struct mac mac; char *buffer; int error; error = copyin(uap->mac_p, &mac, sizeof(mac)); if (error) return (error); error = mac_check_structmac_consistent(&mac); if (error) return (error); buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL); if (error) { free(buffer, M_MACTEMP); return (error); } intlabel = mac_vnode_label_alloc(); error = mac_internalize_vnode_label(intlabel, buffer); free(buffer, M_MACTEMP); if (error) goto out; mtx_lock(&Giant); /* VFS */ NDINIT(&nd, LOOKUP, LOCKLEAF | NOFOLLOW, UIO_USERSPACE, uap->path_p, td); error = namei(&nd); if (error == 0) { error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH); if (error == 0) error = vn_setlabel(nd.ni_vp, intlabel, td->td_ucred); vn_finished_write(mp); } NDFREE(&nd, 0); mtx_unlock(&Giant); /* VFS */ out: mac_vnode_label_free(intlabel); return (error); } /* * MPSAFE */ int mac_syscall(struct thread *td, struct mac_syscall_args *uap) { struct mac_policy_conf *mpc; char target[MAC_MAX_POLICY_NAME]; int entrycount, error; error = copyinstr(uap->policy, target, sizeof(target), NULL); if (error) return (error); error = ENOSYS; LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) { if (strcmp(mpc->mpc_name, target) == 0 && mpc->mpc_ops->mpo_syscall != NULL) { error = mpc->mpc_ops->mpo_syscall(td, uap->call, uap->arg); goto out; } } if ((entrycount = mac_policy_list_conditional_busy()) != 0) { LIST_FOREACH(mpc, &mac_policy_list, mpc_list) { if (strcmp(mpc->mpc_name, target) == 0 && mpc->mpc_ops->mpo_syscall != NULL) { error = mpc->mpc_ops->mpo_syscall(td, uap->call, uap->arg); break; } } mac_policy_list_unbusy(); } out: return (error); } SYSINIT(mac, SI_SUB_MAC, SI_ORDER_FIRST, mac_init, NULL); SYSINIT(mac_late, SI_SUB_MAC_LATE, SI_ORDER_FIRST, mac_late_init, NULL); #else /* !MAC */ int __mac_get_pid(struct thread *td, struct __mac_get_pid_args *uap) { return (ENOSYS); } int __mac_get_proc(struct thread *td, struct __mac_get_proc_args *uap) { return (ENOSYS); } int __mac_set_proc(struct thread *td, struct __mac_set_proc_args *uap) { return (ENOSYS); } int __mac_get_fd(struct thread *td, struct __mac_get_fd_args *uap) { return (ENOSYS); } int __mac_get_file(struct thread *td, struct __mac_get_file_args *uap) { return (ENOSYS); } int __mac_get_link(struct thread *td, struct __mac_get_link_args *uap) { return (ENOSYS); } int __mac_set_fd(struct thread *td, struct __mac_set_fd_args *uap) { return (ENOSYS); } int __mac_set_file(struct thread *td, struct __mac_set_file_args *uap) { return (ENOSYS); } int __mac_set_link(struct thread *td, struct __mac_set_link_args *uap) { return (ENOSYS); } int mac_syscall(struct thread *td, struct mac_syscall_args *uap) { return (ENOSYS); } #endif Index: head/sys/kern/sys_pipe.c =================================================================== --- head/sys/kern/sys_pipe.c (revision 125292) +++ head/sys/kern/sys_pipe.c (revision 125293) @@ -1,1529 +1,1588 @@ /* * Copyright (c) 1996 John S. Dyson * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice immediately at the beginning of the file, without modification, * this list of conditions, and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Absolutely no warranty of function or purpose is made by the author * John S. Dyson. * 4. Modifications may be freely made to this file if the above conditions * are met. */ /* * This file contains a high-performance replacement for the socket-based * pipes scheme originally used in FreeBSD/4.4Lite. It does not support * all features of sockets, but does do everything that pipes normally * do. */ /* * This code has two modes of operation, a small write mode and a large * write mode. The small write mode acts like conventional pipes with * a kernel buffer. If the buffer is less than PIPE_MINDIRECT, then the * "normal" pipe buffering is done. If the buffer is between PIPE_MINDIRECT * and PIPE_SIZE in size, it is fully mapped and wired into the kernel, and * the receiving process can copy it directly from the pages in the sending * process. * * If the sending process receives a signal, it is possible that it will * go away, and certainly its address space can change, because control * is returned back to the user-mode side. In that case, the pipe code * arranges to copy the buffer supplied by the user process, to a pageable * kernel buffer, and the receiving process will grab the data from the * pageable kernel buffer. Since signals don't happen all that often, * the copy operation is normally eliminated. * * The constant PIPE_MINDIRECT is chosen to make sure that buffering will * happen for small transfers so that the system will not spend all of * its time context switching. * * In order to limit the resource use of pipes, two sysctls exist: * * kern.ipc.maxpipekva - This is a hard limit on the amount of pageable * address space available to us in pipe_map. Whenever the amount in use * exceeds half of this value, all new pipes will be created with size * SMALL_PIPE_SIZE, rather than PIPE_SIZE. Big pipe creation will be limited * as well. This value is loader tunable only. * * kern.ipc.maxpipekvawired - This value limits the amount of memory that may * be wired in order to facilitate direct copies using page flipping. * Whenever this value is exceeded, pipes will fall back to using regular * copies. This value is sysctl controllable at all times. * * These values are autotuned in subr_param.c. * * Memory usage may be monitored through the sysctls * kern.ipc.pipes, kern.ipc.pipekva and kern.ipc.pipekvawired. * */ #include __FBSDID("$FreeBSD$"); #include "opt_mac.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* * Use this define if you want to disable *fancy* VM things. Expect an * approx 30% decrease in transfer rate. This could be useful for * NetBSD or OpenBSD. */ /* #define PIPE_NODIRECT */ /* * interfaces to the outside world */ static fo_rdwr_t pipe_read; static fo_rdwr_t pipe_write; static fo_ioctl_t pipe_ioctl; static fo_poll_t pipe_poll; static fo_kqfilter_t pipe_kqfilter; static fo_stat_t pipe_stat; static fo_close_t pipe_close; static struct fileops pipeops = { .fo_read = pipe_read, .fo_write = pipe_write, .fo_ioctl = pipe_ioctl, .fo_poll = pipe_poll, .fo_kqfilter = pipe_kqfilter, .fo_stat = pipe_stat, .fo_close = pipe_close, .fo_flags = DFLAG_PASSABLE }; static void filt_pipedetach(struct knote *kn); static int filt_piperead(struct knote *kn, long hint); static int filt_pipewrite(struct knote *kn, long hint); static struct filterops pipe_rfiltops = { 1, NULL, filt_pipedetach, filt_piperead }; static struct filterops pipe_wfiltops = { 1, NULL, filt_pipedetach, filt_pipewrite }; /* * Default pipe buffer size(s), this can be kind-of large now because pipe * space is pageable. The pipe code will try to maintain locality of * reference for performance reasons, so small amounts of outstanding I/O * will not wipe the cache. */ #define MINPIPESIZE (PIPE_SIZE/3) #define MAXPIPESIZE (2*PIPE_SIZE/3) /* * Limit the number of "big" pipes */ #define LIMITBIGPIPES 32 static int nbigpipe; static int amountpipes; static int amountpipekva; static int amountpipekvawired; SYSCTL_DECL(_kern_ipc); SYSCTL_INT(_kern_ipc, OID_AUTO, maxpipekva, CTLFLAG_RDTUN, &maxpipekva, 0, "Pipe KVA limit"); SYSCTL_INT(_kern_ipc, OID_AUTO, maxpipekvawired, CTLFLAG_RW, &maxpipekvawired, 0, "Pipe KVA wired limit"); SYSCTL_INT(_kern_ipc, OID_AUTO, pipes, CTLFLAG_RD, &amountpipes, 0, "Current # of pipes"); SYSCTL_INT(_kern_ipc, OID_AUTO, bigpipes, CTLFLAG_RD, &nbigpipe, 0, "Current # of big pipes"); SYSCTL_INT(_kern_ipc, OID_AUTO, pipekva, CTLFLAG_RD, &amountpipekva, 0, "Pipe KVA usage"); SYSCTL_INT(_kern_ipc, OID_AUTO, pipekvawired, CTLFLAG_RD, &amountpipekvawired, 0, "Pipe wired KVA usage"); static void pipeinit(void *dummy __unused); static void pipeclose(struct pipe *cpipe); static void pipe_free_kmem(struct pipe *cpipe); -static int pipe_create(struct pipe **cpipep); +static int pipe_create(struct pipe *pipe); static __inline int pipelock(struct pipe *cpipe, int catch); static __inline void pipeunlock(struct pipe *cpipe); static __inline void pipeselwakeup(struct pipe *cpipe); #ifndef PIPE_NODIRECT static int pipe_build_write_buffer(struct pipe *wpipe, struct uio *uio); static void pipe_destroy_write_buffer(struct pipe *wpipe); static int pipe_direct_write(struct pipe *wpipe, struct uio *uio); static void pipe_clone_write_buffer(struct pipe *wpipe); #endif static int pipespace(struct pipe *cpipe, int size); +static void pipe_zone_ctor(void *mem, int size, void *arg); +static void pipe_zone_dtor(void *mem, int size, void *arg); +static void pipe_zone_init(void *mem, int size); +static void pipe_zone_fini(void *mem, int size); + static uma_zone_t pipe_zone; SYSINIT(vfs, SI_SUB_VFS, SI_ORDER_ANY, pipeinit, NULL); static void pipeinit(void *dummy __unused) { - pipe_zone = uma_zcreate("PIPE", sizeof(struct pipe), NULL, - NULL, NULL, NULL, UMA_ALIGN_PTR, 0); + pipe_zone = uma_zcreate("PIPE", sizeof(struct pipepair), + pipe_zone_ctor, pipe_zone_dtor, pipe_zone_init, pipe_zone_fini, + UMA_ALIGN_PTR, 0); KASSERT(pipe_zone != NULL, ("pipe_zone not initialized")); } +static void +pipe_zone_ctor(void *mem, int size, void *arg) +{ + struct pipepair *pp; + struct pipe *rpipe, *wpipe; + + KASSERT(size == sizeof(*pp), ("pipe_zone_ctor: wrong size")); + + pp = (struct pipepair *)mem; + + /* + * We zero both pipe endpoints to make sure all the kmem pointers + * are NULL, flag fields are zero'd, etc. We timestamp both + * endpoints with the same time. + */ + rpipe = &pp->pp_rpipe; + bzero(rpipe, sizeof(*rpipe)); + vfs_timestamp(&rpipe->pipe_ctime); + rpipe->pipe_atime = rpipe->pipe_mtime = rpipe->pipe_ctime; + + wpipe = &pp->pp_wpipe; + bzero(wpipe, sizeof(*wpipe)); + wpipe->pipe_ctime = rpipe->pipe_ctime; + wpipe->pipe_atime = wpipe->pipe_mtime = rpipe->pipe_ctime; + + rpipe->pipe_peer = wpipe; + rpipe->pipe_pair = pp; + wpipe->pipe_peer = rpipe; + wpipe->pipe_pair = pp; + + /* + * Mark both endpoints as present; they will later get free'd + * one at a time. When both are free'd, then the whole pair + * is released. + */ + rpipe->pipe_present = 1; + wpipe->pipe_present = 1; + + /* + * Eventually, the MAC Framework may initialize the label + * in ctor or init, but for now we do it elswhere to avoid + * blocking in ctor or init. + */ + pp->pp_label = NULL; + +} + +static void +pipe_zone_dtor(void *mem, int size, void *arg) +{ + struct pipepair *pp; + + KASSERT(size == sizeof(*pp), ("pipe_zone_dtor: wrong size")); + + pp = (struct pipepair *)mem; +} + +static void +pipe_zone_init(void *mem, int size) +{ + struct pipepair *pp; + + KASSERT(size == sizeof(*pp), ("pipe_zone_init: wrong size")); + + pp = (struct pipepair *)mem; + + mtx_init(&pp->pp_mtx, "pipe mutex", NULL, MTX_DEF | MTX_RECURSE); +} + +static void +pipe_zone_fini(void *mem, int size) +{ + struct pipepair *pp; + + KASSERT(size == sizeof(*pp), ("pipe_zone_fini: wrong size")); + + pp = (struct pipepair *)mem; + + mtx_destroy(&pp->pp_mtx); +} + /* - * The pipe system call for the DTYPE_PIPE type of pipes + * The pipe system call for the DTYPE_PIPE type of pipes. If we fail, + * let the zone pick up the pieces via pipeclose(). */ /* ARGSUSED */ int pipe(td, uap) struct thread *td; struct pipe_args /* { int dummy; } */ *uap; { struct filedesc *fdp = td->td_proc->p_fd; struct file *rf, *wf; + struct pipepair *pp; struct pipe *rpipe, *wpipe; - struct mtx *pmtx; int fd, error; - rpipe = wpipe = NULL; - if (pipe_create(&rpipe) || pipe_create(&wpipe)) { + pp = uma_zalloc(pipe_zone, M_WAITOK); +#ifdef MAC + /* + * struct pipe represents a pipe endpoint. The MAC label is shared + * between the connected endpoints. As a result mac_init_pipe() and + * mac_create_pipe() should only be called on one of the endpoints + * after they have been connected. + */ + mac_init_pipe(pp); + mac_create_pipe(td->td_ucred, pp); +#endif + rpipe = &pp->pp_rpipe; + wpipe = &pp->pp_wpipe; + + if (pipe_create(rpipe) || pipe_create(wpipe)) { pipeclose(rpipe); pipeclose(wpipe); return (ENFILE); } rpipe->pipe_state |= PIPE_DIRECTOK; wpipe->pipe_state |= PIPE_DIRECTOK; error = falloc(td, &rf, &fd); if (error) { pipeclose(rpipe); pipeclose(wpipe); return (error); } /* An extra reference on `rf' has been held for us by falloc(). */ td->td_retval[0] = fd; /* * Warning: once we've gotten past allocation of the fd for the * read-side, we can only drop the read side via fdrop() in order * to avoid races against processes which manage to dup() the read * side while we are blocked trying to allocate the write side. */ FILE_LOCK(rf); rf->f_flag = FREAD | FWRITE; rf->f_type = DTYPE_PIPE; rf->f_data = rpipe; rf->f_ops = &pipeops; FILE_UNLOCK(rf); error = falloc(td, &wf, &fd); if (error) { FILEDESC_LOCK(fdp); if (fdp->fd_ofiles[td->td_retval[0]] == rf) { fdp->fd_ofiles[td->td_retval[0]] = NULL; fdunused(fdp, td->td_retval[0]); FILEDESC_UNLOCK(fdp); fdrop(rf, td); } else { FILEDESC_UNLOCK(fdp); } fdrop(rf, td); /* rpipe has been closed by fdrop(). */ pipeclose(wpipe); return (error); } /* An extra reference on `wf' has been held for us by falloc(). */ FILE_LOCK(wf); wf->f_flag = FREAD | FWRITE; wf->f_type = DTYPE_PIPE; wf->f_data = wpipe; wf->f_ops = &pipeops; FILE_UNLOCK(wf); fdrop(wf, td); td->td_retval[1] = fd; - rpipe->pipe_peer = wpipe; - wpipe->pipe_peer = rpipe; -#ifdef MAC - /* - * struct pipe represents a pipe endpoint. The MAC label is shared - * between the connected endpoints. As a result mac_init_pipe() and - * mac_create_pipe() should only be called on one of the endpoints - * after they have been connected. - */ - mac_init_pipe(rpipe); - mac_create_pipe(td->td_ucred, rpipe); -#endif - pmtx = malloc(sizeof(*pmtx), M_TEMP, M_WAITOK | M_ZERO); - mtx_init(pmtx, "pipe mutex", NULL, MTX_DEF | MTX_RECURSE); - rpipe->pipe_mtxp = wpipe->pipe_mtxp = pmtx; fdrop(rf, td); return (0); } /* * Allocate kva for pipe circular buffer, the space is pageable * This routine will 'realloc' the size of a pipe safely, if it fails * it will retain the old buffer. * If it fails it will return ENOMEM. */ static int pipespace(cpipe, size) struct pipe *cpipe; int size; { caddr_t buffer; int error; static int curfail = 0; static struct timeval lastfail; - KASSERT(cpipe->pipe_mtxp == NULL || !mtx_owned(PIPE_MTX(cpipe)), - ("pipespace: pipe mutex locked")); + KASSERT(!mtx_owned(PIPE_MTX(cpipe)), ("pipespace: pipe mutex locked")); size = round_page(size); /* * XXX -- minor change needed here for NetBSD/OpenBSD VM systems. */ buffer = (caddr_t) vm_map_min(pipe_map); /* * The map entry is, by default, pageable. * XXX -- minor change needed here for NetBSD/OpenBSD VM systems. */ error = vm_map_find(pipe_map, NULL, 0, (vm_offset_t *) &buffer, size, 1, VM_PROT_ALL, VM_PROT_ALL, 0); if (error != KERN_SUCCESS) { if (ppsratecheck(&lastfail, &curfail, 1)) printf("kern.ipc.maxpipekva exceeded; see tuning(7)\n"); return (ENOMEM); } /* free old resources if we're resizing */ pipe_free_kmem(cpipe); cpipe->pipe_buffer.buffer = buffer; cpipe->pipe_buffer.size = size; cpipe->pipe_buffer.in = 0; cpipe->pipe_buffer.out = 0; cpipe->pipe_buffer.cnt = 0; atomic_add_int(&amountpipes, 1); atomic_add_int(&amountpipekva, cpipe->pipe_buffer.size); return (0); } /* - * initialize and allocate VM and memory for pipe + * Initialize and allocate VM and memory for pipe. The structure + * will start out zero'd from the ctor, so we just manage the kmem. */ static int -pipe_create(cpipep) - struct pipe **cpipep; +pipe_create(pipe) + struct pipe *pipe; { - struct pipe *cpipe; int error; - *cpipep = uma_zalloc(pipe_zone, M_WAITOK); - if (*cpipep == NULL) - return (ENOMEM); - - cpipe = *cpipep; - /* - * protect so pipeclose() doesn't follow a junk pointer - * if pipespace() fails. - */ - bzero(&cpipe->pipe_sel, sizeof(cpipe->pipe_sel)); - cpipe->pipe_state = 0; - cpipe->pipe_peer = NULL; - cpipe->pipe_busy = 0; - -#ifndef PIPE_NODIRECT - /* - * pipe data structure initializations to support direct pipe I/O - */ - cpipe->pipe_map.cnt = 0; - cpipe->pipe_map.kva = 0; - cpipe->pipe_map.pos = 0; - cpipe->pipe_map.npages = 0; - /* cpipe->pipe_map.ms[] = invalid */ -#endif - - cpipe->pipe_mtxp = NULL; /* avoid pipespace assertion */ - /* * Reduce to 1/4th pipe size if we're over our global max. */ if (amountpipekva > maxpipekva / 2) - error = pipespace(cpipe, SMALL_PIPE_SIZE); + error = pipespace(pipe, SMALL_PIPE_SIZE); else - error = pipespace(cpipe, PIPE_SIZE); + error = pipespace(pipe, PIPE_SIZE); if (error) return (error); - vfs_timestamp(&cpipe->pipe_ctime); - cpipe->pipe_atime = cpipe->pipe_ctime; - cpipe->pipe_mtime = cpipe->pipe_ctime; - return (0); } - /* * lock a pipe for I/O, blocking other access */ static __inline int pipelock(cpipe, catch) struct pipe *cpipe; int catch; { int error; PIPE_LOCK_ASSERT(cpipe, MA_OWNED); while (cpipe->pipe_state & PIPE_LOCKFL) { cpipe->pipe_state |= PIPE_LWANT; error = msleep(cpipe, PIPE_MTX(cpipe), catch ? (PRIBIO | PCATCH) : PRIBIO, "pipelk", 0); if (error != 0) return (error); } cpipe->pipe_state |= PIPE_LOCKFL; return (0); } /* * unlock a pipe I/O lock */ static __inline void pipeunlock(cpipe) struct pipe *cpipe; { PIPE_LOCK_ASSERT(cpipe, MA_OWNED); cpipe->pipe_state &= ~PIPE_LOCKFL; if (cpipe->pipe_state & PIPE_LWANT) { cpipe->pipe_state &= ~PIPE_LWANT; wakeup(cpipe); } } static __inline void pipeselwakeup(cpipe) struct pipe *cpipe; { if (cpipe->pipe_state & PIPE_SEL) { cpipe->pipe_state &= ~PIPE_SEL; selwakeuppri(&cpipe->pipe_sel, PSOCK); } if ((cpipe->pipe_state & PIPE_ASYNC) && cpipe->pipe_sigio) pgsigio(&cpipe->pipe_sigio, SIGIO, 0); KNOTE(&cpipe->pipe_sel.si_note, 0); } /* ARGSUSED */ static int pipe_read(fp, uio, active_cred, flags, td) struct file *fp; struct uio *uio; struct ucred *active_cred; struct thread *td; int flags; { struct pipe *rpipe = fp->f_data; int error; int nread = 0; u_int size; PIPE_LOCK(rpipe); ++rpipe->pipe_busy; error = pipelock(rpipe, 1); if (error) goto unlocked_error; #ifdef MAC - error = mac_check_pipe_read(active_cred, rpipe); + error = mac_check_pipe_read(active_cred, rpipe->pipe_pair); if (error) goto locked_error; #endif while (uio->uio_resid) { /* * normal pipe buffer receive */ if (rpipe->pipe_buffer.cnt > 0) { size = rpipe->pipe_buffer.size - rpipe->pipe_buffer.out; if (size > rpipe->pipe_buffer.cnt) size = rpipe->pipe_buffer.cnt; if (size > (u_int) uio->uio_resid) size = (u_int) uio->uio_resid; PIPE_UNLOCK(rpipe); error = uiomove( &rpipe->pipe_buffer.buffer[rpipe->pipe_buffer.out], size, uio); PIPE_LOCK(rpipe); if (error) break; rpipe->pipe_buffer.out += size; if (rpipe->pipe_buffer.out >= rpipe->pipe_buffer.size) rpipe->pipe_buffer.out = 0; rpipe->pipe_buffer.cnt -= size; /* * If there is no more to read in the pipe, reset * its pointers to the beginning. This improves * cache hit stats. */ if (rpipe->pipe_buffer.cnt == 0) { rpipe->pipe_buffer.in = 0; rpipe->pipe_buffer.out = 0; } nread += size; #ifndef PIPE_NODIRECT /* * Direct copy, bypassing a kernel buffer. */ } else if ((size = rpipe->pipe_map.cnt) && (rpipe->pipe_state & PIPE_DIRECTW)) { caddr_t va; if (size > (u_int) uio->uio_resid) size = (u_int) uio->uio_resid; va = (caddr_t) rpipe->pipe_map.kva + rpipe->pipe_map.pos; PIPE_UNLOCK(rpipe); error = uiomove(va, size, uio); PIPE_LOCK(rpipe); if (error) break; nread += size; rpipe->pipe_map.pos += size; rpipe->pipe_map.cnt -= size; if (rpipe->pipe_map.cnt == 0) { rpipe->pipe_state &= ~PIPE_DIRECTW; wakeup(rpipe); } #endif } else { /* * detect EOF condition * read returns 0 on EOF, no need to set error */ if (rpipe->pipe_state & PIPE_EOF) break; /* * If the "write-side" has been blocked, wake it up now. */ if (rpipe->pipe_state & PIPE_WANTW) { rpipe->pipe_state &= ~PIPE_WANTW; wakeup(rpipe); } /* * Break if some data was read. */ if (nread > 0) break; /* * Unlock the pipe buffer for our remaining processing. * We will either break out with an error or we will * sleep and relock to loop. */ pipeunlock(rpipe); /* * Handle non-blocking mode operation or * wait for more data. */ if (fp->f_flag & FNONBLOCK) { error = EAGAIN; } else { rpipe->pipe_state |= PIPE_WANTR; if ((error = msleep(rpipe, PIPE_MTX(rpipe), PRIBIO | PCATCH, "piperd", 0)) == 0) error = pipelock(rpipe, 1); } if (error) goto unlocked_error; } } #ifdef MAC locked_error: #endif pipeunlock(rpipe); /* XXX: should probably do this before getting any locks. */ if (error == 0) vfs_timestamp(&rpipe->pipe_atime); unlocked_error: --rpipe->pipe_busy; /* * PIPE_WANT processing only makes sense if pipe_busy is 0. */ if ((rpipe->pipe_busy == 0) && (rpipe->pipe_state & PIPE_WANT)) { rpipe->pipe_state &= ~(PIPE_WANT|PIPE_WANTW); wakeup(rpipe); } else if (rpipe->pipe_buffer.cnt < MINPIPESIZE) { /* * Handle write blocking hysteresis. */ if (rpipe->pipe_state & PIPE_WANTW) { rpipe->pipe_state &= ~PIPE_WANTW; wakeup(rpipe); } } if ((rpipe->pipe_buffer.size - rpipe->pipe_buffer.cnt) >= PIPE_BUF) pipeselwakeup(rpipe); PIPE_UNLOCK(rpipe); return (error); } #ifndef PIPE_NODIRECT /* * Map the sending processes' buffer into kernel space and wire it. * This is similar to a physical write operation. */ static int pipe_build_write_buffer(wpipe, uio) struct pipe *wpipe; struct uio *uio; { pmap_t pmap; u_int size; int i, j; vm_offset_t addr, endaddr; PIPE_LOCK_ASSERT(wpipe, MA_NOTOWNED); size = (u_int) uio->uio_iov->iov_len; if (size > wpipe->pipe_buffer.size) size = wpipe->pipe_buffer.size; pmap = vmspace_pmap(curproc->p_vmspace); endaddr = round_page((vm_offset_t)uio->uio_iov->iov_base + size); addr = trunc_page((vm_offset_t)uio->uio_iov->iov_base); for (i = 0; addr < endaddr; addr += PAGE_SIZE, i++) { /* * vm_fault_quick() can sleep. Consequently, * vm_page_lock_queue() and vm_page_unlock_queue() * should not be performed outside of this loop. */ race: if (vm_fault_quick((caddr_t)addr, VM_PROT_READ) < 0) { vm_page_lock_queues(); for (j = 0; j < i; j++) vm_page_unhold(wpipe->pipe_map.ms[j]); vm_page_unlock_queues(); return (EFAULT); } wpipe->pipe_map.ms[i] = pmap_extract_and_hold(pmap, addr, VM_PROT_READ); if (wpipe->pipe_map.ms[i] == NULL) goto race; } /* * set up the control block */ wpipe->pipe_map.npages = i; wpipe->pipe_map.pos = ((vm_offset_t) uio->uio_iov->iov_base) & PAGE_MASK; wpipe->pipe_map.cnt = size; /* * and map the buffer */ if (wpipe->pipe_map.kva == 0) { /* * We need to allocate space for an extra page because the * address range might (will) span pages at times. */ wpipe->pipe_map.kva = kmem_alloc_nofault(kernel_map, wpipe->pipe_buffer.size + PAGE_SIZE); atomic_add_int(&amountpipekvawired, wpipe->pipe_buffer.size + PAGE_SIZE); } pmap_qenter(wpipe->pipe_map.kva, wpipe->pipe_map.ms, wpipe->pipe_map.npages); /* * and update the uio data */ uio->uio_iov->iov_len -= size; uio->uio_iov->iov_base = (char *)uio->uio_iov->iov_base + size; if (uio->uio_iov->iov_len == 0) uio->uio_iov++; uio->uio_resid -= size; uio->uio_offset += size; return (0); } /* * unmap and unwire the process buffer */ static void pipe_destroy_write_buffer(wpipe) struct pipe *wpipe; { int i; PIPE_LOCK_ASSERT(wpipe, MA_NOTOWNED); if (wpipe->pipe_map.kva) { pmap_qremove(wpipe->pipe_map.kva, wpipe->pipe_map.npages); if (amountpipekvawired > maxpipekvawired / 2) { /* Conserve address space */ vm_offset_t kva = wpipe->pipe_map.kva; wpipe->pipe_map.kva = 0; kmem_free(kernel_map, kva, wpipe->pipe_buffer.size + PAGE_SIZE); atomic_subtract_int(&amountpipekvawired, wpipe->pipe_buffer.size + PAGE_SIZE); } } vm_page_lock_queues(); for (i = 0; i < wpipe->pipe_map.npages; i++) { vm_page_unhold(wpipe->pipe_map.ms[i]); } vm_page_unlock_queues(); wpipe->pipe_map.npages = 0; } /* * In the case of a signal, the writing process might go away. This * code copies the data into the circular buffer so that the source * pages can be freed without loss of data. */ static void pipe_clone_write_buffer(wpipe) struct pipe *wpipe; { int size; int pos; PIPE_LOCK_ASSERT(wpipe, MA_OWNED); size = wpipe->pipe_map.cnt; pos = wpipe->pipe_map.pos; wpipe->pipe_buffer.in = size; wpipe->pipe_buffer.out = 0; wpipe->pipe_buffer.cnt = size; wpipe->pipe_state &= ~PIPE_DIRECTW; PIPE_UNLOCK(wpipe); bcopy((caddr_t) wpipe->pipe_map.kva + pos, wpipe->pipe_buffer.buffer, size); pipe_destroy_write_buffer(wpipe); PIPE_LOCK(wpipe); } /* * This implements the pipe buffer write mechanism. Note that only * a direct write OR a normal pipe write can be pending at any given time. * If there are any characters in the pipe buffer, the direct write will * be deferred until the receiving process grabs all of the bytes from * the pipe buffer. Then the direct mapping write is set-up. */ static int pipe_direct_write(wpipe, uio) struct pipe *wpipe; struct uio *uio; { int error; retry: PIPE_LOCK_ASSERT(wpipe, MA_OWNED); while (wpipe->pipe_state & PIPE_DIRECTW) { if (wpipe->pipe_state & PIPE_WANTR) { wpipe->pipe_state &= ~PIPE_WANTR; wakeup(wpipe); } wpipe->pipe_state |= PIPE_WANTW; error = msleep(wpipe, PIPE_MTX(wpipe), PRIBIO | PCATCH, "pipdww", 0); if (error) goto error1; if (wpipe->pipe_state & PIPE_EOF) { error = EPIPE; goto error1; } } wpipe->pipe_map.cnt = 0; /* transfer not ready yet */ if (wpipe->pipe_buffer.cnt > 0) { if (wpipe->pipe_state & PIPE_WANTR) { wpipe->pipe_state &= ~PIPE_WANTR; wakeup(wpipe); } wpipe->pipe_state |= PIPE_WANTW; error = msleep(wpipe, PIPE_MTX(wpipe), PRIBIO | PCATCH, "pipdwc", 0); if (error) goto error1; if (wpipe->pipe_state & PIPE_EOF) { error = EPIPE; goto error1; } goto retry; } wpipe->pipe_state |= PIPE_DIRECTW; pipelock(wpipe, 0); PIPE_UNLOCK(wpipe); error = pipe_build_write_buffer(wpipe, uio); PIPE_LOCK(wpipe); pipeunlock(wpipe); if (error) { wpipe->pipe_state &= ~PIPE_DIRECTW; goto error1; } error = 0; while (!error && (wpipe->pipe_state & PIPE_DIRECTW)) { if (wpipe->pipe_state & PIPE_EOF) { pipelock(wpipe, 0); PIPE_UNLOCK(wpipe); pipe_destroy_write_buffer(wpipe); PIPE_LOCK(wpipe); pipeselwakeup(wpipe); pipeunlock(wpipe); error = EPIPE; goto error1; } if (wpipe->pipe_state & PIPE_WANTR) { wpipe->pipe_state &= ~PIPE_WANTR; wakeup(wpipe); } pipeselwakeup(wpipe); error = msleep(wpipe, PIPE_MTX(wpipe), PRIBIO | PCATCH, "pipdwt", 0); } pipelock(wpipe,0); if (wpipe->pipe_state & PIPE_DIRECTW) { /* * this bit of trickery substitutes a kernel buffer for * the process that might be going away. */ pipe_clone_write_buffer(wpipe); } else { PIPE_UNLOCK(wpipe); pipe_destroy_write_buffer(wpipe); PIPE_LOCK(wpipe); } pipeunlock(wpipe); return (error); error1: wakeup(wpipe); return (error); } #endif static int pipe_write(fp, uio, active_cred, flags, td) struct file *fp; struct uio *uio; struct ucred *active_cred; struct thread *td; int flags; { int error = 0; int orig_resid; struct pipe *wpipe, *rpipe; rpipe = fp->f_data; wpipe = rpipe->pipe_peer; PIPE_LOCK(rpipe); /* * detect loss of pipe read side, issue SIGPIPE if lost. */ if ((wpipe == NULL) || (wpipe->pipe_state & PIPE_EOF)) { PIPE_UNLOCK(rpipe); return (EPIPE); } #ifdef MAC - error = mac_check_pipe_write(active_cred, wpipe); + error = mac_check_pipe_write(active_cred, wpipe->pipe_pair); if (error) { PIPE_UNLOCK(rpipe); return (error); } #endif ++wpipe->pipe_busy; /* * If it is advantageous to resize the pipe buffer, do * so. */ if ((uio->uio_resid > PIPE_SIZE) && (amountpipekva < maxpipekva / 2) && (nbigpipe < LIMITBIGPIPES) && (wpipe->pipe_state & PIPE_DIRECTW) == 0 && (wpipe->pipe_buffer.size <= PIPE_SIZE) && (wpipe->pipe_buffer.cnt == 0)) { if ((error = pipelock(wpipe, 1)) == 0) { PIPE_UNLOCK(wpipe); if (pipespace(wpipe, BIG_PIPE_SIZE) == 0) atomic_add_int(&nbigpipe, 1); PIPE_LOCK(wpipe); pipeunlock(wpipe); } } /* * If an early error occured unbusy and return, waking up any pending * readers. */ if (error) { --wpipe->pipe_busy; if ((wpipe->pipe_busy == 0) && (wpipe->pipe_state & PIPE_WANT)) { wpipe->pipe_state &= ~(PIPE_WANT | PIPE_WANTR); wakeup(wpipe); } PIPE_UNLOCK(rpipe); return(error); } orig_resid = uio->uio_resid; while (uio->uio_resid) { int space; #ifndef PIPE_NODIRECT /* * If the transfer is large, we can gain performance if * we do process-to-process copies directly. * If the write is non-blocking, we don't use the * direct write mechanism. * * The direct write mechanism will detect the reader going * away on us. */ if ((uio->uio_iov->iov_len >= PIPE_MINDIRECT) && (fp->f_flag & FNONBLOCK) == 0 && amountpipekvawired + uio->uio_resid < maxpipekvawired) { error = pipe_direct_write(wpipe, uio); if (error) break; continue; } #endif /* * Pipe buffered writes cannot be coincidental with * direct writes. We wait until the currently executing * direct write is completed before we start filling the * pipe buffer. We break out if a signal occurs or the * reader goes away. */ retrywrite: while (wpipe->pipe_state & PIPE_DIRECTW) { if (wpipe->pipe_state & PIPE_WANTR) { wpipe->pipe_state &= ~PIPE_WANTR; wakeup(wpipe); } error = msleep(wpipe, PIPE_MTX(rpipe), PRIBIO | PCATCH, "pipbww", 0); if (wpipe->pipe_state & PIPE_EOF) break; if (error) break; } if (wpipe->pipe_state & PIPE_EOF) { error = EPIPE; break; } space = wpipe->pipe_buffer.size - wpipe->pipe_buffer.cnt; /* Writes of size <= PIPE_BUF must be atomic. */ if ((space < uio->uio_resid) && (orig_resid <= PIPE_BUF)) space = 0; if (space > 0) { if ((error = pipelock(wpipe,1)) == 0) { int size; /* Transfer size */ int segsize; /* first segment to transfer */ /* * It is possible for a direct write to * slip in on us... handle it here... */ if (wpipe->pipe_state & PIPE_DIRECTW) { pipeunlock(wpipe); goto retrywrite; } /* * If a process blocked in uiomove, our * value for space might be bad. * * XXX will we be ok if the reader has gone * away here? */ if (space > wpipe->pipe_buffer.size - wpipe->pipe_buffer.cnt) { pipeunlock(wpipe); goto retrywrite; } /* * Transfer size is minimum of uio transfer * and free space in pipe buffer. */ if (space > uio->uio_resid) size = uio->uio_resid; else size = space; /* * First segment to transfer is minimum of * transfer size and contiguous space in * pipe buffer. If first segment to transfer * is less than the transfer size, we've got * a wraparound in the buffer. */ segsize = wpipe->pipe_buffer.size - wpipe->pipe_buffer.in; if (segsize > size) segsize = size; /* Transfer first segment */ PIPE_UNLOCK(rpipe); error = uiomove(&wpipe->pipe_buffer.buffer[wpipe->pipe_buffer.in], segsize, uio); PIPE_LOCK(rpipe); if (error == 0 && segsize < size) { /* * Transfer remaining part now, to * support atomic writes. Wraparound * happened. */ if (wpipe->pipe_buffer.in + segsize != wpipe->pipe_buffer.size) panic("Expected pipe buffer " "wraparound disappeared"); PIPE_UNLOCK(rpipe); error = uiomove( &wpipe->pipe_buffer.buffer[0], size - segsize, uio); PIPE_LOCK(rpipe); } if (error == 0) { wpipe->pipe_buffer.in += size; if (wpipe->pipe_buffer.in >= wpipe->pipe_buffer.size) { if (wpipe->pipe_buffer.in != size - segsize + wpipe->pipe_buffer.size) panic("Expected " "wraparound bad"); wpipe->pipe_buffer.in = size - segsize; } wpipe->pipe_buffer.cnt += size; if (wpipe->pipe_buffer.cnt > wpipe->pipe_buffer.size) panic("Pipe buffer overflow"); } pipeunlock(wpipe); } if (error) break; } else { /* * If the "read-side" has been blocked, wake it up now. */ if (wpipe->pipe_state & PIPE_WANTR) { wpipe->pipe_state &= ~PIPE_WANTR; wakeup(wpipe); } /* * don't block on non-blocking I/O */ if (fp->f_flag & FNONBLOCK) { error = EAGAIN; break; } /* * We have no more space and have something to offer, * wake up select/poll. */ pipeselwakeup(wpipe); wpipe->pipe_state |= PIPE_WANTW; error = msleep(wpipe, PIPE_MTX(rpipe), PRIBIO | PCATCH, "pipewr", 0); if (error != 0) break; /* * If read side wants to go away, we just issue a signal * to ourselves. */ if (wpipe->pipe_state & PIPE_EOF) { error = EPIPE; break; } } } --wpipe->pipe_busy; if ((wpipe->pipe_busy == 0) && (wpipe->pipe_state & PIPE_WANT)) { wpipe->pipe_state &= ~(PIPE_WANT | PIPE_WANTR); wakeup(wpipe); } else if (wpipe->pipe_buffer.cnt > 0) { /* * If we have put any characters in the buffer, we wake up * the reader. */ if (wpipe->pipe_state & PIPE_WANTR) { wpipe->pipe_state &= ~PIPE_WANTR; wakeup(wpipe); } } /* * Don't return EPIPE if I/O was successful */ if ((wpipe->pipe_buffer.cnt == 0) && (uio->uio_resid == 0) && (error == EPIPE)) { error = 0; } if (error == 0) vfs_timestamp(&wpipe->pipe_mtime); /* * We have something to offer, * wake up select/poll. */ if (wpipe->pipe_buffer.cnt) pipeselwakeup(wpipe); PIPE_UNLOCK(rpipe); return (error); } /* * we implement a very minimal set of ioctls for compatibility with sockets. */ static int pipe_ioctl(fp, cmd, data, active_cred, td) struct file *fp; u_long cmd; void *data; struct ucred *active_cred; struct thread *td; { struct pipe *mpipe = fp->f_data; #ifdef MAC int error; #endif PIPE_LOCK(mpipe); #ifdef MAC - error = mac_check_pipe_ioctl(active_cred, mpipe, cmd, data); + error = mac_check_pipe_ioctl(active_cred, mpipe->pipe_pair, cmd, data); if (error) { PIPE_UNLOCK(mpipe); return (error); } #endif switch (cmd) { case FIONBIO: PIPE_UNLOCK(mpipe); return (0); case FIOASYNC: if (*(int *)data) { mpipe->pipe_state |= PIPE_ASYNC; } else { mpipe->pipe_state &= ~PIPE_ASYNC; } PIPE_UNLOCK(mpipe); return (0); case FIONREAD: if (mpipe->pipe_state & PIPE_DIRECTW) *(int *)data = mpipe->pipe_map.cnt; else *(int *)data = mpipe->pipe_buffer.cnt; PIPE_UNLOCK(mpipe); return (0); case FIOSETOWN: PIPE_UNLOCK(mpipe); return (fsetown(*(int *)data, &mpipe->pipe_sigio)); case FIOGETOWN: PIPE_UNLOCK(mpipe); *(int *)data = fgetown(&mpipe->pipe_sigio); return (0); /* This is deprecated, FIOSETOWN should be used instead. */ case TIOCSPGRP: PIPE_UNLOCK(mpipe); return (fsetown(-(*(int *)data), &mpipe->pipe_sigio)); /* This is deprecated, FIOGETOWN should be used instead. */ case TIOCGPGRP: PIPE_UNLOCK(mpipe); *(int *)data = -fgetown(&mpipe->pipe_sigio); return (0); } PIPE_UNLOCK(mpipe); return (ENOTTY); } static int pipe_poll(fp, events, active_cred, td) struct file *fp; int events; struct ucred *active_cred; struct thread *td; { struct pipe *rpipe = fp->f_data; struct pipe *wpipe; int revents = 0; #ifdef MAC int error; #endif wpipe = rpipe->pipe_peer; PIPE_LOCK(rpipe); #ifdef MAC - error = mac_check_pipe_poll(active_cred, rpipe); + error = mac_check_pipe_poll(active_cred, rpipe->pipe_pair); if (error) goto locked_error; #endif if (events & (POLLIN | POLLRDNORM)) if ((rpipe->pipe_state & PIPE_DIRECTW) || (rpipe->pipe_buffer.cnt > 0) || (rpipe->pipe_state & PIPE_EOF)) revents |= events & (POLLIN | POLLRDNORM); if (events & (POLLOUT | POLLWRNORM)) if (wpipe == NULL || (wpipe->pipe_state & PIPE_EOF) || (((wpipe->pipe_state & PIPE_DIRECTW) == 0) && (wpipe->pipe_buffer.size - wpipe->pipe_buffer.cnt) >= PIPE_BUF)) revents |= events & (POLLOUT | POLLWRNORM); if ((rpipe->pipe_state & PIPE_EOF) || (wpipe == NULL) || (wpipe->pipe_state & PIPE_EOF)) revents |= POLLHUP; if (revents == 0) { if (events & (POLLIN | POLLRDNORM)) { selrecord(td, &rpipe->pipe_sel); rpipe->pipe_state |= PIPE_SEL; } if (events & (POLLOUT | POLLWRNORM)) { selrecord(td, &wpipe->pipe_sel); wpipe->pipe_state |= PIPE_SEL; } } #ifdef MAC locked_error: #endif PIPE_UNLOCK(rpipe); return (revents); } /* * We shouldn't need locks here as we're doing a read and this should * be a natural race. */ static int pipe_stat(fp, ub, active_cred, td) struct file *fp; struct stat *ub; struct ucred *active_cred; struct thread *td; { struct pipe *pipe = fp->f_data; #ifdef MAC int error; PIPE_LOCK(pipe); - error = mac_check_pipe_stat(active_cred, pipe); + error = mac_check_pipe_stat(active_cred, pipe->pipe_pair); PIPE_UNLOCK(pipe); if (error) return (error); #endif bzero(ub, sizeof(*ub)); ub->st_mode = S_IFIFO; ub->st_blksize = pipe->pipe_buffer.size; ub->st_size = pipe->pipe_buffer.cnt; ub->st_blocks = (ub->st_size + ub->st_blksize - 1) / ub->st_blksize; ub->st_atimespec = pipe->pipe_atime; ub->st_mtimespec = pipe->pipe_mtime; ub->st_ctimespec = pipe->pipe_ctime; ub->st_uid = fp->f_cred->cr_uid; ub->st_gid = fp->f_cred->cr_gid; /* * Left as 0: st_dev, st_ino, st_nlink, st_rdev, st_flags, st_gen. * XXX (st_dev, st_ino) should be unique. */ return (0); } /* ARGSUSED */ static int pipe_close(fp, td) struct file *fp; struct thread *td; { struct pipe *cpipe = fp->f_data; fp->f_ops = &badfileops; fp->f_data = NULL; funsetown(&cpipe->pipe_sigio); pipeclose(cpipe); return (0); } static void pipe_free_kmem(cpipe) struct pipe *cpipe; { - KASSERT(cpipe->pipe_mtxp == NULL || !mtx_owned(PIPE_MTX(cpipe)), - ("pipe_free_kmem: pipe mutex locked")); + KASSERT(!mtx_owned(PIPE_MTX(cpipe)), + ("pipe_free_kmem: pipe mutex locked")); if (cpipe->pipe_buffer.buffer != NULL) { if (cpipe->pipe_buffer.size > PIPE_SIZE) atomic_subtract_int(&nbigpipe, 1); atomic_subtract_int(&amountpipekva, cpipe->pipe_buffer.size); atomic_subtract_int(&amountpipes, 1); vm_map_remove(pipe_map, (vm_offset_t)cpipe->pipe_buffer.buffer, (vm_offset_t)cpipe->pipe_buffer.buffer + cpipe->pipe_buffer.size); cpipe->pipe_buffer.buffer = NULL; } #ifndef PIPE_NODIRECT if (cpipe->pipe_map.kva != 0) { atomic_subtract_int(&amountpipekvawired, cpipe->pipe_buffer.size + PAGE_SIZE); kmem_free(kernel_map, cpipe->pipe_map.kva, cpipe->pipe_buffer.size + PAGE_SIZE); cpipe->pipe_map.cnt = 0; cpipe->pipe_map.kva = 0; cpipe->pipe_map.pos = 0; cpipe->pipe_map.npages = 0; } #endif } /* * shutdown the pipe */ static void pipeclose(cpipe) struct pipe *cpipe; { + struct pipepair *pp; struct pipe *ppipe; int hadpeer; - if (cpipe == NULL) - return; + KASSERT(cpipe != NULL, ("pipeclose: cpipe == NULL")); hadpeer = 0; + PIPE_LOCK(cpipe); + pp = cpipe->pipe_pair; - /* partially created pipes won't have a valid mutex. */ - if (PIPE_MTX(cpipe) != NULL) - PIPE_LOCK(cpipe); - pipeselwakeup(cpipe); /* * If the other side is blocked, wake it up saying that * we want to close it down. */ while (cpipe->pipe_busy) { wakeup(cpipe); cpipe->pipe_state |= PIPE_WANT | PIPE_EOF; msleep(cpipe, PIPE_MTX(cpipe), PRIBIO, "pipecl", 0); } -#ifdef MAC - if (cpipe->pipe_label != NULL && cpipe->pipe_peer == NULL) - mac_destroy_pipe(cpipe); -#endif /* - * Disconnect from peer + * Disconnect from peer, if any. */ - if ((ppipe = cpipe->pipe_peer) != NULL) { + ppipe = cpipe->pipe_peer; + if (ppipe->pipe_present != 0) { hadpeer++; pipeselwakeup(ppipe); ppipe->pipe_state |= PIPE_EOF; wakeup(ppipe); KNOTE(&ppipe->pipe_sel.si_note, 0); - ppipe->pipe_peer = NULL; } + /* - * free resources + * Mark this endpoint as free. Release kmem resources. We + * don't mark this endpoint as unused until we've finished + * doing that, or the pipe might disappear out from under + * us. */ - if (PIPE_MTX(cpipe) != NULL) { - PIPE_UNLOCK(cpipe); - if (!hadpeer) { - mtx_destroy(PIPE_MTX(cpipe)); - free(PIPE_MTX(cpipe), M_TEMP); - } - } + PIPE_UNLOCK(cpipe); pipe_free_kmem(cpipe); - uma_zfree(pipe_zone, cpipe); + PIPE_LOCK(cpipe); + cpipe->pipe_present = 0; + + /* + * If both endpoints are now closed, release the memory for the + * pipe pair. If not, unlock. + */ + if (ppipe->pipe_present == 0) { + PIPE_UNLOCK(cpipe); +#ifdef MAC + mac_destroy_pipe(pp); +#endif + uma_zfree(pipe_zone, cpipe->pipe_pair); + } else + PIPE_UNLOCK(cpipe); } /*ARGSUSED*/ static int pipe_kqfilter(struct file *fp, struct knote *kn) { struct pipe *cpipe; cpipe = kn->kn_fp->f_data; switch (kn->kn_filter) { case EVFILT_READ: kn->kn_fop = &pipe_rfiltops; break; case EVFILT_WRITE: kn->kn_fop = &pipe_wfiltops; cpipe = cpipe->pipe_peer; if (cpipe == NULL) /* other end of pipe has been closed */ return (EPIPE); break; default: return (1); } PIPE_LOCK(cpipe); SLIST_INSERT_HEAD(&cpipe->pipe_sel.si_note, kn, kn_selnext); PIPE_UNLOCK(cpipe); return (0); } static void filt_pipedetach(struct knote *kn) { struct pipe *cpipe = (struct pipe *)kn->kn_fp->f_data; if (kn->kn_filter == EVFILT_WRITE) { if (cpipe->pipe_peer == NULL) return; cpipe = cpipe->pipe_peer; } PIPE_LOCK(cpipe); SLIST_REMOVE(&cpipe->pipe_sel.si_note, kn, knote, kn_selnext); PIPE_UNLOCK(cpipe); } /*ARGSUSED*/ static int filt_piperead(struct knote *kn, long hint) { struct pipe *rpipe = kn->kn_fp->f_data; struct pipe *wpipe = rpipe->pipe_peer; PIPE_LOCK(rpipe); kn->kn_data = rpipe->pipe_buffer.cnt; if ((kn->kn_data == 0) && (rpipe->pipe_state & PIPE_DIRECTW)) kn->kn_data = rpipe->pipe_map.cnt; if ((rpipe->pipe_state & PIPE_EOF) || (wpipe == NULL) || (wpipe->pipe_state & PIPE_EOF)) { kn->kn_flags |= EV_EOF; PIPE_UNLOCK(rpipe); return (1); } PIPE_UNLOCK(rpipe); return (kn->kn_data > 0); } /*ARGSUSED*/ static int filt_pipewrite(struct knote *kn, long hint) { struct pipe *rpipe = kn->kn_fp->f_data; struct pipe *wpipe = rpipe->pipe_peer; PIPE_LOCK(rpipe); if ((wpipe == NULL) || (wpipe->pipe_state & PIPE_EOF)) { kn->kn_data = 0; kn->kn_flags |= EV_EOF; PIPE_UNLOCK(rpipe); return (1); } kn->kn_data = wpipe->pipe_buffer.size - wpipe->pipe_buffer.cnt; if (wpipe->pipe_state & PIPE_DIRECTW) kn->kn_data = 0; PIPE_UNLOCK(rpipe); return (kn->kn_data >= PIPE_BUF); } Index: head/sys/security/mac/mac_framework.c =================================================================== --- head/sys/security/mac/mac_framework.c (revision 125292) +++ head/sys/security/mac/mac_framework.c (revision 125293) @@ -1,1209 +1,1209 @@ /*- * Copyright (c) 1999, 2000, 2001, 2002 Robert N. M. Watson * Copyright (c) 2001 Ilmar S. Habibulin * Copyright (c) 2001, 2002, 2003 Networks Associates Technology, Inc. * All rights reserved. * * This software was developed by Robert Watson and Ilmar Habibulin for the * TrustedBSD Project. * * This software was developed for the FreeBSD Project in part by Network * Associates Laboratories, the Security Research Division of Network * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), * as part of the DARPA CHATS research program. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /*- * Framework for extensible kernel access control. This file contains * Kernel and userland interface to the framework, policy registration * and composition. Per-object interfaces, controls, and labeling may be * found in src/sys/mac/. Sample policies may be found in src/sys/mac*. */ #include __FBSDID("$FreeBSD$"); #include "opt_mac.h" #include "opt_devfs.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef MAC /* * Declare that the kernel provides MAC support, version 1. This permits * modules to refuse to be loaded if the necessary support isn't present, * even if it's pre-boot. */ MODULE_VERSION(kernel_mac_support, 1); SYSCTL_NODE(_security, OID_AUTO, mac, CTLFLAG_RW, 0, "TrustedBSD MAC policy controls"); #if MAC_MAX_SLOTS > 32 #error "MAC_MAX_SLOTS too large" #endif 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, &mac_max_slots, 0, ""); /* * Has the kernel started generating labeled objects yet? All read/write * access to this variable is serialized during the boot process. Following * the end of serialization, we don't update this flag; no locking. */ int mac_late = 0; /* * Flag to indicate whether or not we should allocate label storage for * new mbufs. Since most dynamic policies we currently work with don't * rely on mbuf 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 mbuf labels, it must * be able to deal with a NULL label being returned on any mbufs 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. Note: currently no locking. Will this be a problem? */ #ifndef MAC_ALWAYS_LABEL_MBUF int mac_labelmbufs = 0; #endif #ifdef MAC_DEBUG SYSCTL_NODE(_security_mac, OID_AUTO, debug, CTLFLAG_RW, 0, "TrustedBSD MAC debug info"); SYSCTL_NODE(_security_mac_debug, OID_AUTO, counters, CTLFLAG_RW, 0, "TrustedBSD MAC object counters"); static unsigned int nmactemp; SYSCTL_UINT(_security_mac_debug_counters, OID_AUTO, temp, CTLFLAG_RD, &nmactemp, 0, "number of temporary labels in use"); #endif static int mac_policy_register(struct mac_policy_conf *mpc); static int mac_policy_unregister(struct mac_policy_conf *mpc); MALLOC_DEFINE(M_MACTEMP, "mactemp", "MAC temporary label storage"); /* * mac_static_policy_list holds a list of policy modules that are not * loaded while the system is "live", and cannot be unloaded. These * policies can be invoked without holding the busy count. * * mac_policy_list stores the list of dynamic policies. A busy count is * maintained for the list, stored in mac_policy_busy. The busy count * is protected by mac_policy_mtx; the list may be modified only * while the busy count is 0, requiring that the lock be held to * prevent new references to the list from being acquired. For almost * all operations, incrementing the busy count is sufficient to * guarantee consistency, as the list cannot be modified while the * busy count is elevated. For a few special operations involving a * change to the list of active policies, the mtx itself must be held. * A condition variable, mac_policy_cv, is used to signal potential * exclusive consumers that they should try to acquire the lock if a * first attempt at exclusive access fails. */ static struct mtx mac_policy_mtx; static struct cv mac_policy_cv; static int mac_policy_count; struct mac_policy_list_head mac_policy_list; struct mac_policy_list_head mac_static_policy_list; /* * We manually invoke WITNESS_WARN() to allow Witness to generate * warnings even if we don't end up ever triggering the wait at * run-time. The consumer of the exclusive interface must not hold * any locks (other than potentially Giant) since we may sleep for * long (potentially indefinite) periods of time waiting for the * framework to become quiescent so that a policy list change may * be made. */ void mac_policy_grab_exclusive(void) { WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, "mac_policy_grab_exclusive() at %s:%d", __FILE__, __LINE__); mtx_lock(&mac_policy_mtx); while (mac_policy_count != 0) cv_wait(&mac_policy_cv, &mac_policy_mtx); } void mac_policy_assert_exclusive(void) { mtx_assert(&mac_policy_mtx, MA_OWNED); KASSERT(mac_policy_count == 0, ("mac_policy_assert_exclusive(): not exclusive")); } void mac_policy_release_exclusive(void) { KASSERT(mac_policy_count == 0, ("mac_policy_release_exclusive(): not exclusive")); mtx_unlock(&mac_policy_mtx); cv_signal(&mac_policy_cv); } void mac_policy_list_busy(void) { mtx_lock(&mac_policy_mtx); mac_policy_count++; mtx_unlock(&mac_policy_mtx); } int mac_policy_list_conditional_busy(void) { int ret; mtx_lock(&mac_policy_mtx); if (!LIST_EMPTY(&mac_policy_list)) { mac_policy_count++; ret = 1; } else ret = 0; mtx_unlock(&mac_policy_mtx); return (ret); } void mac_policy_list_unbusy(void) { mtx_lock(&mac_policy_mtx); mac_policy_count--; KASSERT(mac_policy_count >= 0, ("MAC_POLICY_LIST_LOCK")); if (mac_policy_count == 0) cv_signal(&mac_policy_cv); mtx_unlock(&mac_policy_mtx); } /* * Initialize the MAC subsystem, including appropriate SMP locks. */ static void mac_init(void) { LIST_INIT(&mac_static_policy_list); LIST_INIT(&mac_policy_list); mac_labelzone_init(); mtx_init(&mac_policy_mtx, "mac_policy_mtx", NULL, MTX_DEF); cv_init(&mac_policy_cv, "mac_policy_cv"); } /* * For the purposes of modules that want to know if they were loaded * "early", set the mac_late flag once we've processed modules either * linked into the kernel, or loaded before the kernel startup. */ static void mac_late_init(void) { mac_late = 1; } /* * After the policy list has changed, walk the list to update any global * flags. Currently, we support only one flag, and it's conditionally * defined; as a result, the entire function is conditional. Eventually, * the #else case might also iterate across the policies. */ static void mac_policy_updateflags(void) { #ifndef MAC_ALWAYS_LABEL_MBUF struct mac_policy_conf *tmpc; int labelmbufs; mac_policy_assert_exclusive(); labelmbufs = 0; 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 } /* * Allow MAC policy modules to register during boot, etc. */ int mac_policy_modevent(module_t mod, int type, void *data) { struct mac_policy_conf *mpc; int error; error = 0; mpc = (struct mac_policy_conf *) data; switch (type) { case MOD_LOAD: if (mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_NOTLATE && mac_late) { printf("mac_policy_modevent: can't load %s policy " "after booting\n", mpc->mpc_name); error = EBUSY; break; } error = mac_policy_register(mpc); break; case MOD_UNLOAD: /* Don't unregister the module if it was never registered. */ if ((mpc->mpc_runtime_flags & MPC_RUNTIME_FLAG_REGISTERED) != 0) error = mac_policy_unregister(mpc); else error = 0; break; default: break; } return (error); } static int mac_policy_register(struct mac_policy_conf *mpc) { struct mac_policy_conf *tmpc; int error, slot, static_entry; error = 0; /* * We don't technically need exclusive access while !mac_late, * but hold it for assertion consistency. */ mac_policy_grab_exclusive(); /* * If the module can potentially be unloaded, or we're loading * late, we have to stick it in the non-static list and pay * an extra performance overhead. Otherwise, we can pay a * light locking cost and stick it in the static list. */ static_entry = (!mac_late && !(mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_UNLOADOK)); if (static_entry) { LIST_FOREACH(tmpc, &mac_static_policy_list, mpc_list) { if (strcmp(tmpc->mpc_name, mpc->mpc_name) == 0) { error = EEXIST; goto out; } } } else { LIST_FOREACH(tmpc, &mac_policy_list, mpc_list) { if (strcmp(tmpc->mpc_name, mpc->mpc_name) == 0) { error = EEXIST; goto out; } } } if (mpc->mpc_field_off != NULL) { slot = ffs(mac_slot_offsets_free); if (slot == 0) { error = ENOMEM; goto out; } slot--; mac_slot_offsets_free &= ~(1 << slot); *mpc->mpc_field_off = slot; } mpc->mpc_runtime_flags |= MPC_RUNTIME_FLAG_REGISTERED; /* * If we're loading a MAC module after the framework has * initialized, it has to go into the dynamic list. If * we're loading it before we've finished initializing, * it can go into the static list with weaker locker * requirements. */ if (static_entry) LIST_INSERT_HEAD(&mac_static_policy_list, mpc, mpc_list); else LIST_INSERT_HEAD(&mac_policy_list, mpc, mpc_list); /* Per-policy initialization. */ if (mpc->mpc_ops->mpo_init != NULL) (*(mpc->mpc_ops->mpo_init))(mpc); mac_policy_updateflags(); printf("Security policy loaded: %s (%s)\n", mpc->mpc_fullname, mpc->mpc_name); out: mac_policy_release_exclusive(); return (error); } static int mac_policy_unregister(struct mac_policy_conf *mpc) { /* * If we fail the load, we may get a request to unload. Check * to see if we did the run-time registration, and if not, * silently succeed. */ mac_policy_grab_exclusive(); if ((mpc->mpc_runtime_flags & MPC_RUNTIME_FLAG_REGISTERED) == 0) { mac_policy_release_exclusive(); return (0); } #if 0 /* * Don't allow unloading modules with private data. */ if (mpc->mpc_field_off != NULL) { MAC_POLICY_LIST_UNLOCK(); return (EBUSY); } #endif /* * Only allow the unload to proceed if the module is unloadable * by its own definition. */ if ((mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_UNLOADOK) == 0) { mac_policy_release_exclusive(); return (EBUSY); } if (mpc->mpc_ops->mpo_destroy != NULL) (*(mpc->mpc_ops->mpo_destroy))(mpc); LIST_REMOVE(mpc, mpc_list); mpc->mpc_runtime_flags &= ~MPC_RUNTIME_FLAG_REGISTERED; mac_policy_updateflags(); mac_policy_release_exclusive(); printf("Security policy unload: %s (%s)\n", mpc->mpc_fullname, mpc->mpc_name); return (0); } /* * Define an error value precedence, and given two arguments, selects the * value with the higher precedence. */ int mac_error_select(int error1, int error2) { /* Certain decision-making errors take top priority. */ if (error1 == EDEADLK || error2 == EDEADLK) return (EDEADLK); /* Invalid arguments should be reported where possible. */ if (error1 == EINVAL || error2 == EINVAL) return (EINVAL); /* Precedence goes to "visibility", with both process and file. */ if (error1 == ESRCH || error2 == ESRCH) return (ESRCH); if (error1 == ENOENT || error2 == ENOENT) return (ENOENT); /* Precedence goes to DAC/MAC protections. */ if (error1 == EACCES || error2 == EACCES) return (EACCES); /* Precedence goes to privilege. */ if (error1 == EPERM || error2 == EPERM) return (EPERM); /* Precedence goes to error over success; otherwise, arbitrary. */ if (error1 != 0) return (error1); return (error2); } void mac_init_label(struct label *label) { bzero(label, sizeof(*label)); label->l_flags = MAC_FLAG_INITIALIZED; } void mac_destroy_label(struct label *label) { KASSERT(label->l_flags & MAC_FLAG_INITIALIZED, ("destroying uninitialized label")); bzero(label, sizeof(*label)); /* implicit: label->l_flags &= ~MAC_FLAG_INITIALIZED; */ } int mac_check_structmac_consistent(struct mac *mac) { if (mac->m_buflen < 0 || mac->m_buflen > MAC_MAX_LABEL_BUF_LEN) return (EINVAL); return (0); } /* * MPSAFE */ int __mac_get_pid(struct thread *td, struct __mac_get_pid_args *uap) { char *elements, *buffer; struct mac mac; struct proc *tproc; struct ucred *tcred; int error; error = copyin(uap->mac_p, &mac, sizeof(mac)); if (error) return (error); error = mac_check_structmac_consistent(&mac); if (error) return (error); tproc = pfind(uap->pid); if (tproc == NULL) return (ESRCH); tcred = NULL; /* Satisfy gcc. */ error = p_cansee(td, tproc); if (error == 0) tcred = crhold(tproc->p_ucred); PROC_UNLOCK(tproc); if (error) return (error); elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL); if (error) { free(elements, M_MACTEMP); crfree(tcred); return (error); } buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); error = mac_externalize_cred_label(tcred->cr_label, elements, buffer, mac.m_buflen); if (error == 0) error = copyout(buffer, mac.m_string, strlen(buffer)+1); free(buffer, M_MACTEMP); free(elements, M_MACTEMP); crfree(tcred); return (error); } /* * MPSAFE */ int __mac_get_proc(struct thread *td, struct __mac_get_proc_args *uap) { char *elements, *buffer; struct mac mac; int error; error = copyin(uap->mac_p, &mac, sizeof(mac)); if (error) return (error); error = mac_check_structmac_consistent(&mac); if (error) return (error); elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL); if (error) { free(elements, M_MACTEMP); return (error); } buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); error = mac_externalize_cred_label(td->td_ucred->cr_label, elements, buffer, mac.m_buflen); if (error == 0) error = copyout(buffer, mac.m_string, strlen(buffer)+1); free(buffer, M_MACTEMP); free(elements, M_MACTEMP); return (error); } /* * MPSAFE */ int __mac_set_proc(struct thread *td, struct __mac_set_proc_args *uap) { struct ucred *newcred, *oldcred; struct label *intlabel; struct proc *p; struct mac mac; char *buffer; int error; error = copyin(uap->mac_p, &mac, sizeof(mac)); if (error) return (error); error = mac_check_structmac_consistent(&mac); if (error) return (error); buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL); if (error) { free(buffer, M_MACTEMP); return (error); } intlabel = mac_cred_label_alloc(); error = mac_internalize_cred_label(intlabel, buffer); free(buffer, M_MACTEMP); if (error) goto out; newcred = crget(); p = td->td_proc; PROC_LOCK(p); oldcred = p->p_ucred; error = mac_check_cred_relabel(oldcred, intlabel); if (error) { PROC_UNLOCK(p); crfree(newcred); goto out; } setsugid(p); crcopy(newcred, oldcred); mac_relabel_cred(newcred, intlabel); p->p_ucred = newcred; /* * Grab additional reference for use while revoking mmaps, prior * to releasing the proc lock and sharing the cred. */ crhold(newcred); PROC_UNLOCK(p); if (mac_enforce_vm) { mtx_lock(&Giant); mac_cred_mmapped_drop_perms(td, newcred); mtx_unlock(&Giant); } crfree(newcred); /* Free revocation reference. */ crfree(oldcred); out: mac_cred_label_free(intlabel); return (error); } /* * MPSAFE */ int __mac_get_fd(struct thread *td, struct __mac_get_fd_args *uap) { char *elements, *buffer; struct label *intlabel; struct file *fp; struct mac mac; struct vnode *vp; struct pipe *pipe; struct socket *so; short label_type; int error; error = copyin(uap->mac_p, &mac, sizeof(mac)); if (error) return (error); error = mac_check_structmac_consistent(&mac); if (error) return (error); elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL); if (error) { free(elements, M_MACTEMP); return (error); } buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); error = fget(td, uap->fd, &fp); if (error) goto out; label_type = fp->f_type; switch (fp->f_type) { case DTYPE_FIFO: case DTYPE_VNODE: vp = fp->f_vnode; intlabel = mac_vnode_label_alloc(); mtx_lock(&Giant); /* VFS */ vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); mac_copy_vnode_label(vp->v_label, intlabel); VOP_UNLOCK(vp, 0, td); mtx_unlock(&Giant); /* VFS */ error = mac_externalize_vnode_label(intlabel, elements, buffer, mac.m_buflen); mac_vnode_label_free(intlabel); break; case DTYPE_PIPE: pipe = fp->f_data; intlabel = mac_pipe_label_alloc(); PIPE_LOCK(pipe); - mac_copy_pipe_label(pipe->pipe_label, intlabel); + mac_copy_pipe_label(pipe->pipe_pair->pp_label, intlabel); PIPE_UNLOCK(pipe); error = mac_externalize_pipe_label(intlabel, elements, buffer, mac.m_buflen); mac_pipe_label_free(intlabel); break; case DTYPE_SOCKET: so = fp->f_data; intlabel = mac_socket_label_alloc(M_WAITOK); mtx_lock(&Giant); /* Sockets */ /* XXX: Socket lock here. */ mac_copy_socket_label(so->so_label, intlabel); /* XXX: Socket unlock here. */ mtx_unlock(&Giant); /* Sockets */ error = mac_externalize_socket_label(intlabel, elements, buffer, mac.m_buflen); mac_socket_label_free(intlabel); break; default: error = EINVAL; } fdrop(fp, td); if (error == 0) error = copyout(buffer, mac.m_string, strlen(buffer)+1); out: free(buffer, M_MACTEMP); free(elements, M_MACTEMP); return (error); } /* * MPSAFE */ int __mac_get_file(struct thread *td, struct __mac_get_file_args *uap) { char *elements, *buffer; struct nameidata nd; struct label *intlabel; struct mac mac; int error; error = copyin(uap->mac_p, &mac, sizeof(mac)); if (error) return (error); error = mac_check_structmac_consistent(&mac); if (error) return (error); elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL); if (error) { free(elements, M_MACTEMP); return (error); } buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); mtx_lock(&Giant); /* VFS */ NDINIT(&nd, LOOKUP, LOCKLEAF | FOLLOW, UIO_USERSPACE, uap->path_p, td); error = namei(&nd); if (error) goto out; intlabel = mac_vnode_label_alloc(); mac_copy_vnode_label(nd.ni_vp->v_label, intlabel); error = mac_externalize_vnode_label(intlabel, elements, buffer, mac.m_buflen); NDFREE(&nd, 0); mac_vnode_label_free(intlabel); if (error == 0) error = copyout(buffer, mac.m_string, strlen(buffer)+1); out: mtx_unlock(&Giant); /* VFS */ free(buffer, M_MACTEMP); free(elements, M_MACTEMP); return (error); } /* * MPSAFE */ int __mac_get_link(struct thread *td, struct __mac_get_link_args *uap) { char *elements, *buffer; struct nameidata nd; struct label *intlabel; struct mac mac; int error; error = copyin(uap->mac_p, &mac, sizeof(mac)); if (error) return (error); error = mac_check_structmac_consistent(&mac); if (error) return (error); elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL); if (error) { free(elements, M_MACTEMP); return (error); } buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); mtx_lock(&Giant); /* VFS */ NDINIT(&nd, LOOKUP, LOCKLEAF | NOFOLLOW, UIO_USERSPACE, uap->path_p, td); error = namei(&nd); if (error) goto out; intlabel = mac_vnode_label_alloc(); mac_copy_vnode_label(nd.ni_vp->v_label, intlabel); error = mac_externalize_vnode_label(intlabel, elements, buffer, mac.m_buflen); NDFREE(&nd, 0); mac_vnode_label_free(intlabel); if (error == 0) error = copyout(buffer, mac.m_string, strlen(buffer)+1); out: mtx_unlock(&Giant); /* VFS */ free(buffer, M_MACTEMP); free(elements, M_MACTEMP); return (error); } /* * MPSAFE */ int __mac_set_fd(struct thread *td, struct __mac_set_fd_args *uap) { struct label *intlabel; struct pipe *pipe; struct socket *so; struct file *fp; struct mount *mp; struct vnode *vp; struct mac mac; char *buffer; int error; error = copyin(uap->mac_p, &mac, sizeof(mac)); if (error) return (error); error = mac_check_structmac_consistent(&mac); if (error) return (error); buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL); if (error) { free(buffer, M_MACTEMP); return (error); } error = fget(td, uap->fd, &fp); if (error) goto out; switch (fp->f_type) { case DTYPE_FIFO: case DTYPE_VNODE: intlabel = mac_vnode_label_alloc(); error = mac_internalize_vnode_label(intlabel, buffer); if (error) { mac_vnode_label_free(intlabel); break; } vp = fp->f_vnode; mtx_lock(&Giant); /* VFS */ error = vn_start_write(vp, &mp, V_WAIT | PCATCH); if (error != 0) { mtx_unlock(&Giant); /* VFS */ mac_vnode_label_free(intlabel); break; } vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); error = vn_setlabel(vp, intlabel, td->td_ucred); VOP_UNLOCK(vp, 0, td); vn_finished_write(mp); mtx_unlock(&Giant); /* VFS */ mac_vnode_label_free(intlabel); break; case DTYPE_PIPE: intlabel = mac_pipe_label_alloc(); error = mac_internalize_pipe_label(intlabel, buffer); if (error == 0) { pipe = fp->f_data; PIPE_LOCK(pipe); - error = mac_pipe_label_set(td->td_ucred, pipe, - intlabel); + error = mac_pipe_label_set(td->td_ucred, + pipe->pipe_pair, intlabel); PIPE_UNLOCK(pipe); } mac_pipe_label_free(intlabel); break; case DTYPE_SOCKET: intlabel = mac_socket_label_alloc(M_WAITOK); error = mac_internalize_socket_label(intlabel, buffer); if (error == 0) { so = fp->f_data; mtx_lock(&Giant); /* Sockets */ /* XXX: Socket lock here. */ error = mac_socket_label_set(td->td_ucred, so, intlabel); /* XXX: Socket unlock here. */ mtx_unlock(&Giant); /* Sockets */ } mac_socket_label_free(intlabel); break; default: error = EINVAL; } fdrop(fp, td); out: free(buffer, M_MACTEMP); return (error); } /* * MPSAFE */ int __mac_set_file(struct thread *td, struct __mac_set_file_args *uap) { struct label *intlabel; struct nameidata nd; struct mount *mp; struct mac mac; char *buffer; int error; error = copyin(uap->mac_p, &mac, sizeof(mac)); if (error) return (error); error = mac_check_structmac_consistent(&mac); if (error) return (error); buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL); if (error) { free(buffer, M_MACTEMP); return (error); } intlabel = mac_vnode_label_alloc(); error = mac_internalize_vnode_label(intlabel, buffer); free(buffer, M_MACTEMP); if (error) goto out; mtx_lock(&Giant); /* VFS */ NDINIT(&nd, LOOKUP, LOCKLEAF | FOLLOW, UIO_USERSPACE, uap->path_p, td); error = namei(&nd); if (error == 0) { error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH); if (error == 0) error = vn_setlabel(nd.ni_vp, intlabel, td->td_ucred); vn_finished_write(mp); } NDFREE(&nd, 0); mtx_unlock(&Giant); /* VFS */ out: mac_vnode_label_free(intlabel); return (error); } /* * MPSAFE */ int __mac_set_link(struct thread *td, struct __mac_set_link_args *uap) { struct label *intlabel; struct nameidata nd; struct mount *mp; struct mac mac; char *buffer; int error; error = copyin(uap->mac_p, &mac, sizeof(mac)); if (error) return (error); error = mac_check_structmac_consistent(&mac); if (error) return (error); buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL); if (error) { free(buffer, M_MACTEMP); return (error); } intlabel = mac_vnode_label_alloc(); error = mac_internalize_vnode_label(intlabel, buffer); free(buffer, M_MACTEMP); if (error) goto out; mtx_lock(&Giant); /* VFS */ NDINIT(&nd, LOOKUP, LOCKLEAF | NOFOLLOW, UIO_USERSPACE, uap->path_p, td); error = namei(&nd); if (error == 0) { error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH); if (error == 0) error = vn_setlabel(nd.ni_vp, intlabel, td->td_ucred); vn_finished_write(mp); } NDFREE(&nd, 0); mtx_unlock(&Giant); /* VFS */ out: mac_vnode_label_free(intlabel); return (error); } /* * MPSAFE */ int mac_syscall(struct thread *td, struct mac_syscall_args *uap) { struct mac_policy_conf *mpc; char target[MAC_MAX_POLICY_NAME]; int entrycount, error; error = copyinstr(uap->policy, target, sizeof(target), NULL); if (error) return (error); error = ENOSYS; LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) { if (strcmp(mpc->mpc_name, target) == 0 && mpc->mpc_ops->mpo_syscall != NULL) { error = mpc->mpc_ops->mpo_syscall(td, uap->call, uap->arg); goto out; } } if ((entrycount = mac_policy_list_conditional_busy()) != 0) { LIST_FOREACH(mpc, &mac_policy_list, mpc_list) { if (strcmp(mpc->mpc_name, target) == 0 && mpc->mpc_ops->mpo_syscall != NULL) { error = mpc->mpc_ops->mpo_syscall(td, uap->call, uap->arg); break; } } mac_policy_list_unbusy(); } out: return (error); } SYSINIT(mac, SI_SUB_MAC, SI_ORDER_FIRST, mac_init, NULL); SYSINIT(mac_late, SI_SUB_MAC_LATE, SI_ORDER_FIRST, mac_late_init, NULL); #else /* !MAC */ int __mac_get_pid(struct thread *td, struct __mac_get_pid_args *uap) { return (ENOSYS); } int __mac_get_proc(struct thread *td, struct __mac_get_proc_args *uap) { return (ENOSYS); } int __mac_set_proc(struct thread *td, struct __mac_set_proc_args *uap) { return (ENOSYS); } int __mac_get_fd(struct thread *td, struct __mac_get_fd_args *uap) { return (ENOSYS); } int __mac_get_file(struct thread *td, struct __mac_get_file_args *uap) { return (ENOSYS); } int __mac_get_link(struct thread *td, struct __mac_get_link_args *uap) { return (ENOSYS); } int __mac_set_fd(struct thread *td, struct __mac_set_fd_args *uap) { return (ENOSYS); } int __mac_set_file(struct thread *td, struct __mac_set_file_args *uap) { return (ENOSYS); } int __mac_set_link(struct thread *td, struct __mac_set_link_args *uap) { return (ENOSYS); } int mac_syscall(struct thread *td, struct mac_syscall_args *uap) { return (ENOSYS); } #endif Index: head/sys/security/mac/mac_framework.h =================================================================== --- head/sys/security/mac/mac_framework.h (revision 125292) +++ head/sys/security/mac/mac_framework.h (revision 125293) @@ -1,366 +1,366 @@ /*- * Copyright (c) 1999, 2000, 2001, 2002 Robert N. M. Watson * Copyright (c) 2001, 2002, 2003 Networks Associates Technology, Inc. * All rights reserved. * * This software was developed by Robert Watson for the TrustedBSD Project. * * This software was developed for the FreeBSD Project in part by Network * Associates Laboratories, the Security Research Division of Network * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), * as part of the DARPA CHATS research program. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ /* * Userland/kernel interface for Mandatory Access Control. * * The POSIX.1e implementation page may be reached at: * http://www.trustedbsd.org/ */ #ifndef _SYS_MAC_H #define _SYS_MAC_H #include #ifndef _POSIX_MAC #define _POSIX_MAC #endif /* * MAC framework-related constants and limits. */ #define MAC_MAX_POLICY_NAME 32 #define MAC_MAX_LABEL_ELEMENT_NAME 32 #define MAC_MAX_LABEL_ELEMENT_DATA 4096 #define MAC_MAX_LABEL_BUF_LEN 8192 struct mac { size_t m_buflen; char *m_string; }; typedef struct mac *mac_t; #ifndef _KERNEL /* * Location of the userland MAC framework configuration file. mac.conf * binds policy names to shared libraries that understand those policies, * as well as setting defaults for MAC-aware applications. */ #define MAC_CONFFILE "/etc/mac.conf" /* * Extended non-POSIX.1e interfaces that offer additional services * available from the userland and kernel MAC frameworks. */ __BEGIN_DECLS int mac_execve(char *fname, char **argv, char **envv, mac_t _label); int mac_free(mac_t _label); int mac_from_text(mac_t *_label, const char *_text); int mac_get_fd(int _fd, mac_t _label); int mac_get_file(const char *_path, mac_t _label); int mac_get_link(const char *_path, mac_t _label); int mac_get_peer(int _fd, mac_t _label); int mac_get_pid(pid_t _pid, mac_t _label); int mac_get_proc(mac_t _label); int mac_is_present(const char *_policyname); int mac_prepare(mac_t *_label, const char *_elements); int mac_prepare_file_label(mac_t *_label); int mac_prepare_ifnet_label(mac_t *_label); int mac_prepare_process_label(mac_t *_label); int mac_prepare_type(mac_t *_label, const char *_type); int mac_set_fd(int _fildes, const mac_t _label); int mac_set_file(const char *_path, mac_t _label); int mac_set_link(const char *_path, mac_t _label); int mac_set_proc(const mac_t _label); int mac_syscall(const char *_policyname, int _call, void *_arg); int mac_to_text(mac_t mac, char **_text); __END_DECLS #else /* _KERNEL */ /* * Kernel functions to manage and evaluate labels. */ struct bpf_d; struct componentname; struct devfs_dirent; struct ifnet; struct ifreq; struct inpcb; struct image_params; struct inpcb; struct ipq; struct m_tag; struct mbuf; struct mount; struct proc; struct sockaddr; struct socket; -struct pipe; +struct pipepair; struct thread; struct timespec; struct ucred; struct uio; struct vattr; struct vnode; #include /* XXX acl_type_t */ struct vop_setlabel_args; /* * Label operations. */ void mac_init_bpfdesc(struct bpf_d *); void mac_init_cred(struct ucred *); void mac_init_devfsdirent(struct devfs_dirent *); void mac_init_ifnet(struct ifnet *); int mac_init_inpcb(struct inpcb *, int flag); int mac_init_ipq(struct ipq *, int flag); int mac_init_socket(struct socket *, int flag); -void mac_init_pipe(struct pipe *); +void mac_init_pipe(struct pipepair *); int mac_init_mbuf(struct mbuf *mbuf, int flag); int mac_init_mbuf_tag(struct m_tag *, int flag); void mac_init_mount(struct mount *); void mac_init_proc(struct proc *); void mac_init_vnode(struct vnode *); void mac_copy_mbuf_tag(struct m_tag *, struct m_tag *); void mac_copy_vnode_label(struct label *, struct label *label); void mac_destroy_bpfdesc(struct bpf_d *); void mac_destroy_cred(struct ucred *); void mac_destroy_devfsdirent(struct devfs_dirent *); void mac_destroy_ifnet(struct ifnet *); void mac_destroy_inpcb(struct inpcb *); void mac_destroy_ipq(struct ipq *); void mac_destroy_socket(struct socket *); -void mac_destroy_pipe(struct pipe *); +void mac_destroy_pipe(struct pipepair *); void mac_destroy_proc(struct proc *); void mac_destroy_mbuf_tag(struct m_tag *); void mac_destroy_mount(struct mount *); void mac_destroy_vnode(struct vnode *); struct label *mac_cred_label_alloc(void); void mac_cred_label_free(struct label *label); struct label *mac_vnode_label_alloc(void); void mac_vnode_label_free(struct label *label); /* * Labeling event operations: file system objects, and things that * look a lot like file system objects. */ void mac_associate_vnode_devfs(struct mount *mp, struct devfs_dirent *de, struct vnode *vp); int mac_associate_vnode_extattr(struct mount *mp, struct vnode *vp); void mac_associate_vnode_singlelabel(struct mount *mp, struct vnode *vp); void mac_create_devfs_device(struct mount *mp, dev_t dev, struct devfs_dirent *de); void mac_create_devfs_directory(struct mount *mp, char *dirname, int dirnamelen, struct devfs_dirent *de); void mac_create_devfs_symlink(struct ucred *cred, struct mount *mp, struct devfs_dirent *dd, struct devfs_dirent *de); int mac_create_vnode_extattr(struct ucred *cred, struct mount *mp, struct vnode *dvp, struct vnode *vp, struct componentname *cnp); void mac_create_mount(struct ucred *cred, struct mount *mp); void mac_create_root_mount(struct ucred *cred, struct mount *mp); void mac_relabel_vnode(struct ucred *cred, struct vnode *vp, struct label *newlabel); void mac_update_devfsdirent(struct mount *mp, struct devfs_dirent *de, struct vnode *vp); /* * Labeling event operations: IPC objects. */ void mac_create_mbuf_from_socket(struct socket *so, struct mbuf *m); void mac_create_socket(struct ucred *cred, struct socket *socket); void mac_create_socket_from_socket(struct socket *oldsocket, struct socket *newsocket); void mac_set_socket_peer_from_mbuf(struct mbuf *mbuf, struct socket *socket); void mac_set_socket_peer_from_socket(struct socket *oldsocket, struct socket *newsocket); -void mac_create_pipe(struct ucred *cred, struct pipe *pipe); +void mac_create_pipe(struct ucred *cred, struct pipepair *pp); /* * Labeling event operations: network objects. */ void mac_create_bpfdesc(struct ucred *cred, struct bpf_d *bpf_d); void mac_create_ifnet(struct ifnet *ifp); void mac_create_inpcb_from_socket(struct socket *so, struct inpcb *inp); void mac_create_ipq(struct mbuf *fragment, struct ipq *ipq); void mac_create_datagram_from_ipq(struct ipq *ipq, struct mbuf *datagram); void mac_create_fragment(struct mbuf *datagram, struct mbuf *fragment); void mac_create_mbuf_from_inpcb(struct inpcb *inp, struct mbuf *m); void mac_create_mbuf_from_mbuf(struct mbuf *oldmbuf, struct mbuf *newmbuf); void mac_create_mbuf_linklayer(struct ifnet *ifnet, struct mbuf *m); void mac_create_mbuf_from_bpfdesc(struct bpf_d *bpf_d, struct mbuf *m); void mac_create_mbuf_from_ifnet(struct ifnet *ifnet, struct mbuf *m); void mac_create_mbuf_multicast_encap(struct mbuf *oldmbuf, struct ifnet *ifnet, struct mbuf *newmbuf); void mac_create_mbuf_netlayer(struct mbuf *oldmbuf, struct mbuf *newmbuf); int mac_fragment_match(struct mbuf *fragment, struct ipq *ipq); void mac_reflect_mbuf_icmp(struct mbuf *m); void mac_reflect_mbuf_tcp(struct mbuf *m); void mac_update_ipq(struct mbuf *fragment, struct ipq *ipq); void mac_inpcb_sosetlabel(struct socket *so, struct inpcb *inp); /* * Labeling event operations: processes. */ void mac_copy_cred(struct ucred *cr1, struct ucred *cr2); int mac_execve_enter(struct image_params *imgp, struct mac *mac_p); void mac_execve_exit(struct image_params *imgp); void mac_execve_transition(struct ucred *old, struct ucred *new, struct vnode *vp, struct label *interpvnodelabel, struct image_params *imgp); int mac_execve_will_transition(struct ucred *old, struct vnode *vp, struct label *interpvnodelabel, struct image_params *imgp); void mac_create_proc0(struct ucred *cred); void mac_create_proc1(struct ucred *cred); void mac_thread_userret(struct thread *td); /* Access control checks. */ int mac_check_bpfdesc_receive(struct bpf_d *bpf_d, struct ifnet *ifnet); int mac_check_cred_visible(struct ucred *u1, struct ucred *u2); int mac_check_ifnet_transmit(struct ifnet *ifnet, struct mbuf *m); int mac_check_inpcb_deliver(struct inpcb *inp, struct mbuf *m); int mac_check_kenv_dump(struct ucred *cred); int mac_check_kenv_get(struct ucred *cred, char *name); int mac_check_kenv_set(struct ucred *cred, char *name, char *value); int mac_check_kenv_unset(struct ucred *cred, char *name); int mac_check_kld_load(struct ucred *cred, struct vnode *vp); int mac_check_kld_stat(struct ucred *cred); int mac_check_kld_unload(struct ucred *cred); int mac_check_mount_stat(struct ucred *cred, struct mount *mp); -int mac_check_pipe_ioctl(struct ucred *cred, struct pipe *pipe, +int mac_check_pipe_ioctl(struct ucred *cred, struct pipepair *pp, unsigned long cmd, void *data); -int mac_check_pipe_poll(struct ucred *cred, struct pipe *pipe); -int mac_check_pipe_read(struct ucred *cred, struct pipe *pipe); -int mac_check_pipe_stat(struct ucred *cred, struct pipe *pipe); -int mac_check_pipe_write(struct ucred *cred, struct pipe *pipe); +int mac_check_pipe_poll(struct ucred *cred, struct pipepair *pp); +int mac_check_pipe_read(struct ucred *cred, struct pipepair *pp); +int mac_check_pipe_stat(struct ucred *cred, struct pipepair *pp); +int mac_check_pipe_write(struct ucred *cred, struct pipepair *pp); int mac_check_proc_debug(struct ucred *cred, struct proc *proc); int mac_check_proc_sched(struct ucred *cred, struct proc *proc); int mac_check_proc_signal(struct ucred *cred, struct proc *proc, int signum); int mac_check_socket_bind(struct ucred *cred, struct socket *so, struct sockaddr *sockaddr); int mac_check_socket_connect(struct ucred *cred, struct socket *so, struct sockaddr *sockaddr); int mac_check_socket_deliver(struct socket *so, struct mbuf *m); int mac_check_socket_listen(struct ucred *cred, struct socket *so); int mac_check_socket_receive(struct ucred *cred, struct socket *so); int mac_check_socket_send(struct ucred *cred, struct socket *so); int mac_check_socket_visible(struct ucred *cred, struct socket *so); int mac_check_sysarch_ioperm(struct ucred *cred); int mac_check_system_acct(struct ucred *cred, struct vnode *vp); int mac_check_system_nfsd(struct ucred *cred); int mac_check_system_reboot(struct ucred *cred, int howto); int mac_check_system_settime(struct ucred *cred); int mac_check_system_swapon(struct ucred *cred, struct vnode *vp); int mac_check_system_swapoff(struct ucred *cred, struct vnode *vp); int mac_check_system_sysctl(struct ucred *cred, int *name, u_int namelen, void *old, size_t *oldlenp, int inkernel, void *new, size_t newlen); int mac_check_vnode_access(struct ucred *cred, struct vnode *vp, int acc_mode); int mac_check_vnode_chdir(struct ucred *cred, struct vnode *dvp); int mac_check_vnode_chroot(struct ucred *cred, struct vnode *dvp); int mac_check_vnode_create(struct ucred *cred, struct vnode *dvp, struct componentname *cnp, struct vattr *vap); int mac_check_vnode_delete(struct ucred *cred, struct vnode *dvp, struct vnode *vp, struct componentname *cnp); int mac_check_vnode_deleteacl(struct ucred *cred, struct vnode *vp, acl_type_t type); int mac_check_vnode_deleteextattr(struct ucred *cred, struct vnode *vp, int attrnamespace, const char *name); int mac_check_vnode_exec(struct ucred *cred, struct vnode *vp, struct image_params *imgp); int mac_check_vnode_getacl(struct ucred *cred, struct vnode *vp, acl_type_t type); int mac_check_vnode_getextattr(struct ucred *cred, struct vnode *vp, int attrnamespace, const char *name, struct uio *uio); int mac_check_vnode_link(struct ucred *cred, struct vnode *dvp, struct vnode *vp, struct componentname *cnp); int mac_check_vnode_listextattr(struct ucred *cred, struct vnode *vp, int attrnamespace); int mac_check_vnode_lookup(struct ucred *cred, struct vnode *dvp, struct componentname *cnp); int mac_check_vnode_mmap(struct ucred *cred, struct vnode *vp, int prot); int mac_check_vnode_mprotect(struct ucred *cred, struct vnode *vp, int prot); int mac_check_vnode_open(struct ucred *cred, struct vnode *vp, int acc_mode); int mac_check_vnode_poll(struct ucred *active_cred, struct ucred *file_cred, struct vnode *vp); int mac_check_vnode_read(struct ucred *active_cred, struct ucred *file_cred, struct vnode *vp); int mac_check_vnode_readdir(struct ucred *cred, struct vnode *vp); int mac_check_vnode_readlink(struct ucred *cred, struct vnode *vp); int mac_check_vnode_rename_from(struct ucred *cred, struct vnode *dvp, struct vnode *vp, struct componentname *cnp); int mac_check_vnode_rename_to(struct ucred *cred, struct vnode *dvp, struct vnode *vp, int samedir, struct componentname *cnp); int mac_check_vnode_revoke(struct ucred *cred, struct vnode *vp); int mac_check_vnode_setacl(struct ucred *cred, struct vnode *vp, acl_type_t type, struct acl *acl); int mac_check_vnode_setextattr(struct ucred *cred, struct vnode *vp, int attrnamespace, const char *name, struct uio *uio); int mac_check_vnode_setflags(struct ucred *cred, struct vnode *vp, u_long flags); int mac_check_vnode_setmode(struct ucred *cred, struct vnode *vp, mode_t mode); int mac_check_vnode_setowner(struct ucred *cred, struct vnode *vp, uid_t uid, gid_t gid); int mac_check_vnode_setutimes(struct ucred *cred, struct vnode *vp, struct timespec atime, struct timespec mtime); int mac_check_vnode_stat(struct ucred *active_cred, struct ucred *file_cred, struct vnode *vp); int mac_check_vnode_write(struct ucred *active_cred, struct ucred *file_cred, struct vnode *vp); int mac_getsockopt_label(struct ucred *cred, struct socket *so, struct mac *extmac); int mac_getsockopt_peerlabel(struct ucred *cred, struct socket *so, struct mac *extmac); int mac_ioctl_ifnet_get(struct ucred *cred, struct ifreq *ifr, struct ifnet *ifnet); int mac_ioctl_ifnet_set(struct ucred *cred, struct ifreq *ifr, struct ifnet *ifnet); int mac_setsockopt_label(struct ucred *cred, struct socket *so, struct mac *extmac); -int mac_pipe_label_set(struct ucred *cred, struct pipe *pipe, +int mac_pipe_label_set(struct ucred *cred, struct pipepair *pp, struct label *label); void mac_cred_mmapped_drop_perms(struct thread *td, struct ucred *cred); /* * Calls to help various file systems implement labeling functionality * using their existing EA implementation. */ int vop_stdsetlabel_ea(struct vop_setlabel_args *ap); #endif /* !_KERNEL */ #endif /* !_SYS_MAC_H */ Index: head/sys/security/mac/mac_pipe.c =================================================================== --- head/sys/security/mac/mac_pipe.c (revision 125292) +++ head/sys/security/mac/mac_pipe.c (revision 125293) @@ -1,248 +1,249 @@ /*- * Copyright (c) 2002, 2003 Networks Associates Technology, Inc. * All rights reserved. * * This software was developed for the FreeBSD Project in part by Network * Associates Laboratories, the Security Research Division of Network * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), * as part of the DARPA CHATS research program. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include "opt_mac.h" #include #include #include #include #include #include #include #include #include #include #include #include #include static int mac_enforce_pipe = 1; SYSCTL_INT(_security_mac, OID_AUTO, enforce_pipe, CTLFLAG_RW, &mac_enforce_pipe, 0, "Enforce MAC policy on pipe operations"); TUNABLE_INT("security.mac.enforce_pipe", &mac_enforce_pipe); #ifdef MAC_DEBUG static unsigned int nmacpipes; SYSCTL_UINT(_security_mac_debug_counters, OID_AUTO, pipes, CTLFLAG_RD, &nmacpipes, 0, "number of pipes in use"); #endif struct label * mac_pipe_label_alloc(void) { struct label *label; label = mac_labelzone_alloc(M_WAITOK); MAC_PERFORM(init_pipe_label, label); MAC_DEBUG_COUNTER_INC(&nmacpipes); return (label); } void -mac_init_pipe(struct pipe *pipe) +mac_init_pipe(struct pipepair *pp) { - pipe->pipe_label = pipe->pipe_peer->pipe_label = - mac_pipe_label_alloc(); + pp->pp_label = mac_pipe_label_alloc(); } void mac_pipe_label_free(struct label *label) { MAC_PERFORM(destroy_pipe_label, label); mac_labelzone_free(label); MAC_DEBUG_COUNTER_DEC(&nmacpipes); } void -mac_destroy_pipe(struct pipe *pipe) +mac_destroy_pipe(struct pipepair *pp) { - mac_pipe_label_free(pipe->pipe_label); - pipe->pipe_label = NULL; + mac_pipe_label_free(pp->pp_label); + pp->pp_label = NULL; } void mac_copy_pipe_label(struct label *src, struct label *dest) { MAC_PERFORM(copy_pipe_label, src, dest); } int mac_externalize_pipe_label(struct label *label, char *elements, char *outbuf, size_t outbuflen) { int error; MAC_EXTERNALIZE(pipe, label, elements, outbuf, outbuflen); return (error); } int mac_internalize_pipe_label(struct label *label, char *string) { int error; MAC_INTERNALIZE(pipe, label, string); return (error); } void -mac_create_pipe(struct ucred *cred, struct pipe *pipe) +mac_create_pipe(struct ucred *cred, struct pipepair *pp) { - MAC_PERFORM(create_pipe, cred, pipe, pipe->pipe_label); + MAC_PERFORM(create_pipe, cred, pp, pp->pp_label); } static void -mac_relabel_pipe(struct ucred *cred, struct pipe *pipe, struct label *newlabel) +mac_relabel_pipe(struct ucred *cred, struct pipepair *pp, + struct label *newlabel) { - MAC_PERFORM(relabel_pipe, cred, pipe, pipe->pipe_label, newlabel); + MAC_PERFORM(relabel_pipe, cred, pp, pp->pp_label, newlabel); } int -mac_check_pipe_ioctl(struct ucred *cred, struct pipe *pipe, unsigned long cmd, - void *data) +mac_check_pipe_ioctl(struct ucred *cred, struct pipepair *pp, + unsigned long cmd, void *data) { int error; - PIPE_LOCK_ASSERT(pipe, MA_OWNED); + mtx_assert(&pp->pp_mtx, MA_OWNED); if (!mac_enforce_pipe) return (0); - MAC_CHECK(check_pipe_ioctl, cred, pipe, pipe->pipe_label, cmd, data); + MAC_CHECK(check_pipe_ioctl, cred, pp, pp->pp_label, cmd, data); return (error); } int -mac_check_pipe_poll(struct ucred *cred, struct pipe *pipe) +mac_check_pipe_poll(struct ucred *cred, struct pipepair *pp) { int error; - PIPE_LOCK_ASSERT(pipe, MA_OWNED); + mtx_assert(&pp->pp_mtx, MA_OWNED); if (!mac_enforce_pipe) return (0); - MAC_CHECK(check_pipe_poll, cred, pipe, pipe->pipe_label); + MAC_CHECK(check_pipe_poll, cred, pp, pp->pp_label); return (error); } int -mac_check_pipe_read(struct ucred *cred, struct pipe *pipe) +mac_check_pipe_read(struct ucred *cred, struct pipepair *pp) { int error; - PIPE_LOCK_ASSERT(pipe, MA_OWNED); + mtx_assert(&pp->pp_mtx, MA_OWNED); if (!mac_enforce_pipe) return (0); - MAC_CHECK(check_pipe_read, cred, pipe, pipe->pipe_label); + MAC_CHECK(check_pipe_read, cred, pp, pp->pp_label); return (error); } static int -mac_check_pipe_relabel(struct ucred *cred, struct pipe *pipe, +mac_check_pipe_relabel(struct ucred *cred, struct pipepair *pp, struct label *newlabel) { int error; - PIPE_LOCK_ASSERT(pipe, MA_OWNED); + mtx_assert(&pp->pp_mtx, MA_OWNED); if (!mac_enforce_pipe) return (0); - MAC_CHECK(check_pipe_relabel, cred, pipe, pipe->pipe_label, newlabel); + MAC_CHECK(check_pipe_relabel, cred, pp, pp->pp_label, newlabel); return (error); } int -mac_check_pipe_stat(struct ucred *cred, struct pipe *pipe) +mac_check_pipe_stat(struct ucred *cred, struct pipepair *pp) { int error; - PIPE_LOCK_ASSERT(pipe, MA_OWNED); + mtx_assert(&pp->pp_mtx, MA_OWNED); if (!mac_enforce_pipe) return (0); - MAC_CHECK(check_pipe_stat, cred, pipe, pipe->pipe_label); + MAC_CHECK(check_pipe_stat, cred, pp, pp->pp_label); return (error); } int -mac_check_pipe_write(struct ucred *cred, struct pipe *pipe) +mac_check_pipe_write(struct ucred *cred, struct pipepair *pp) { int error; - PIPE_LOCK_ASSERT(pipe, MA_OWNED); + mtx_assert(&pp->pp_mtx, MA_OWNED); if (!mac_enforce_pipe) return (0); - MAC_CHECK(check_pipe_write, cred, pipe, pipe->pipe_label); + MAC_CHECK(check_pipe_write, cred, pp, pp->pp_label); return (error); } int -mac_pipe_label_set(struct ucred *cred, struct pipe *pipe, struct label *label) +mac_pipe_label_set(struct ucred *cred, struct pipepair *pp, + struct label *label) { int error; - PIPE_LOCK_ASSERT(pipe, MA_OWNED); + mtx_assert(&pp->pp_mtx, MA_OWNED); - error = mac_check_pipe_relabel(cred, pipe, label); + error = mac_check_pipe_relabel(cred, pp, label); if (error) return (error); - mac_relabel_pipe(cred, pipe, label); + mac_relabel_pipe(cred, pp, label); return (0); } Index: head/sys/security/mac/mac_policy.h =================================================================== --- head/sys/security/mac/mac_policy.h (revision 125292) +++ head/sys/security/mac/mac_policy.h (revision 125293) @@ -1,495 +1,496 @@ /*- * Copyright (c) 1999, 2000, 2001, 2002 Robert N. M. Watson * Copyright (c) 2001, 2002, 2003 Networks Associates Technology, Inc. * All rights reserved. * * This software was developed by Robert Watson for the TrustedBSD Project. * * This software was developed for the FreeBSD Project in part by Network * Associates Laboratories, the Security Research Division of Network * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), * as part of the DARPA CHATS research program. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ /* * Kernel interface for MAC policy modules. */ #ifndef _SYS_MAC_POLICY_H #define _SYS_MAC_POLICY_H /*- * Pluggable access control policy definition structure. * * List of operations that are performed as part of the implementation * of a MAC policy. Policy implementors declare operations with a * mac_policy_ops structure, and using the MAC_POLICY_SET() macro. * If an entry point is not declared, then then the policy will be ignored * during evaluation of that event or check. * * Operations are sorted first by general class of operation, then * alphabetically. */ struct acl; struct componentname; struct devfs_dirent; struct inpcb; struct ipq; struct label; struct mac_policy_conf; struct mbuf; struct mount; -struct pipe; +struct pipepair; struct sbuf; struct socket; struct ucred; struct uio; struct vnode; struct mac_policy_ops { /* * Policy module operations. */ void (*mpo_destroy)(struct mac_policy_conf *mpc); void (*mpo_init)(struct mac_policy_conf *mpc); /* * General policy-directed security system call so that policies * may implement new services without reserving explicit * system call numbers. */ int (*mpo_syscall)(struct thread *td, int call, void *arg); /* * Label operations. */ void (*mpo_init_bpfdesc_label)(struct label *label); void (*mpo_init_cred_label)(struct label *label); void (*mpo_init_devfsdirent_label)(struct label *label); void (*mpo_init_ifnet_label)(struct label *label); int (*mpo_init_inpcb_label)(struct label *label, int flag); int (*mpo_init_ipq_label)(struct label *label, int flag); int (*mpo_init_mbuf_label)(struct label *label, int flag); void (*mpo_init_mount_label)(struct label *label); void (*mpo_init_mount_fs_label)(struct label *label); int (*mpo_init_socket_label)(struct label *label, int flag); int (*mpo_init_socket_peer_label)(struct label *label, int flag); void (*mpo_init_pipe_label)(struct label *label); void (*mpo_init_proc_label)(struct label *label); void (*mpo_init_vnode_label)(struct label *label); void (*mpo_destroy_bpfdesc_label)(struct label *label); void (*mpo_destroy_cred_label)(struct label *label); void (*mpo_destroy_devfsdirent_label)(struct label *label); void (*mpo_destroy_ifnet_label)(struct label *label); void (*mpo_destroy_inpcb_label)(struct label *label); void (*mpo_destroy_ipq_label)(struct label *label); void (*mpo_destroy_mbuf_label)(struct label *label); void (*mpo_destroy_mount_label)(struct label *label); void (*mpo_destroy_mount_fs_label)(struct label *label); void (*mpo_destroy_socket_label)(struct label *label); void (*mpo_destroy_socket_peer_label)(struct label *label); void (*mpo_destroy_pipe_label)(struct label *label); void (*mpo_destroy_proc_label)(struct label *label); void (*mpo_destroy_vnode_label)(struct label *label); void (*mpo_copy_cred_label)(struct label *src, struct label *dest); void (*mpo_copy_mbuf_label)(struct label *src, struct label *dest); void (*mpo_copy_pipe_label)(struct label *src, struct label *dest); void (*mpo_copy_socket_label)(struct label *src, struct label *dest); void (*mpo_copy_vnode_label)(struct label *src, struct label *dest); int (*mpo_externalize_cred_label)(struct label *label, char *element_name, struct sbuf *sb, int *claimed); int (*mpo_externalize_ifnet_label)(struct label *label, char *element_name, struct sbuf *sb, int *claimed); int (*mpo_externalize_pipe_label)(struct label *label, char *element_name, struct sbuf *sb, int *claimed); int (*mpo_externalize_socket_label)(struct label *label, char *element_name, struct sbuf *sb, int *claimed); int (*mpo_externalize_socket_peer_label)(struct label *label, char *element_name, struct sbuf *sb, int *claimed); int (*mpo_externalize_vnode_label)(struct label *label, char *element_name, struct sbuf *sb, int *claimed); int (*mpo_internalize_cred_label)(struct label *label, char *element_name, char *element_data, int *claimed); int (*mpo_internalize_ifnet_label)(struct label *label, char *element_name, char *element_data, int *claimed); int (*mpo_internalize_pipe_label)(struct label *label, char *element_name, char *element_data, int *claimed); int (*mpo_internalize_socket_label)(struct label *label, char *element_name, char *element_data, int *claimed); int (*mpo_internalize_vnode_label)(struct label *label, char *element_name, char *element_data, int *claimed); /* * Labeling event operations: file system objects, and things that * look a lot like file system objects. */ void (*mpo_associate_vnode_devfs)(struct mount *mp, struct label *fslabel, struct devfs_dirent *de, struct label *delabel, struct vnode *vp, struct label *vlabel); int (*mpo_associate_vnode_extattr)(struct mount *mp, struct label *fslabel, struct vnode *vp, struct label *vlabel); void (*mpo_associate_vnode_singlelabel)(struct mount *mp, struct label *fslabel, struct vnode *vp, struct label *vlabel); void (*mpo_create_devfs_device)(struct mount *mp, dev_t dev, struct devfs_dirent *de, struct label *label); void (*mpo_create_devfs_directory)(struct mount *mp, char *dirname, int dirnamelen, struct devfs_dirent *de, struct label *label); void (*mpo_create_devfs_symlink)(struct ucred *cred, struct mount *mp, struct devfs_dirent *dd, struct label *ddlabel, struct devfs_dirent *de, struct label *delabel); int (*mpo_create_vnode_extattr)(struct ucred *cred, struct mount *mp, struct label *fslabel, struct vnode *dvp, struct label *dlabel, struct vnode *vp, struct label *vlabel, struct componentname *cnp); void (*mpo_create_mount)(struct ucred *cred, struct mount *mp, struct label *mntlabel, struct label *fslabel); void (*mpo_create_root_mount)(struct ucred *cred, struct mount *mp, struct label *mountlabel, struct label *fslabel); void (*mpo_relabel_vnode)(struct ucred *cred, struct vnode *vp, struct label *vnodelabel, struct label *label); int (*mpo_setlabel_vnode_extattr)(struct ucred *cred, struct vnode *vp, struct label *vlabel, struct label *intlabel); void (*mpo_update_devfsdirent)(struct mount *mp, struct devfs_dirent *devfs_dirent, struct label *direntlabel, struct vnode *vp, struct label *vnodelabel); /* * Labeling event operations: IPC objects. */ void (*mpo_create_mbuf_from_socket)(struct socket *so, struct label *socketlabel, struct mbuf *m, struct label *mbuflabel); void (*mpo_create_socket)(struct ucred *cred, struct socket *so, struct label *socketlabel); void (*mpo_create_socket_from_socket)(struct socket *oldsocket, struct label *oldsocketlabel, struct socket *newsocket, struct label *newsocketlabel); void (*mpo_relabel_socket)(struct ucred *cred, struct socket *so, struct label *oldlabel, struct label *newlabel); - void (*mpo_relabel_pipe)(struct ucred *cred, struct pipe *pipe, + void (*mpo_relabel_pipe)(struct ucred *cred, struct pipepair *pp, struct label *oldlabel, struct label *newlabel); void (*mpo_set_socket_peer_from_mbuf)(struct mbuf *mbuf, struct label *mbuflabel, struct socket *so, struct label *socketpeerlabel); void (*mpo_set_socket_peer_from_socket)(struct socket *oldsocket, struct label *oldsocketlabel, struct socket *newsocket, struct label *newsocketpeerlabel); - void (*mpo_create_pipe)(struct ucred *cred, struct pipe *pipe, + void (*mpo_create_pipe)(struct ucred *cred, struct pipepair *pp, struct label *pipelabel); /* * Labeling event operations: network objects. */ void (*mpo_create_bpfdesc)(struct ucred *cred, struct bpf_d *bpf_d, struct label *bpflabel); void (*mpo_create_ifnet)(struct ifnet *ifnet, struct label *ifnetlabel); void (*mpo_create_inpcb_from_socket)(struct socket *so, struct label *solabel, struct inpcb *inp, struct label *inplabel); void (*mpo_create_ipq)(struct mbuf *fragment, struct label *fragmentlabel, struct ipq *ipq, struct label *ipqlabel); void (*mpo_create_datagram_from_ipq) (struct ipq *ipq, struct label *ipqlabel, struct mbuf *datagram, struct label *datagramlabel); void (*mpo_create_fragment)(struct mbuf *datagram, struct label *datagramlabel, struct mbuf *fragment, struct label *fragmentlabel); void (*mpo_create_mbuf_from_inpcb)(struct inpcb *inp, struct label *inplabel, struct mbuf *m, struct label *mlabel); void (*mpo_create_mbuf_from_mbuf)(struct mbuf *oldmbuf, struct label *oldlabel, struct mbuf *newmbuf, struct label *newlabel); void (*mpo_create_mbuf_linklayer)(struct ifnet *ifnet, struct label *ifnetlabel, struct mbuf *mbuf, struct label *mbuflabel); void (*mpo_create_mbuf_from_bpfdesc)(struct bpf_d *bpf_d, struct label *bpflabel, struct mbuf *mbuf, struct label *mbuflabel); void (*mpo_create_mbuf_from_ifnet)(struct ifnet *ifnet, struct label *ifnetlabel, struct mbuf *mbuf, struct label *mbuflabel); void (*mpo_create_mbuf_multicast_encap)(struct mbuf *oldmbuf, struct label *oldmbuflabel, struct ifnet *ifnet, struct label *ifnetlabel, struct mbuf *newmbuf, struct label *newmbuflabel); void (*mpo_create_mbuf_netlayer)(struct mbuf *oldmbuf, struct label *oldmbuflabel, struct mbuf *newmbuf, struct label *newmbuflabel); int (*mpo_fragment_match)(struct mbuf *fragment, struct label *fragmentlabel, struct ipq *ipq, struct label *ipqlabel); void (*mpo_reflect_mbuf_icmp)(struct mbuf *m, struct label *mlabel); void (*mpo_reflect_mbuf_tcp)(struct mbuf *m, struct label *mlabel); void (*mpo_relabel_ifnet)(struct ucred *cred, struct ifnet *ifnet, struct label *ifnetlabel, struct label *newlabel); void (*mpo_update_ipq)(struct mbuf *fragment, struct label *fragmentlabel, struct ipq *ipq, struct label *ipqlabel); void (*mpo_inpcb_sosetlabel)(struct socket *so, struct label *label, struct inpcb *inp, struct label *inplabel); /* * Labeling event operations: processes. */ void (*mpo_execve_transition)(struct ucred *old, struct ucred *new, struct vnode *vp, struct label *vnodelabel, struct label *interpvnodelabel, struct image_params *imgp, struct label *execlabel); int (*mpo_execve_will_transition)(struct ucred *old, struct vnode *vp, struct label *vnodelabel, struct label *interpvnodelabel, struct image_params *imgp, struct label *execlabel); void (*mpo_create_proc0)(struct ucred *cred); void (*mpo_create_proc1)(struct ucred *cred); void (*mpo_relabel_cred)(struct ucred *cred, struct label *newlabel); void (*mpo_thread_userret)(struct thread *thread); /* * Access control checks. */ int (*mpo_check_bpfdesc_receive)(struct bpf_d *bpf_d, struct label *bpflabel, struct ifnet *ifnet, struct label *ifnetlabel); int (*mpo_check_cred_relabel)(struct ucred *cred, struct label *newlabel); int (*mpo_check_cred_visible)(struct ucred *u1, struct ucred *u2); int (*mpo_check_ifnet_relabel)(struct ucred *cred, struct ifnet *ifnet, struct label *ifnetlabel, struct label *newlabel); int (*mpo_check_ifnet_transmit)(struct ifnet *ifnet, struct label *ifnetlabel, struct mbuf *m, struct label *mbuflabel); int (*mpo_check_inpcb_deliver)(struct inpcb *inp, struct label *inplabel, struct mbuf *m, struct label *mlabel); int (*mpo_check_kenv_dump)(struct ucred *cred); int (*mpo_check_kenv_get)(struct ucred *cred, char *name); int (*mpo_check_kenv_set)(struct ucred *cred, char *name, char *value); int (*mpo_check_kenv_unset)(struct ucred *cred, char *name); int (*mpo_check_kld_load)(struct ucred *cred, struct vnode *vp, struct label *vlabel); int (*mpo_check_kld_stat)(struct ucred *cred); int (*mpo_check_kld_unload)(struct ucred *cred); int (*mpo_check_mount_stat)(struct ucred *cred, struct mount *mp, struct label *mntlabel); - int (*mpo_check_pipe_ioctl)(struct ucred *cred, struct pipe *pipe, - struct label *pipelabel, unsigned long cmd, void *data); - int (*mpo_check_pipe_poll)(struct ucred *cred, struct pipe *pipe, - struct label *pipelabel); - int (*mpo_check_pipe_read)(struct ucred *cred, struct pipe *pipe, - struct label *pipelabel); + int (*mpo_check_pipe_ioctl)(struct ucred *cred, + struct pipepair *pp, struct label *pipelabel, + unsigned long cmd, void *data); + int (*mpo_check_pipe_poll)(struct ucred *cred, + struct pipepair *pp, struct label *pipelabel); + int (*mpo_check_pipe_read)(struct ucred *cred, + struct pipepair *pp, struct label *pipelabel); int (*mpo_check_pipe_relabel)(struct ucred *cred, - struct pipe *pipe, struct label *pipelabel, + struct pipepair *pp, struct label *pipelabel, struct label *newlabel); - int (*mpo_check_pipe_stat)(struct ucred *cred, struct pipe *pipe, - struct label *pipelabel); - int (*mpo_check_pipe_write)(struct ucred *cred, struct pipe *pipe, - struct label *pipelabel); + int (*mpo_check_pipe_stat)(struct ucred *cred, + struct pipepair *pp, struct label *pipelabel); + int (*mpo_check_pipe_write)(struct ucred *cred, + struct pipepair *pp, struct label *pipelabel); int (*mpo_check_proc_debug)(struct ucred *cred, struct proc *proc); int (*mpo_check_proc_sched)(struct ucred *cred, struct proc *proc); int (*mpo_check_proc_signal)(struct ucred *cred, struct proc *proc, int signum); int (*mpo_check_socket_bind)(struct ucred *cred, struct socket *so, struct label *socketlabel, struct sockaddr *sockaddr); int (*mpo_check_socket_connect)(struct ucred *cred, struct socket *so, struct label *socketlabel, struct sockaddr *sockaddr); int (*mpo_check_socket_deliver)(struct socket *so, struct label *socketlabel, struct mbuf *m, struct label *mbuflabel); int (*mpo_check_socket_listen)(struct ucred *cred, struct socket *so, struct label *socketlabel); int (*mpo_check_socket_receive)(struct ucred *cred, struct socket *so, struct label *socketlabel); int (*mpo_check_socket_relabel)(struct ucred *cred, struct socket *so, struct label *socketlabel, struct label *newlabel); int (*mpo_check_socket_send)(struct ucred *cred, struct socket *so, struct label *socketlabel); int (*mpo_check_socket_visible)(struct ucred *cred, struct socket *so, struct label *socketlabel); int (*mpo_check_sysarch_ioperm)(struct ucred *cred); int (*mpo_check_system_acct)(struct ucred *cred, struct vnode *vp, struct label *vlabel); int (*mpo_check_system_nfsd)(struct ucred *cred); int (*mpo_check_system_reboot)(struct ucred *cred, int howto); int (*mpo_check_system_settime)(struct ucred *cred); int (*mpo_check_system_swapon)(struct ucred *cred, struct vnode *vp, struct label *label); int (*mpo_check_system_swapoff)(struct ucred *cred, struct vnode *vp, struct label *label); int (*mpo_check_system_sysctl)(struct ucred *cred, int *name, u_int namelen, void *old, size_t *oldlenp, int inkernel, void *new, size_t newlen); int (*mpo_check_vnode_access)(struct ucred *cred, struct vnode *vp, struct label *label, int acc_mode); int (*mpo_check_vnode_chdir)(struct ucred *cred, struct vnode *dvp, struct label *dlabel); int (*mpo_check_vnode_chroot)(struct ucred *cred, struct vnode *dvp, struct label *dlabel); int (*mpo_check_vnode_create)(struct ucred *cred, struct vnode *dvp, struct label *dlabel, struct componentname *cnp, struct vattr *vap); int (*mpo_check_vnode_delete)(struct ucred *cred, struct vnode *dvp, struct label *dlabel, struct vnode *vp, struct label *label, struct componentname *cnp); int (*mpo_check_vnode_deleteacl)(struct ucred *cred, struct vnode *vp, struct label *label, acl_type_t type); int (*mpo_check_vnode_deleteextattr)(struct ucred *cred, struct vnode *vp, struct label *label, int attrnamespace, const char *name); int (*mpo_check_vnode_exec)(struct ucred *cred, struct vnode *vp, struct label *label, struct image_params *imgp, struct label *execlabel); int (*mpo_check_vnode_getacl)(struct ucred *cred, struct vnode *vp, struct label *label, acl_type_t type); int (*mpo_check_vnode_getextattr)(struct ucred *cred, struct vnode *vp, struct label *label, int attrnamespace, const char *name, struct uio *uio); int (*mpo_check_vnode_link)(struct ucred *cred, struct vnode *dvp, struct label *dlabel, struct vnode *vp, struct label *label, struct componentname *cnp); int (*mpo_check_vnode_listextattr)(struct ucred *cred, struct vnode *vp, struct label *label, int attrnamespace); int (*mpo_check_vnode_lookup)(struct ucred *cred, struct vnode *dvp, struct label *dlabel, struct componentname *cnp); int (*mpo_check_vnode_mmap)(struct ucred *cred, struct vnode *vp, struct label *label, int prot); void (*mpo_check_vnode_mmap_downgrade)(struct ucred *cred, struct vnode *vp, struct label *label, int *prot); int (*mpo_check_vnode_mprotect)(struct ucred *cred, struct vnode *vp, struct label *label, int prot); int (*mpo_check_vnode_open)(struct ucred *cred, struct vnode *vp, struct label *label, int acc_mode); int (*mpo_check_vnode_poll)(struct ucred *active_cred, struct ucred *file_cred, struct vnode *vp, struct label *label); int (*mpo_check_vnode_read)(struct ucred *active_cred, struct ucred *file_cred, struct vnode *vp, struct label *label); int (*mpo_check_vnode_readdir)(struct ucred *cred, struct vnode *dvp, struct label *dlabel); int (*mpo_check_vnode_readlink)(struct ucred *cred, struct vnode *vp, struct label *label); int (*mpo_check_vnode_relabel)(struct ucred *cred, struct vnode *vp, struct label *vnodelabel, struct label *newlabel); int (*mpo_check_vnode_rename_from)(struct ucred *cred, struct vnode *dvp, struct label *dlabel, struct vnode *vp, struct label *label, struct componentname *cnp); int (*mpo_check_vnode_rename_to)(struct ucred *cred, struct vnode *dvp, struct label *dlabel, struct vnode *vp, struct label *label, int samedir, struct componentname *cnp); int (*mpo_check_vnode_revoke)(struct ucred *cred, struct vnode *vp, struct label *label); int (*mpo_check_vnode_setacl)(struct ucred *cred, struct vnode *vp, struct label *label, acl_type_t type, struct acl *acl); int (*mpo_check_vnode_setextattr)(struct ucred *cred, struct vnode *vp, struct label *label, int attrnamespace, const char *name, struct uio *uio); int (*mpo_check_vnode_setflags)(struct ucred *cred, struct vnode *vp, struct label *label, u_long flags); int (*mpo_check_vnode_setmode)(struct ucred *cred, struct vnode *vp, struct label *label, mode_t mode); int (*mpo_check_vnode_setowner)(struct ucred *cred, struct vnode *vp, struct label *label, uid_t uid, gid_t gid); int (*mpo_check_vnode_setutimes)(struct ucred *cred, struct vnode *vp, struct label *label, struct timespec atime, struct timespec mtime); int (*mpo_check_vnode_stat)(struct ucred *active_cred, struct ucred *file_cred, struct vnode *vp, struct label *label); int (*mpo_check_vnode_write)(struct ucred *active_cred, struct ucred *file_cred, struct vnode *vp, struct label *label); }; struct mac_policy_conf { char *mpc_name; /* policy name */ char *mpc_fullname; /* policy full name */ struct mac_policy_ops *mpc_ops; /* policy operations */ int mpc_loadtime_flags; /* flags */ int *mpc_field_off; /* security field */ int mpc_runtime_flags; /* flags */ LIST_ENTRY(mac_policy_conf) mpc_list; /* global list */ }; /* Flags for the mpc_loadtime_flags field. */ #define MPC_LOADTIME_FLAG_NOTLATE 0x00000001 #define MPC_LOADTIME_FLAG_UNLOADOK 0x00000002 #define MPC_LOADTIME_FLAG_LABELMBUFS 0x00000004 /* Flags for the mpc_runtime_flags field. */ #define MPC_RUNTIME_FLAG_REGISTERED 0x00000001 #define MAC_POLICY_SET(mpops, mpname, mpfullname, mpflags, privdata_wanted) \ static struct mac_policy_conf mpname##_mac_policy_conf = { \ #mpname, \ mpfullname, \ mpops, \ mpflags, \ privdata_wanted, \ 0, \ }; \ static moduledata_t mpname##_mod = { \ #mpname, \ mac_policy_modevent, \ &mpname##_mac_policy_conf \ }; \ MODULE_DEPEND(mpname, kernel_mac_support, 1, 1, 1); \ DECLARE_MODULE(mpname, mpname##_mod, SI_SUB_MAC_POLICY, \ SI_ORDER_MIDDLE) int mac_policy_modevent(module_t mod, int type, void *data); #define LABEL_TO_SLOT(l, s) (l)->l_perpolicy[s] #endif /* !_SYS_MAC_POLICY_H */ Index: head/sys/security/mac/mac_syscalls.c =================================================================== --- head/sys/security/mac/mac_syscalls.c (revision 125292) +++ head/sys/security/mac/mac_syscalls.c (revision 125293) @@ -1,1209 +1,1209 @@ /*- * Copyright (c) 1999, 2000, 2001, 2002 Robert N. M. Watson * Copyright (c) 2001 Ilmar S. Habibulin * Copyright (c) 2001, 2002, 2003 Networks Associates Technology, Inc. * All rights reserved. * * This software was developed by Robert Watson and Ilmar Habibulin for the * TrustedBSD Project. * * This software was developed for the FreeBSD Project in part by Network * Associates Laboratories, the Security Research Division of Network * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), * as part of the DARPA CHATS research program. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /*- * Framework for extensible kernel access control. This file contains * Kernel and userland interface to the framework, policy registration * and composition. Per-object interfaces, controls, and labeling may be * found in src/sys/mac/. Sample policies may be found in src/sys/mac*. */ #include __FBSDID("$FreeBSD$"); #include "opt_mac.h" #include "opt_devfs.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef MAC /* * Declare that the kernel provides MAC support, version 1. This permits * modules to refuse to be loaded if the necessary support isn't present, * even if it's pre-boot. */ MODULE_VERSION(kernel_mac_support, 1); SYSCTL_NODE(_security, OID_AUTO, mac, CTLFLAG_RW, 0, "TrustedBSD MAC policy controls"); #if MAC_MAX_SLOTS > 32 #error "MAC_MAX_SLOTS too large" #endif 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, &mac_max_slots, 0, ""); /* * Has the kernel started generating labeled objects yet? All read/write * access to this variable is serialized during the boot process. Following * the end of serialization, we don't update this flag; no locking. */ int mac_late = 0; /* * Flag to indicate whether or not we should allocate label storage for * new mbufs. Since most dynamic policies we currently work with don't * rely on mbuf 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 mbuf labels, it must * be able to deal with a NULL label being returned on any mbufs 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. Note: currently no locking. Will this be a problem? */ #ifndef MAC_ALWAYS_LABEL_MBUF int mac_labelmbufs = 0; #endif #ifdef MAC_DEBUG SYSCTL_NODE(_security_mac, OID_AUTO, debug, CTLFLAG_RW, 0, "TrustedBSD MAC debug info"); SYSCTL_NODE(_security_mac_debug, OID_AUTO, counters, CTLFLAG_RW, 0, "TrustedBSD MAC object counters"); static unsigned int nmactemp; SYSCTL_UINT(_security_mac_debug_counters, OID_AUTO, temp, CTLFLAG_RD, &nmactemp, 0, "number of temporary labels in use"); #endif static int mac_policy_register(struct mac_policy_conf *mpc); static int mac_policy_unregister(struct mac_policy_conf *mpc); MALLOC_DEFINE(M_MACTEMP, "mactemp", "MAC temporary label storage"); /* * mac_static_policy_list holds a list of policy modules that are not * loaded while the system is "live", and cannot be unloaded. These * policies can be invoked without holding the busy count. * * mac_policy_list stores the list of dynamic policies. A busy count is * maintained for the list, stored in mac_policy_busy. The busy count * is protected by mac_policy_mtx; the list may be modified only * while the busy count is 0, requiring that the lock be held to * prevent new references to the list from being acquired. For almost * all operations, incrementing the busy count is sufficient to * guarantee consistency, as the list cannot be modified while the * busy count is elevated. For a few special operations involving a * change to the list of active policies, the mtx itself must be held. * A condition variable, mac_policy_cv, is used to signal potential * exclusive consumers that they should try to acquire the lock if a * first attempt at exclusive access fails. */ static struct mtx mac_policy_mtx; static struct cv mac_policy_cv; static int mac_policy_count; struct mac_policy_list_head mac_policy_list; struct mac_policy_list_head mac_static_policy_list; /* * We manually invoke WITNESS_WARN() to allow Witness to generate * warnings even if we don't end up ever triggering the wait at * run-time. The consumer of the exclusive interface must not hold * any locks (other than potentially Giant) since we may sleep for * long (potentially indefinite) periods of time waiting for the * framework to become quiescent so that a policy list change may * be made. */ void mac_policy_grab_exclusive(void) { WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, "mac_policy_grab_exclusive() at %s:%d", __FILE__, __LINE__); mtx_lock(&mac_policy_mtx); while (mac_policy_count != 0) cv_wait(&mac_policy_cv, &mac_policy_mtx); } void mac_policy_assert_exclusive(void) { mtx_assert(&mac_policy_mtx, MA_OWNED); KASSERT(mac_policy_count == 0, ("mac_policy_assert_exclusive(): not exclusive")); } void mac_policy_release_exclusive(void) { KASSERT(mac_policy_count == 0, ("mac_policy_release_exclusive(): not exclusive")); mtx_unlock(&mac_policy_mtx); cv_signal(&mac_policy_cv); } void mac_policy_list_busy(void) { mtx_lock(&mac_policy_mtx); mac_policy_count++; mtx_unlock(&mac_policy_mtx); } int mac_policy_list_conditional_busy(void) { int ret; mtx_lock(&mac_policy_mtx); if (!LIST_EMPTY(&mac_policy_list)) { mac_policy_count++; ret = 1; } else ret = 0; mtx_unlock(&mac_policy_mtx); return (ret); } void mac_policy_list_unbusy(void) { mtx_lock(&mac_policy_mtx); mac_policy_count--; KASSERT(mac_policy_count >= 0, ("MAC_POLICY_LIST_LOCK")); if (mac_policy_count == 0) cv_signal(&mac_policy_cv); mtx_unlock(&mac_policy_mtx); } /* * Initialize the MAC subsystem, including appropriate SMP locks. */ static void mac_init(void) { LIST_INIT(&mac_static_policy_list); LIST_INIT(&mac_policy_list); mac_labelzone_init(); mtx_init(&mac_policy_mtx, "mac_policy_mtx", NULL, MTX_DEF); cv_init(&mac_policy_cv, "mac_policy_cv"); } /* * For the purposes of modules that want to know if they were loaded * "early", set the mac_late flag once we've processed modules either * linked into the kernel, or loaded before the kernel startup. */ static void mac_late_init(void) { mac_late = 1; } /* * After the policy list has changed, walk the list to update any global * flags. Currently, we support only one flag, and it's conditionally * defined; as a result, the entire function is conditional. Eventually, * the #else case might also iterate across the policies. */ static void mac_policy_updateflags(void) { #ifndef MAC_ALWAYS_LABEL_MBUF struct mac_policy_conf *tmpc; int labelmbufs; mac_policy_assert_exclusive(); labelmbufs = 0; 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 } /* * Allow MAC policy modules to register during boot, etc. */ int mac_policy_modevent(module_t mod, int type, void *data) { struct mac_policy_conf *mpc; int error; error = 0; mpc = (struct mac_policy_conf *) data; switch (type) { case MOD_LOAD: if (mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_NOTLATE && mac_late) { printf("mac_policy_modevent: can't load %s policy " "after booting\n", mpc->mpc_name); error = EBUSY; break; } error = mac_policy_register(mpc); break; case MOD_UNLOAD: /* Don't unregister the module if it was never registered. */ if ((mpc->mpc_runtime_flags & MPC_RUNTIME_FLAG_REGISTERED) != 0) error = mac_policy_unregister(mpc); else error = 0; break; default: break; } return (error); } static int mac_policy_register(struct mac_policy_conf *mpc) { struct mac_policy_conf *tmpc; int error, slot, static_entry; error = 0; /* * We don't technically need exclusive access while !mac_late, * but hold it for assertion consistency. */ mac_policy_grab_exclusive(); /* * If the module can potentially be unloaded, or we're loading * late, we have to stick it in the non-static list and pay * an extra performance overhead. Otherwise, we can pay a * light locking cost and stick it in the static list. */ static_entry = (!mac_late && !(mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_UNLOADOK)); if (static_entry) { LIST_FOREACH(tmpc, &mac_static_policy_list, mpc_list) { if (strcmp(tmpc->mpc_name, mpc->mpc_name) == 0) { error = EEXIST; goto out; } } } else { LIST_FOREACH(tmpc, &mac_policy_list, mpc_list) { if (strcmp(tmpc->mpc_name, mpc->mpc_name) == 0) { error = EEXIST; goto out; } } } if (mpc->mpc_field_off != NULL) { slot = ffs(mac_slot_offsets_free); if (slot == 0) { error = ENOMEM; goto out; } slot--; mac_slot_offsets_free &= ~(1 << slot); *mpc->mpc_field_off = slot; } mpc->mpc_runtime_flags |= MPC_RUNTIME_FLAG_REGISTERED; /* * If we're loading a MAC module after the framework has * initialized, it has to go into the dynamic list. If * we're loading it before we've finished initializing, * it can go into the static list with weaker locker * requirements. */ if (static_entry) LIST_INSERT_HEAD(&mac_static_policy_list, mpc, mpc_list); else LIST_INSERT_HEAD(&mac_policy_list, mpc, mpc_list); /* Per-policy initialization. */ if (mpc->mpc_ops->mpo_init != NULL) (*(mpc->mpc_ops->mpo_init))(mpc); mac_policy_updateflags(); printf("Security policy loaded: %s (%s)\n", mpc->mpc_fullname, mpc->mpc_name); out: mac_policy_release_exclusive(); return (error); } static int mac_policy_unregister(struct mac_policy_conf *mpc) { /* * If we fail the load, we may get a request to unload. Check * to see if we did the run-time registration, and if not, * silently succeed. */ mac_policy_grab_exclusive(); if ((mpc->mpc_runtime_flags & MPC_RUNTIME_FLAG_REGISTERED) == 0) { mac_policy_release_exclusive(); return (0); } #if 0 /* * Don't allow unloading modules with private data. */ if (mpc->mpc_field_off != NULL) { MAC_POLICY_LIST_UNLOCK(); return (EBUSY); } #endif /* * Only allow the unload to proceed if the module is unloadable * by its own definition. */ if ((mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_UNLOADOK) == 0) { mac_policy_release_exclusive(); return (EBUSY); } if (mpc->mpc_ops->mpo_destroy != NULL) (*(mpc->mpc_ops->mpo_destroy))(mpc); LIST_REMOVE(mpc, mpc_list); mpc->mpc_runtime_flags &= ~MPC_RUNTIME_FLAG_REGISTERED; mac_policy_updateflags(); mac_policy_release_exclusive(); printf("Security policy unload: %s (%s)\n", mpc->mpc_fullname, mpc->mpc_name); return (0); } /* * Define an error value precedence, and given two arguments, selects the * value with the higher precedence. */ int mac_error_select(int error1, int error2) { /* Certain decision-making errors take top priority. */ if (error1 == EDEADLK || error2 == EDEADLK) return (EDEADLK); /* Invalid arguments should be reported where possible. */ if (error1 == EINVAL || error2 == EINVAL) return (EINVAL); /* Precedence goes to "visibility", with both process and file. */ if (error1 == ESRCH || error2 == ESRCH) return (ESRCH); if (error1 == ENOENT || error2 == ENOENT) return (ENOENT); /* Precedence goes to DAC/MAC protections. */ if (error1 == EACCES || error2 == EACCES) return (EACCES); /* Precedence goes to privilege. */ if (error1 == EPERM || error2 == EPERM) return (EPERM); /* Precedence goes to error over success; otherwise, arbitrary. */ if (error1 != 0) return (error1); return (error2); } void mac_init_label(struct label *label) { bzero(label, sizeof(*label)); label->l_flags = MAC_FLAG_INITIALIZED; } void mac_destroy_label(struct label *label) { KASSERT(label->l_flags & MAC_FLAG_INITIALIZED, ("destroying uninitialized label")); bzero(label, sizeof(*label)); /* implicit: label->l_flags &= ~MAC_FLAG_INITIALIZED; */ } int mac_check_structmac_consistent(struct mac *mac) { if (mac->m_buflen < 0 || mac->m_buflen > MAC_MAX_LABEL_BUF_LEN) return (EINVAL); return (0); } /* * MPSAFE */ int __mac_get_pid(struct thread *td, struct __mac_get_pid_args *uap) { char *elements, *buffer; struct mac mac; struct proc *tproc; struct ucred *tcred; int error; error = copyin(uap->mac_p, &mac, sizeof(mac)); if (error) return (error); error = mac_check_structmac_consistent(&mac); if (error) return (error); tproc = pfind(uap->pid); if (tproc == NULL) return (ESRCH); tcred = NULL; /* Satisfy gcc. */ error = p_cansee(td, tproc); if (error == 0) tcred = crhold(tproc->p_ucred); PROC_UNLOCK(tproc); if (error) return (error); elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL); if (error) { free(elements, M_MACTEMP); crfree(tcred); return (error); } buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); error = mac_externalize_cred_label(tcred->cr_label, elements, buffer, mac.m_buflen); if (error == 0) error = copyout(buffer, mac.m_string, strlen(buffer)+1); free(buffer, M_MACTEMP); free(elements, M_MACTEMP); crfree(tcred); return (error); } /* * MPSAFE */ int __mac_get_proc(struct thread *td, struct __mac_get_proc_args *uap) { char *elements, *buffer; struct mac mac; int error; error = copyin(uap->mac_p, &mac, sizeof(mac)); if (error) return (error); error = mac_check_structmac_consistent(&mac); if (error) return (error); elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL); if (error) { free(elements, M_MACTEMP); return (error); } buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); error = mac_externalize_cred_label(td->td_ucred->cr_label, elements, buffer, mac.m_buflen); if (error == 0) error = copyout(buffer, mac.m_string, strlen(buffer)+1); free(buffer, M_MACTEMP); free(elements, M_MACTEMP); return (error); } /* * MPSAFE */ int __mac_set_proc(struct thread *td, struct __mac_set_proc_args *uap) { struct ucred *newcred, *oldcred; struct label *intlabel; struct proc *p; struct mac mac; char *buffer; int error; error = copyin(uap->mac_p, &mac, sizeof(mac)); if (error) return (error); error = mac_check_structmac_consistent(&mac); if (error) return (error); buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL); if (error) { free(buffer, M_MACTEMP); return (error); } intlabel = mac_cred_label_alloc(); error = mac_internalize_cred_label(intlabel, buffer); free(buffer, M_MACTEMP); if (error) goto out; newcred = crget(); p = td->td_proc; PROC_LOCK(p); oldcred = p->p_ucred; error = mac_check_cred_relabel(oldcred, intlabel); if (error) { PROC_UNLOCK(p); crfree(newcred); goto out; } setsugid(p); crcopy(newcred, oldcred); mac_relabel_cred(newcred, intlabel); p->p_ucred = newcred; /* * Grab additional reference for use while revoking mmaps, prior * to releasing the proc lock and sharing the cred. */ crhold(newcred); PROC_UNLOCK(p); if (mac_enforce_vm) { mtx_lock(&Giant); mac_cred_mmapped_drop_perms(td, newcred); mtx_unlock(&Giant); } crfree(newcred); /* Free revocation reference. */ crfree(oldcred); out: mac_cred_label_free(intlabel); return (error); } /* * MPSAFE */ int __mac_get_fd(struct thread *td, struct __mac_get_fd_args *uap) { char *elements, *buffer; struct label *intlabel; struct file *fp; struct mac mac; struct vnode *vp; struct pipe *pipe; struct socket *so; short label_type; int error; error = copyin(uap->mac_p, &mac, sizeof(mac)); if (error) return (error); error = mac_check_structmac_consistent(&mac); if (error) return (error); elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL); if (error) { free(elements, M_MACTEMP); return (error); } buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); error = fget(td, uap->fd, &fp); if (error) goto out; label_type = fp->f_type; switch (fp->f_type) { case DTYPE_FIFO: case DTYPE_VNODE: vp = fp->f_vnode; intlabel = mac_vnode_label_alloc(); mtx_lock(&Giant); /* VFS */ vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); mac_copy_vnode_label(vp->v_label, intlabel); VOP_UNLOCK(vp, 0, td); mtx_unlock(&Giant); /* VFS */ error = mac_externalize_vnode_label(intlabel, elements, buffer, mac.m_buflen); mac_vnode_label_free(intlabel); break; case DTYPE_PIPE: pipe = fp->f_data; intlabel = mac_pipe_label_alloc(); PIPE_LOCK(pipe); - mac_copy_pipe_label(pipe->pipe_label, intlabel); + mac_copy_pipe_label(pipe->pipe_pair->pp_label, intlabel); PIPE_UNLOCK(pipe); error = mac_externalize_pipe_label(intlabel, elements, buffer, mac.m_buflen); mac_pipe_label_free(intlabel); break; case DTYPE_SOCKET: so = fp->f_data; intlabel = mac_socket_label_alloc(M_WAITOK); mtx_lock(&Giant); /* Sockets */ /* XXX: Socket lock here. */ mac_copy_socket_label(so->so_label, intlabel); /* XXX: Socket unlock here. */ mtx_unlock(&Giant); /* Sockets */ error = mac_externalize_socket_label(intlabel, elements, buffer, mac.m_buflen); mac_socket_label_free(intlabel); break; default: error = EINVAL; } fdrop(fp, td); if (error == 0) error = copyout(buffer, mac.m_string, strlen(buffer)+1); out: free(buffer, M_MACTEMP); free(elements, M_MACTEMP); return (error); } /* * MPSAFE */ int __mac_get_file(struct thread *td, struct __mac_get_file_args *uap) { char *elements, *buffer; struct nameidata nd; struct label *intlabel; struct mac mac; int error; error = copyin(uap->mac_p, &mac, sizeof(mac)); if (error) return (error); error = mac_check_structmac_consistent(&mac); if (error) return (error); elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL); if (error) { free(elements, M_MACTEMP); return (error); } buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); mtx_lock(&Giant); /* VFS */ NDINIT(&nd, LOOKUP, LOCKLEAF | FOLLOW, UIO_USERSPACE, uap->path_p, td); error = namei(&nd); if (error) goto out; intlabel = mac_vnode_label_alloc(); mac_copy_vnode_label(nd.ni_vp->v_label, intlabel); error = mac_externalize_vnode_label(intlabel, elements, buffer, mac.m_buflen); NDFREE(&nd, 0); mac_vnode_label_free(intlabel); if (error == 0) error = copyout(buffer, mac.m_string, strlen(buffer)+1); out: mtx_unlock(&Giant); /* VFS */ free(buffer, M_MACTEMP); free(elements, M_MACTEMP); return (error); } /* * MPSAFE */ int __mac_get_link(struct thread *td, struct __mac_get_link_args *uap) { char *elements, *buffer; struct nameidata nd; struct label *intlabel; struct mac mac; int error; error = copyin(uap->mac_p, &mac, sizeof(mac)); if (error) return (error); error = mac_check_structmac_consistent(&mac); if (error) return (error); elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL); if (error) { free(elements, M_MACTEMP); return (error); } buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); mtx_lock(&Giant); /* VFS */ NDINIT(&nd, LOOKUP, LOCKLEAF | NOFOLLOW, UIO_USERSPACE, uap->path_p, td); error = namei(&nd); if (error) goto out; intlabel = mac_vnode_label_alloc(); mac_copy_vnode_label(nd.ni_vp->v_label, intlabel); error = mac_externalize_vnode_label(intlabel, elements, buffer, mac.m_buflen); NDFREE(&nd, 0); mac_vnode_label_free(intlabel); if (error == 0) error = copyout(buffer, mac.m_string, strlen(buffer)+1); out: mtx_unlock(&Giant); /* VFS */ free(buffer, M_MACTEMP); free(elements, M_MACTEMP); return (error); } /* * MPSAFE */ int __mac_set_fd(struct thread *td, struct __mac_set_fd_args *uap) { struct label *intlabel; struct pipe *pipe; struct socket *so; struct file *fp; struct mount *mp; struct vnode *vp; struct mac mac; char *buffer; int error; error = copyin(uap->mac_p, &mac, sizeof(mac)); if (error) return (error); error = mac_check_structmac_consistent(&mac); if (error) return (error); buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL); if (error) { free(buffer, M_MACTEMP); return (error); } error = fget(td, uap->fd, &fp); if (error) goto out; switch (fp->f_type) { case DTYPE_FIFO: case DTYPE_VNODE: intlabel = mac_vnode_label_alloc(); error = mac_internalize_vnode_label(intlabel, buffer); if (error) { mac_vnode_label_free(intlabel); break; } vp = fp->f_vnode; mtx_lock(&Giant); /* VFS */ error = vn_start_write(vp, &mp, V_WAIT | PCATCH); if (error != 0) { mtx_unlock(&Giant); /* VFS */ mac_vnode_label_free(intlabel); break; } vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); error = vn_setlabel(vp, intlabel, td->td_ucred); VOP_UNLOCK(vp, 0, td); vn_finished_write(mp); mtx_unlock(&Giant); /* VFS */ mac_vnode_label_free(intlabel); break; case DTYPE_PIPE: intlabel = mac_pipe_label_alloc(); error = mac_internalize_pipe_label(intlabel, buffer); if (error == 0) { pipe = fp->f_data; PIPE_LOCK(pipe); - error = mac_pipe_label_set(td->td_ucred, pipe, - intlabel); + error = mac_pipe_label_set(td->td_ucred, + pipe->pipe_pair, intlabel); PIPE_UNLOCK(pipe); } mac_pipe_label_free(intlabel); break; case DTYPE_SOCKET: intlabel = mac_socket_label_alloc(M_WAITOK); error = mac_internalize_socket_label(intlabel, buffer); if (error == 0) { so = fp->f_data; mtx_lock(&Giant); /* Sockets */ /* XXX: Socket lock here. */ error = mac_socket_label_set(td->td_ucred, so, intlabel); /* XXX: Socket unlock here. */ mtx_unlock(&Giant); /* Sockets */ } mac_socket_label_free(intlabel); break; default: error = EINVAL; } fdrop(fp, td); out: free(buffer, M_MACTEMP); return (error); } /* * MPSAFE */ int __mac_set_file(struct thread *td, struct __mac_set_file_args *uap) { struct label *intlabel; struct nameidata nd; struct mount *mp; struct mac mac; char *buffer; int error; error = copyin(uap->mac_p, &mac, sizeof(mac)); if (error) return (error); error = mac_check_structmac_consistent(&mac); if (error) return (error); buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL); if (error) { free(buffer, M_MACTEMP); return (error); } intlabel = mac_vnode_label_alloc(); error = mac_internalize_vnode_label(intlabel, buffer); free(buffer, M_MACTEMP); if (error) goto out; mtx_lock(&Giant); /* VFS */ NDINIT(&nd, LOOKUP, LOCKLEAF | FOLLOW, UIO_USERSPACE, uap->path_p, td); error = namei(&nd); if (error == 0) { error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH); if (error == 0) error = vn_setlabel(nd.ni_vp, intlabel, td->td_ucred); vn_finished_write(mp); } NDFREE(&nd, 0); mtx_unlock(&Giant); /* VFS */ out: mac_vnode_label_free(intlabel); return (error); } /* * MPSAFE */ int __mac_set_link(struct thread *td, struct __mac_set_link_args *uap) { struct label *intlabel; struct nameidata nd; struct mount *mp; struct mac mac; char *buffer; int error; error = copyin(uap->mac_p, &mac, sizeof(mac)); if (error) return (error); error = mac_check_structmac_consistent(&mac); if (error) return (error); buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL); if (error) { free(buffer, M_MACTEMP); return (error); } intlabel = mac_vnode_label_alloc(); error = mac_internalize_vnode_label(intlabel, buffer); free(buffer, M_MACTEMP); if (error) goto out; mtx_lock(&Giant); /* VFS */ NDINIT(&nd, LOOKUP, LOCKLEAF | NOFOLLOW, UIO_USERSPACE, uap->path_p, td); error = namei(&nd); if (error == 0) { error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH); if (error == 0) error = vn_setlabel(nd.ni_vp, intlabel, td->td_ucred); vn_finished_write(mp); } NDFREE(&nd, 0); mtx_unlock(&Giant); /* VFS */ out: mac_vnode_label_free(intlabel); return (error); } /* * MPSAFE */ int mac_syscall(struct thread *td, struct mac_syscall_args *uap) { struct mac_policy_conf *mpc; char target[MAC_MAX_POLICY_NAME]; int entrycount, error; error = copyinstr(uap->policy, target, sizeof(target), NULL); if (error) return (error); error = ENOSYS; LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) { if (strcmp(mpc->mpc_name, target) == 0 && mpc->mpc_ops->mpo_syscall != NULL) { error = mpc->mpc_ops->mpo_syscall(td, uap->call, uap->arg); goto out; } } if ((entrycount = mac_policy_list_conditional_busy()) != 0) { LIST_FOREACH(mpc, &mac_policy_list, mpc_list) { if (strcmp(mpc->mpc_name, target) == 0 && mpc->mpc_ops->mpo_syscall != NULL) { error = mpc->mpc_ops->mpo_syscall(td, uap->call, uap->arg); break; } } mac_policy_list_unbusy(); } out: return (error); } SYSINIT(mac, SI_SUB_MAC, SI_ORDER_FIRST, mac_init, NULL); SYSINIT(mac_late, SI_SUB_MAC_LATE, SI_ORDER_FIRST, mac_late_init, NULL); #else /* !MAC */ int __mac_get_pid(struct thread *td, struct __mac_get_pid_args *uap) { return (ENOSYS); } int __mac_get_proc(struct thread *td, struct __mac_get_proc_args *uap) { return (ENOSYS); } int __mac_set_proc(struct thread *td, struct __mac_set_proc_args *uap) { return (ENOSYS); } int __mac_get_fd(struct thread *td, struct __mac_get_fd_args *uap) { return (ENOSYS); } int __mac_get_file(struct thread *td, struct __mac_get_file_args *uap) { return (ENOSYS); } int __mac_get_link(struct thread *td, struct __mac_get_link_args *uap) { return (ENOSYS); } int __mac_set_fd(struct thread *td, struct __mac_set_fd_args *uap) { return (ENOSYS); } int __mac_set_file(struct thread *td, struct __mac_set_file_args *uap) { return (ENOSYS); } int __mac_set_link(struct thread *td, struct __mac_set_link_args *uap) { return (ENOSYS); } int mac_syscall(struct thread *td, struct mac_syscall_args *uap) { return (ENOSYS); } #endif Index: head/sys/security/mac_biba/mac_biba.c =================================================================== --- head/sys/security/mac_biba/mac_biba.c (revision 125292) +++ head/sys/security/mac_biba/mac_biba.c (revision 125293) @@ -1,2789 +1,2789 @@ /*- * Copyright (c) 1999, 2000, 2001, 2002 Robert N. M. Watson * Copyright (c) 2001, 2002, 2003 Networks Associates Technology, Inc. * All rights reserved. * * This software was developed by Robert Watson for the TrustedBSD Project. * * This software was developed for the FreeBSD Project in part by Network * Associates Laboratories, the Security Research Division of Network * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), * as part of the DARPA CHATS research program. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ /* * Developed by the TrustedBSD Project. * Biba fixed label mandatory integrity policy. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include SYSCTL_DECL(_security_mac); SYSCTL_NODE(_security_mac, OID_AUTO, biba, CTLFLAG_RW, 0, "TrustedBSD mac_biba policy controls"); static int mac_biba_label_size = sizeof(struct mac_biba); SYSCTL_INT(_security_mac_biba, OID_AUTO, label_size, CTLFLAG_RD, &mac_biba_label_size, 0, "Size of struct mac_biba"); static int mac_biba_enabled = 1; SYSCTL_INT(_security_mac_biba, OID_AUTO, enabled, CTLFLAG_RW, &mac_biba_enabled, 0, "Enforce MAC/Biba policy"); TUNABLE_INT("security.mac.biba.enabled", &mac_biba_enabled); static int destroyed_not_inited; SYSCTL_INT(_security_mac_biba, OID_AUTO, destroyed_not_inited, CTLFLAG_RD, &destroyed_not_inited, 0, "Count of labels destroyed but not inited"); static int trust_all_interfaces = 0; SYSCTL_INT(_security_mac_biba, OID_AUTO, trust_all_interfaces, CTLFLAG_RD, &trust_all_interfaces, 0, "Consider all interfaces 'trusted' by MAC/Biba"); TUNABLE_INT("security.mac.biba.trust_all_interfaces", &trust_all_interfaces); static char trusted_interfaces[128]; SYSCTL_STRING(_security_mac_biba, OID_AUTO, trusted_interfaces, CTLFLAG_RD, trusted_interfaces, 0, "Interfaces considered 'trusted' by MAC/Biba"); TUNABLE_STR("security.mac.biba.trusted_interfaces", trusted_interfaces, sizeof(trusted_interfaces)); static int max_compartments = MAC_BIBA_MAX_COMPARTMENTS; SYSCTL_INT(_security_mac_biba, OID_AUTO, max_compartments, CTLFLAG_RD, &max_compartments, 0, "Maximum supported compartments"); static int ptys_equal = 0; SYSCTL_INT(_security_mac_biba, OID_AUTO, ptys_equal, CTLFLAG_RW, &ptys_equal, 0, "Label pty devices as biba/equal on create"); TUNABLE_INT("security.mac.biba.ptys_equal", &ptys_equal); static int revocation_enabled = 0; SYSCTL_INT(_security_mac_biba, OID_AUTO, revocation_enabled, CTLFLAG_RW, &revocation_enabled, 0, "Revoke access to objects on relabel"); TUNABLE_INT("security.mac.biba.revocation_enabled", &revocation_enabled); static int mac_biba_slot; #define SLOT(l) ((struct mac_biba *)LABEL_TO_SLOT((l), mac_biba_slot).l_ptr) static uma_zone_t zone_biba; static __inline int biba_bit_set_empty(u_char *set) { int i; for (i = 0; i < MAC_BIBA_MAX_COMPARTMENTS >> 3; i++) if (set[i] != 0) return (0); return (1); } static struct mac_biba * biba_alloc(int flag) { return (uma_zalloc(zone_biba, flag | M_ZERO)); } static void biba_free(struct mac_biba *mac_biba) { if (mac_biba != NULL) uma_zfree(zone_biba, mac_biba); else atomic_add_int(&destroyed_not_inited, 1); } static int biba_atmostflags(struct mac_biba *mac_biba, int flags) { if ((mac_biba->mb_flags & flags) != mac_biba->mb_flags) return (EINVAL); return (0); } static int mac_biba_dominate_element(struct mac_biba_element *a, struct mac_biba_element *b) { int bit; switch (a->mbe_type) { case MAC_BIBA_TYPE_EQUAL: case MAC_BIBA_TYPE_HIGH: return (1); case MAC_BIBA_TYPE_LOW: switch (b->mbe_type) { case MAC_BIBA_TYPE_GRADE: case MAC_BIBA_TYPE_HIGH: return (0); case MAC_BIBA_TYPE_EQUAL: case MAC_BIBA_TYPE_LOW: return (1); default: panic("mac_biba_dominate_element: b->mbe_type invalid"); } case MAC_BIBA_TYPE_GRADE: switch (b->mbe_type) { case MAC_BIBA_TYPE_EQUAL: case MAC_BIBA_TYPE_LOW: return (1); case MAC_BIBA_TYPE_HIGH: return (0); case MAC_BIBA_TYPE_GRADE: for (bit = 1; bit <= MAC_BIBA_MAX_COMPARTMENTS; bit++) if (!MAC_BIBA_BIT_TEST(bit, a->mbe_compartments) && MAC_BIBA_BIT_TEST(bit, b->mbe_compartments)) return (0); return (a->mbe_grade >= b->mbe_grade); default: panic("mac_biba_dominate_element: b->mbe_type invalid"); } default: panic("mac_biba_dominate_element: a->mbe_type invalid"); } return (0); } static int mac_biba_subject_dominate_high(struct mac_biba *mac_biba) { struct mac_biba_element *element; KASSERT((mac_biba->mb_flags & MAC_BIBA_FLAG_SINGLE) != 0, ("mac_biba_single_in_range: mac_biba not single")); element = &mac_biba->mb_single; return (element->mbe_type == MAC_BIBA_TYPE_EQUAL || element->mbe_type == MAC_BIBA_TYPE_HIGH); } static int mac_biba_range_in_range(struct mac_biba *rangea, struct mac_biba *rangeb) { return (mac_biba_dominate_element(&rangeb->mb_rangehigh, &rangea->mb_rangehigh) && mac_biba_dominate_element(&rangea->mb_rangelow, &rangeb->mb_rangelow)); } static int mac_biba_single_in_range(struct mac_biba *single, struct mac_biba *range) { KASSERT((single->mb_flags & MAC_BIBA_FLAG_SINGLE) != 0, ("mac_biba_single_in_range: a not single")); KASSERT((range->mb_flags & MAC_BIBA_FLAG_RANGE) != 0, ("mac_biba_single_in_range: b not range")); return (mac_biba_dominate_element(&range->mb_rangehigh, &single->mb_single) && mac_biba_dominate_element(&single->mb_single, &range->mb_rangelow)); return (1); } static int mac_biba_dominate_single(struct mac_biba *a, struct mac_biba *b) { KASSERT((a->mb_flags & MAC_BIBA_FLAG_SINGLE) != 0, ("mac_biba_dominate_single: a not single")); KASSERT((b->mb_flags & MAC_BIBA_FLAG_SINGLE) != 0, ("mac_biba_dominate_single: b not single")); return (mac_biba_dominate_element(&a->mb_single, &b->mb_single)); } static int mac_biba_equal_element(struct mac_biba_element *a, struct mac_biba_element *b) { if (a->mbe_type == MAC_BIBA_TYPE_EQUAL || b->mbe_type == MAC_BIBA_TYPE_EQUAL) return (1); return (a->mbe_type == b->mbe_type && a->mbe_grade == b->mbe_grade); } static int mac_biba_equal_single(struct mac_biba *a, struct mac_biba *b) { KASSERT((a->mb_flags & MAC_BIBA_FLAG_SINGLE) != 0, ("mac_biba_equal_single: a not single")); KASSERT((b->mb_flags & MAC_BIBA_FLAG_SINGLE) != 0, ("mac_biba_equal_single: b not single")); return (mac_biba_equal_element(&a->mb_single, &b->mb_single)); } static int mac_biba_contains_equal(struct mac_biba *mac_biba) { if (mac_biba->mb_flags & MAC_BIBA_FLAG_SINGLE) if (mac_biba->mb_single.mbe_type == MAC_BIBA_TYPE_EQUAL) return (1); if (mac_biba->mb_flags & MAC_BIBA_FLAG_RANGE) { if (mac_biba->mb_rangelow.mbe_type == MAC_BIBA_TYPE_EQUAL) return (1); if (mac_biba->mb_rangehigh.mbe_type == MAC_BIBA_TYPE_EQUAL) return (1); } return (0); } static int mac_biba_subject_privileged(struct mac_biba *mac_biba) { KASSERT((mac_biba->mb_flags & MAC_BIBA_FLAGS_BOTH) == MAC_BIBA_FLAGS_BOTH, ("mac_biba_subject_privileged: subject doesn't have both labels")); /* If the single is EQUAL, it's ok. */ if (mac_biba->mb_single.mbe_type == MAC_BIBA_TYPE_EQUAL) return (0); /* If either range endpoint is EQUAL, it's ok. */ if (mac_biba->mb_rangelow.mbe_type == MAC_BIBA_TYPE_EQUAL || mac_biba->mb_rangehigh.mbe_type == MAC_BIBA_TYPE_EQUAL) return (0); /* If the range is low-high, it's ok. */ if (mac_biba->mb_rangelow.mbe_type == MAC_BIBA_TYPE_LOW && mac_biba->mb_rangehigh.mbe_type == MAC_BIBA_TYPE_HIGH) return (0); /* It's not ok. */ return (EPERM); } static int mac_biba_high_single(struct mac_biba *mac_biba) { KASSERT((mac_biba->mb_flags & MAC_BIBA_FLAG_SINGLE) != 0, ("mac_biba_equal_single: mac_biba not single")); return (mac_biba->mb_single.mbe_type == MAC_BIBA_TYPE_HIGH); } static int mac_biba_valid(struct mac_biba *mac_biba) { if (mac_biba->mb_flags & MAC_BIBA_FLAG_SINGLE) { switch (mac_biba->mb_single.mbe_type) { case MAC_BIBA_TYPE_GRADE: break; case MAC_BIBA_TYPE_EQUAL: case MAC_BIBA_TYPE_HIGH: case MAC_BIBA_TYPE_LOW: if (mac_biba->mb_single.mbe_grade != 0 || !MAC_BIBA_BIT_SET_EMPTY( mac_biba->mb_single.mbe_compartments)) return (EINVAL); break; default: return (EINVAL); } } else { if (mac_biba->mb_single.mbe_type != MAC_BIBA_TYPE_UNDEF) return (EINVAL); } if (mac_biba->mb_flags & MAC_BIBA_FLAG_RANGE) { switch (mac_biba->mb_rangelow.mbe_type) { case MAC_BIBA_TYPE_GRADE: break; case MAC_BIBA_TYPE_EQUAL: case MAC_BIBA_TYPE_HIGH: case MAC_BIBA_TYPE_LOW: if (mac_biba->mb_rangelow.mbe_grade != 0 || !MAC_BIBA_BIT_SET_EMPTY( mac_biba->mb_rangelow.mbe_compartments)) return (EINVAL); break; default: return (EINVAL); } switch (mac_biba->mb_rangehigh.mbe_type) { case MAC_BIBA_TYPE_GRADE: break; case MAC_BIBA_TYPE_EQUAL: case MAC_BIBA_TYPE_HIGH: case MAC_BIBA_TYPE_LOW: if (mac_biba->mb_rangehigh.mbe_grade != 0 || !MAC_BIBA_BIT_SET_EMPTY( mac_biba->mb_rangehigh.mbe_compartments)) return (EINVAL); break; default: return (EINVAL); } if (!mac_biba_dominate_element(&mac_biba->mb_rangehigh, &mac_biba->mb_rangelow)) return (EINVAL); } else { if (mac_biba->mb_rangelow.mbe_type != MAC_BIBA_TYPE_UNDEF || mac_biba->mb_rangehigh.mbe_type != MAC_BIBA_TYPE_UNDEF) return (EINVAL); } return (0); } static void mac_biba_set_range(struct mac_biba *mac_biba, u_short typelow, u_short gradelow, u_char *compartmentslow, u_short typehigh, u_short gradehigh, u_char *compartmentshigh) { mac_biba->mb_rangelow.mbe_type = typelow; mac_biba->mb_rangelow.mbe_grade = gradelow; if (compartmentslow != NULL) memcpy(mac_biba->mb_rangelow.mbe_compartments, compartmentslow, sizeof(mac_biba->mb_rangelow.mbe_compartments)); mac_biba->mb_rangehigh.mbe_type = typehigh; mac_biba->mb_rangehigh.mbe_grade = gradehigh; if (compartmentshigh != NULL) memcpy(mac_biba->mb_rangehigh.mbe_compartments, compartmentshigh, sizeof(mac_biba->mb_rangehigh.mbe_compartments)); mac_biba->mb_flags |= MAC_BIBA_FLAG_RANGE; } static void mac_biba_set_single(struct mac_biba *mac_biba, u_short type, u_short grade, u_char *compartments) { mac_biba->mb_single.mbe_type = type; mac_biba->mb_single.mbe_grade = grade; if (compartments != NULL) memcpy(mac_biba->mb_single.mbe_compartments, compartments, sizeof(mac_biba->mb_single.mbe_compartments)); mac_biba->mb_flags |= MAC_BIBA_FLAG_SINGLE; } static void mac_biba_copy_range(struct mac_biba *labelfrom, struct mac_biba *labelto) { KASSERT((labelfrom->mb_flags & MAC_BIBA_FLAG_RANGE) != 0, ("mac_biba_copy_range: labelfrom not range")); labelto->mb_rangelow = labelfrom->mb_rangelow; labelto->mb_rangehigh = labelfrom->mb_rangehigh; labelto->mb_flags |= MAC_BIBA_FLAG_RANGE; } static void mac_biba_copy_single(struct mac_biba *labelfrom, struct mac_biba *labelto) { KASSERT((labelfrom->mb_flags & MAC_BIBA_FLAG_SINGLE) != 0, ("mac_biba_copy_single: labelfrom not single")); labelto->mb_single = labelfrom->mb_single; labelto->mb_flags |= MAC_BIBA_FLAG_SINGLE; } static void mac_biba_copy(struct mac_biba *source, struct mac_biba *dest) { if (source->mb_flags & MAC_BIBA_FLAG_SINGLE) mac_biba_copy_single(source, dest); if (source->mb_flags & MAC_BIBA_FLAG_RANGE) mac_biba_copy_range(source, dest); } /* * Policy module operations. */ static void mac_biba_init(struct mac_policy_conf *conf) { zone_biba = uma_zcreate("mac_biba", sizeof(struct mac_biba), NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); } /* * Label operations. */ static void mac_biba_init_label(struct label *label) { SLOT(label) = biba_alloc(M_WAITOK); } static int mac_biba_init_label_waitcheck(struct label *label, int flag) { SLOT(label) = biba_alloc(flag); if (SLOT(label) == NULL) return (ENOMEM); return (0); } static void mac_biba_destroy_label(struct label *label) { biba_free(SLOT(label)); SLOT(label) = NULL; } /* * mac_biba_element_to_string() accepts an sbuf and Biba element. It * converts the Biba element to a string and stores the result in the * sbuf; if there isn't space in the sbuf, -1 is returned. */ static int mac_biba_element_to_string(struct sbuf *sb, struct mac_biba_element *element) { int i, first; switch (element->mbe_type) { case MAC_BIBA_TYPE_HIGH: return (sbuf_printf(sb, "high")); case MAC_BIBA_TYPE_LOW: return (sbuf_printf(sb, "low")); case MAC_BIBA_TYPE_EQUAL: return (sbuf_printf(sb, "equal")); case MAC_BIBA_TYPE_GRADE: if (sbuf_printf(sb, "%d", element->mbe_grade) == -1) return (-1); first = 1; for (i = 1; i <= MAC_BIBA_MAX_COMPARTMENTS; i++) { if (MAC_BIBA_BIT_TEST(i, element->mbe_compartments)) { if (first) { if (sbuf_putc(sb, ':') == -1) return (-1); if (sbuf_printf(sb, "%d", i) == -1) return (-1); first = 0; } else { if (sbuf_printf(sb, "+%d", i) == -1) return (-1); } } } return (0); default: panic("mac_biba_element_to_string: invalid type (%d)", element->mbe_type); } } /* * mac_biba_to_string() converts a Biba label to a string, and places * the results in the passed sbuf. It returns 0 on success, or EINVAL * if there isn't room in the sbuf. Note: the sbuf will be modified * even in a failure case, so the caller may need to revert the sbuf * by restoring the offset if that's undesired. */ static int mac_biba_to_string(struct sbuf *sb, struct mac_biba *mac_biba) { if (mac_biba->mb_flags & MAC_BIBA_FLAG_SINGLE) { if (mac_biba_element_to_string(sb, &mac_biba->mb_single) == -1) return (EINVAL); } if (mac_biba->mb_flags & MAC_BIBA_FLAG_RANGE) { if (sbuf_putc(sb, '(') == -1) return (EINVAL); if (mac_biba_element_to_string(sb, &mac_biba->mb_rangelow) == -1) return (EINVAL); if (sbuf_putc(sb, '-') == -1) return (EINVAL); if (mac_biba_element_to_string(sb, &mac_biba->mb_rangehigh) == -1) return (EINVAL); if (sbuf_putc(sb, ')') == -1) return (EINVAL); } return (0); } static int mac_biba_externalize_label(struct label *label, char *element_name, struct sbuf *sb, int *claimed) { struct mac_biba *mac_biba; if (strcmp(MAC_BIBA_LABEL_NAME, element_name) != 0) return (0); (*claimed)++; mac_biba = SLOT(label); return (mac_biba_to_string(sb, mac_biba)); } static int mac_biba_parse_element(struct mac_biba_element *element, char *string) { char *compartment, *end, *grade; int value; if (strcmp(string, "high") == 0 || strcmp(string, "hi") == 0) { element->mbe_type = MAC_BIBA_TYPE_HIGH; element->mbe_grade = MAC_BIBA_TYPE_UNDEF; } else if (strcmp(string, "low") == 0 || strcmp(string, "lo") == 0) { element->mbe_type = MAC_BIBA_TYPE_LOW; element->mbe_grade = MAC_BIBA_TYPE_UNDEF; } else if (strcmp(string, "equal") == 0 || strcmp(string, "eq") == 0) { element->mbe_type = MAC_BIBA_TYPE_EQUAL; element->mbe_grade = MAC_BIBA_TYPE_UNDEF; } else { element->mbe_type = MAC_BIBA_TYPE_GRADE; /* * Numeric grade piece of the element. */ grade = strsep(&string, ":"); value = strtol(grade, &end, 10); if (end == grade || *end != '\0') return (EINVAL); if (value < 0 || value > 65535) return (EINVAL); element->mbe_grade = value; /* * Optional compartment piece of the element. If none * are included, we assume that the label has no * compartments. */ if (string == NULL) return (0); if (*string == '\0') return (0); while ((compartment = strsep(&string, "+")) != NULL) { value = strtol(compartment, &end, 10); if (compartment == end || *end != '\0') return (EINVAL); if (value < 1 || value > MAC_BIBA_MAX_COMPARTMENTS) return (EINVAL); MAC_BIBA_BIT_SET(value, element->mbe_compartments); } } return (0); } /* * Note: destructively consumes the string, make a local copy before * calling if that's a problem. */ static int mac_biba_parse(struct mac_biba *mac_biba, char *string) { char *rangehigh, *rangelow, *single; int error; single = strsep(&string, "("); if (*single == '\0') single = NULL; if (string != NULL) { rangelow = strsep(&string, "-"); if (string == NULL) return (EINVAL); rangehigh = strsep(&string, ")"); if (string == NULL) return (EINVAL); if (*string != '\0') return (EINVAL); } else { rangelow = NULL; rangehigh = NULL; } KASSERT((rangelow != NULL && rangehigh != NULL) || (rangelow == NULL && rangehigh == NULL), ("mac_biba_parse: range mismatch")); bzero(mac_biba, sizeof(*mac_biba)); if (single != NULL) { error = mac_biba_parse_element(&mac_biba->mb_single, single); if (error) return (error); mac_biba->mb_flags |= MAC_BIBA_FLAG_SINGLE; } if (rangelow != NULL) { error = mac_biba_parse_element(&mac_biba->mb_rangelow, rangelow); if (error) return (error); error = mac_biba_parse_element(&mac_biba->mb_rangehigh, rangehigh); if (error) return (error); mac_biba->mb_flags |= MAC_BIBA_FLAG_RANGE; } error = mac_biba_valid(mac_biba); if (error) return (error); return (0); } static int mac_biba_internalize_label(struct label *label, char *element_name, char *element_data, int *claimed) { struct mac_biba *mac_biba, mac_biba_temp; int error; if (strcmp(MAC_BIBA_LABEL_NAME, element_name) != 0) return (0); (*claimed)++; error = mac_biba_parse(&mac_biba_temp, element_data); if (error) return (error); mac_biba = SLOT(label); *mac_biba = mac_biba_temp; return (0); } static void mac_biba_copy_label(struct label *src, struct label *dest) { *SLOT(dest) = *SLOT(src); } /* * Labeling event operations: file system objects, and things that look * a lot like file system objects. */ static void mac_biba_create_devfs_device(struct mount *mp, dev_t dev, struct devfs_dirent *devfs_dirent, struct label *label) { struct mac_biba *mac_biba; int biba_type; mac_biba = SLOT(label); if (strcmp(dev->si_name, "null") == 0 || strcmp(dev->si_name, "zero") == 0 || strcmp(dev->si_name, "random") == 0 || strncmp(dev->si_name, "fd/", strlen("fd/")) == 0) biba_type = MAC_BIBA_TYPE_EQUAL; else if (ptys_equal && (strncmp(dev->si_name, "ttyp", strlen("ttyp")) == 0 || strncmp(dev->si_name, "ptyp", strlen("ptyp")) == 0)) biba_type = MAC_BIBA_TYPE_EQUAL; else biba_type = MAC_BIBA_TYPE_HIGH; mac_biba_set_single(mac_biba, biba_type, 0, NULL); } static void mac_biba_create_devfs_directory(struct mount *mp, char *dirname, int dirnamelen, struct devfs_dirent *devfs_dirent, struct label *label) { struct mac_biba *mac_biba; mac_biba = SLOT(label); mac_biba_set_single(mac_biba, MAC_BIBA_TYPE_HIGH, 0, NULL); } static void mac_biba_create_devfs_symlink(struct ucred *cred, struct mount *mp, struct devfs_dirent *dd, struct label *ddlabel, struct devfs_dirent *de, struct label *delabel) { struct mac_biba *source, *dest; source = SLOT(cred->cr_label); dest = SLOT(delabel); mac_biba_copy_single(source, dest); } static void mac_biba_create_mount(struct ucred *cred, struct mount *mp, struct label *mntlabel, struct label *fslabel) { struct mac_biba *source, *dest; source = SLOT(cred->cr_label); dest = SLOT(mntlabel); mac_biba_copy_single(source, dest); dest = SLOT(fslabel); mac_biba_copy_single(source, dest); } static void mac_biba_create_root_mount(struct ucred *cred, struct mount *mp, struct label *mntlabel, struct label *fslabel) { struct mac_biba *mac_biba; /* Always mount root as high integrity. */ mac_biba = SLOT(fslabel); mac_biba_set_single(mac_biba, MAC_BIBA_TYPE_HIGH, 0, NULL); mac_biba = SLOT(mntlabel); mac_biba_set_single(mac_biba, MAC_BIBA_TYPE_HIGH, 0, NULL); } static void mac_biba_relabel_vnode(struct ucred *cred, struct vnode *vp, struct label *vnodelabel, struct label *label) { struct mac_biba *source, *dest; source = SLOT(label); dest = SLOT(vnodelabel); mac_biba_copy(source, dest); } static void mac_biba_update_devfsdirent(struct mount *mp, struct devfs_dirent *devfs_dirent, struct label *direntlabel, struct vnode *vp, struct label *vnodelabel) { struct mac_biba *source, *dest; source = SLOT(vnodelabel); dest = SLOT(direntlabel); mac_biba_copy(source, dest); } static void mac_biba_associate_vnode_devfs(struct mount *mp, struct label *fslabel, struct devfs_dirent *de, struct label *delabel, struct vnode *vp, struct label *vlabel) { struct mac_biba *source, *dest; source = SLOT(delabel); dest = SLOT(vlabel); mac_biba_copy_single(source, dest); } static int mac_biba_associate_vnode_extattr(struct mount *mp, struct label *fslabel, struct vnode *vp, struct label *vlabel) { struct mac_biba temp, *source, *dest; int buflen, error; source = SLOT(fslabel); dest = SLOT(vlabel); buflen = sizeof(temp); bzero(&temp, buflen); error = vn_extattr_get(vp, IO_NODELOCKED, MAC_BIBA_EXTATTR_NAMESPACE, MAC_BIBA_EXTATTR_NAME, &buflen, (char *) &temp, curthread); if (error == ENOATTR || error == EOPNOTSUPP) { /* Fall back to the fslabel. */ mac_biba_copy_single(source, dest); return (0); } else if (error) return (error); if (buflen != sizeof(temp)) { printf("mac_biba_associate_vnode_extattr: bad size %d\n", buflen); return (EPERM); } if (mac_biba_valid(&temp) != 0) { printf("mac_biba_associate_vnode_extattr: invalid\n"); return (EPERM); } if ((temp.mb_flags & MAC_BIBA_FLAGS_BOTH) != MAC_BIBA_FLAG_SINGLE) { printf("mac_biba_associate_vnode_extattr: not single\n"); return (EPERM); } mac_biba_copy_single(&temp, dest); return (0); } static void mac_biba_associate_vnode_singlelabel(struct mount *mp, struct label *fslabel, struct vnode *vp, struct label *vlabel) { struct mac_biba *source, *dest; source = SLOT(fslabel); dest = SLOT(vlabel); mac_biba_copy_single(source, dest); } static int mac_biba_create_vnode_extattr(struct ucred *cred, struct mount *mp, struct label *fslabel, struct vnode *dvp, struct label *dlabel, struct vnode *vp, struct label *vlabel, struct componentname *cnp) { struct mac_biba *source, *dest, temp; size_t buflen; int error; buflen = sizeof(temp); bzero(&temp, buflen); source = SLOT(cred->cr_label); dest = SLOT(vlabel); mac_biba_copy_single(source, &temp); error = vn_extattr_set(vp, IO_NODELOCKED, MAC_BIBA_EXTATTR_NAMESPACE, MAC_BIBA_EXTATTR_NAME, buflen, (char *) &temp, curthread); if (error == 0) mac_biba_copy_single(source, dest); return (error); } static int mac_biba_setlabel_vnode_extattr(struct ucred *cred, struct vnode *vp, struct label *vlabel, struct label *intlabel) { struct mac_biba *source, temp; size_t buflen; int error; buflen = sizeof(temp); bzero(&temp, buflen); source = SLOT(intlabel); if ((source->mb_flags & MAC_BIBA_FLAG_SINGLE) == 0) return (0); mac_biba_copy_single(source, &temp); error = vn_extattr_set(vp, IO_NODELOCKED, MAC_BIBA_EXTATTR_NAMESPACE, MAC_BIBA_EXTATTR_NAME, buflen, (char *) &temp, curthread); return (error); } /* * Labeling event operations: IPC object. */ static void mac_biba_create_inpcb_from_socket(struct socket *so, struct label *solabel, struct inpcb *inp, struct label *inplabel) { struct mac_biba *source, *dest; source = SLOT(solabel); dest = SLOT(inplabel); mac_biba_copy_single(source, dest); } static void mac_biba_create_mbuf_from_socket(struct socket *so, struct label *socketlabel, struct mbuf *m, struct label *mbuflabel) { struct mac_biba *source, *dest; source = SLOT(socketlabel); dest = SLOT(mbuflabel); mac_biba_copy_single(source, dest); } static void mac_biba_create_socket(struct ucred *cred, struct socket *socket, struct label *socketlabel) { struct mac_biba *source, *dest; source = SLOT(cred->cr_label); dest = SLOT(socketlabel); mac_biba_copy_single(source, dest); } static void -mac_biba_create_pipe(struct ucred *cred, struct pipe *pipe, +mac_biba_create_pipe(struct ucred *cred, struct pipepair *pp, struct label *pipelabel) { struct mac_biba *source, *dest; source = SLOT(cred->cr_label); dest = SLOT(pipelabel); mac_biba_copy_single(source, dest); } static void mac_biba_create_socket_from_socket(struct socket *oldsocket, struct label *oldsocketlabel, struct socket *newsocket, struct label *newsocketlabel) { struct mac_biba *source, *dest; source = SLOT(oldsocketlabel); dest = SLOT(newsocketlabel); mac_biba_copy_single(source, dest); } static void mac_biba_relabel_socket(struct ucred *cred, struct socket *socket, struct label *socketlabel, struct label *newlabel) { struct mac_biba *source, *dest; source = SLOT(newlabel); dest = SLOT(socketlabel); mac_biba_copy(source, dest); } static void -mac_biba_relabel_pipe(struct ucred *cred, struct pipe *pipe, +mac_biba_relabel_pipe(struct ucred *cred, struct pipepair *pp, struct label *pipelabel, struct label *newlabel) { struct mac_biba *source, *dest; source = SLOT(newlabel); dest = SLOT(pipelabel); mac_biba_copy(source, dest); } static void mac_biba_set_socket_peer_from_mbuf(struct mbuf *mbuf, struct label *mbuflabel, struct socket *socket, struct label *socketpeerlabel) { struct mac_biba *source, *dest; source = SLOT(mbuflabel); dest = SLOT(socketpeerlabel); mac_biba_copy_single(source, dest); } /* * Labeling event operations: network objects. */ static void mac_biba_set_socket_peer_from_socket(struct socket *oldsocket, struct label *oldsocketlabel, struct socket *newsocket, struct label *newsocketpeerlabel) { struct mac_biba *source, *dest; source = SLOT(oldsocketlabel); dest = SLOT(newsocketpeerlabel); mac_biba_copy_single(source, dest); } static void mac_biba_create_bpfdesc(struct ucred *cred, struct bpf_d *bpf_d, struct label *bpflabel) { struct mac_biba *source, *dest; source = SLOT(cred->cr_label); dest = SLOT(bpflabel); mac_biba_copy_single(source, dest); } static void mac_biba_create_ifnet(struct ifnet *ifnet, struct label *ifnetlabel) { char tifname[IFNAMSIZ], *p, *q; char tiflist[sizeof(trusted_interfaces)]; struct mac_biba *dest; int len, type; dest = SLOT(ifnetlabel); if (ifnet->if_type == IFT_LOOP) { type = MAC_BIBA_TYPE_EQUAL; goto set; } if (trust_all_interfaces) { type = MAC_BIBA_TYPE_HIGH; goto set; } type = MAC_BIBA_TYPE_LOW; if (trusted_interfaces[0] == '\0' || !strvalid(trusted_interfaces, sizeof(trusted_interfaces))) goto set; bzero(tiflist, sizeof(tiflist)); for (p = trusted_interfaces, q = tiflist; *p != '\0'; p++, q++) if(*p != ' ' && *p != '\t') *q = *p; for (p = q = tiflist;; p++) { if (*p == ',' || *p == '\0') { len = p - q; if (len < IFNAMSIZ) { bzero(tifname, sizeof(tifname)); bcopy(q, tifname, len); if (strcmp(tifname, ifnet->if_xname) == 0) { type = MAC_BIBA_TYPE_HIGH; break; } } else { *p = '\0'; printf("mac_biba warning: interface name " "\"%s\" is too long (must be < %d)\n", q, IFNAMSIZ); } if (*p == '\0') break; q = p + 1; } } set: mac_biba_set_single(dest, type, 0, NULL); mac_biba_set_range(dest, type, 0, NULL, type, 0, NULL); } static void mac_biba_create_ipq(struct mbuf *fragment, struct label *fragmentlabel, struct ipq *ipq, struct label *ipqlabel) { struct mac_biba *source, *dest; source = SLOT(fragmentlabel); dest = SLOT(ipqlabel); mac_biba_copy_single(source, dest); } static void mac_biba_create_datagram_from_ipq(struct ipq *ipq, struct label *ipqlabel, struct mbuf *datagram, struct label *datagramlabel) { struct mac_biba *source, *dest; source = SLOT(ipqlabel); dest = SLOT(datagramlabel); /* Just use the head, since we require them all to match. */ mac_biba_copy_single(source, dest); } static void mac_biba_create_fragment(struct mbuf *datagram, struct label *datagramlabel, struct mbuf *fragment, struct label *fragmentlabel) { struct mac_biba *source, *dest; source = SLOT(datagramlabel); dest = SLOT(fragmentlabel); mac_biba_copy_single(source, dest); } static void mac_biba_create_mbuf_from_inpcb(struct inpcb *inp, struct label *inplabel, struct mbuf *m, struct label *mlabel) { struct mac_biba *source, *dest; source = SLOT(inplabel); dest = SLOT(mlabel); mac_biba_copy_single(source, dest); } static void mac_biba_create_mbuf_from_mbuf(struct mbuf *oldmbuf, struct label *oldmbuflabel, struct mbuf *newmbuf, struct label *newmbuflabel) { struct mac_biba *source, *dest; source = SLOT(oldmbuflabel); dest = SLOT(newmbuflabel); /* * Because the source mbuf may not yet have been "created", * just initialized, we do a conditional copy. Since we don't * allow mbufs to have ranges, do a KASSERT to make sure that * doesn't happen. */ KASSERT((source->mb_flags & MAC_BIBA_FLAG_RANGE) == 0, ("mac_biba_create_mbuf_from_mbuf: source mbuf has range")); mac_biba_copy(source, dest); } static void mac_biba_create_mbuf_linklayer(struct ifnet *ifnet, struct label *ifnetlabel, struct mbuf *mbuf, struct label *mbuflabel) { struct mac_biba *dest; dest = SLOT(mbuflabel); mac_biba_set_single(dest, MAC_BIBA_TYPE_EQUAL, 0, NULL); } static void mac_biba_create_mbuf_from_bpfdesc(struct bpf_d *bpf_d, struct label *bpflabel, struct mbuf *mbuf, struct label *mbuflabel) { struct mac_biba *source, *dest; source = SLOT(bpflabel); dest = SLOT(mbuflabel); mac_biba_copy_single(source, dest); } static void mac_biba_create_mbuf_from_ifnet(struct ifnet *ifnet, struct label *ifnetlabel, struct mbuf *m, struct label *mbuflabel) { struct mac_biba *source, *dest; source = SLOT(ifnetlabel); dest = SLOT(mbuflabel); mac_biba_copy_single(source, dest); } static void mac_biba_create_mbuf_multicast_encap(struct mbuf *oldmbuf, struct label *oldmbuflabel, struct ifnet *ifnet, struct label *ifnetlabel, struct mbuf *newmbuf, struct label *newmbuflabel) { struct mac_biba *source, *dest; source = SLOT(oldmbuflabel); dest = SLOT(newmbuflabel); mac_biba_copy_single(source, dest); } static void mac_biba_create_mbuf_netlayer(struct mbuf *oldmbuf, struct label *oldmbuflabel, struct mbuf *newmbuf, struct label *newmbuflabel) { struct mac_biba *source, *dest; source = SLOT(oldmbuflabel); dest = SLOT(newmbuflabel); mac_biba_copy_single(source, dest); } static int mac_biba_fragment_match(struct mbuf *fragment, struct label *fragmentlabel, struct ipq *ipq, struct label *ipqlabel) { struct mac_biba *a, *b; a = SLOT(ipqlabel); b = SLOT(fragmentlabel); return (mac_biba_equal_single(a, b)); } static void mac_biba_relabel_ifnet(struct ucred *cred, struct ifnet *ifnet, struct label *ifnetlabel, struct label *newlabel) { struct mac_biba *source, *dest; source = SLOT(newlabel); dest = SLOT(ifnetlabel); mac_biba_copy(source, dest); } static void mac_biba_update_ipq(struct mbuf *fragment, struct label *fragmentlabel, struct ipq *ipq, struct label *ipqlabel) { /* NOOP: we only accept matching labels, so no need to update */ } static void mac_biba_inpcb_sosetlabel(struct socket *so, struct label *solabel, struct inpcb *inp, struct label *inplabel) { struct mac_biba *source, *dest; source = SLOT(solabel); dest = SLOT(inplabel); mac_biba_copy(source, dest); } /* * Labeling event operations: processes. */ static void mac_biba_create_proc0(struct ucred *cred) { struct mac_biba *dest; dest = SLOT(cred->cr_label); mac_biba_set_single(dest, MAC_BIBA_TYPE_EQUAL, 0, NULL); mac_biba_set_range(dest, MAC_BIBA_TYPE_LOW, 0, NULL, MAC_BIBA_TYPE_HIGH, 0, NULL); } static void mac_biba_create_proc1(struct ucred *cred) { struct mac_biba *dest; dest = SLOT(cred->cr_label); mac_biba_set_single(dest, MAC_BIBA_TYPE_HIGH, 0, NULL); mac_biba_set_range(dest, MAC_BIBA_TYPE_LOW, 0, NULL, MAC_BIBA_TYPE_HIGH, 0, NULL); } static void mac_biba_relabel_cred(struct ucred *cred, struct label *newlabel) { struct mac_biba *source, *dest; source = SLOT(newlabel); dest = SLOT(cred->cr_label); mac_biba_copy(source, dest); } /* * Access control checks. */ static int mac_biba_check_bpfdesc_receive(struct bpf_d *bpf_d, struct label *bpflabel, struct ifnet *ifnet, struct label *ifnetlabel) { struct mac_biba *a, *b; if (!mac_biba_enabled) return (0); a = SLOT(bpflabel); b = SLOT(ifnetlabel); if (mac_biba_equal_single(a, b)) return (0); return (EACCES); } static int mac_biba_check_cred_relabel(struct ucred *cred, struct label *newlabel) { struct mac_biba *subj, *new; int error; subj = SLOT(cred->cr_label); new = SLOT(newlabel); /* * If there is a Biba label update for the credential, it may * be an update of the single, range, or both. */ error = biba_atmostflags(new, MAC_BIBA_FLAGS_BOTH); if (error) return (error); /* * If the Biba label is to be changed, authorize as appropriate. */ if (new->mb_flags & MAC_BIBA_FLAGS_BOTH) { /* * If the change request modifies both the Biba label * single and range, check that the new single will be * in the new range. */ if ((new->mb_flags & MAC_BIBA_FLAGS_BOTH) == MAC_BIBA_FLAGS_BOTH && !mac_biba_single_in_range(new, new)) return (EINVAL); /* * To change the Biba single label on a credential, the * new single label must be in the current range. */ if (new->mb_flags & MAC_BIBA_FLAG_SINGLE && !mac_biba_single_in_range(new, subj)) return (EPERM); /* * To change the Biba range on a credential, the new * range label must be in the current range. */ if (new->mb_flags & MAC_BIBA_FLAG_RANGE && !mac_biba_range_in_range(new, subj)) return (EPERM); /* * To have EQUAL in any component of the new credential * Biba label, the subject must already have EQUAL in * their label. */ if (mac_biba_contains_equal(new)) { error = mac_biba_subject_privileged(subj); if (error) return (error); } } return (0); } static int mac_biba_check_cred_visible(struct ucred *u1, struct ucred *u2) { struct mac_biba *subj, *obj; if (!mac_biba_enabled) return (0); subj = SLOT(u1->cr_label); obj = SLOT(u2->cr_label); /* XXX: range */ if (!mac_biba_dominate_single(obj, subj)) return (ESRCH); return (0); } static int mac_biba_check_ifnet_relabel(struct ucred *cred, struct ifnet *ifnet, struct label *ifnetlabel, struct label *newlabel) { struct mac_biba *subj, *new; int error; subj = SLOT(cred->cr_label); new = SLOT(newlabel); /* * If there is a Biba label update for the interface, it may * be an update of the single, range, or both. */ error = biba_atmostflags(new, MAC_BIBA_FLAGS_BOTH); if (error) return (error); /* * Relabling network interfaces requires Biba privilege. */ error = mac_biba_subject_privileged(subj); if (error) return (error); return (0); } static int mac_biba_check_ifnet_transmit(struct ifnet *ifnet, struct label *ifnetlabel, struct mbuf *m, struct label *mbuflabel) { struct mac_biba *p, *i; if (!mac_biba_enabled) return (0); p = SLOT(mbuflabel); i = SLOT(ifnetlabel); return (mac_biba_single_in_range(p, i) ? 0 : EACCES); } static int mac_biba_check_inpcb_deliver(struct inpcb *inp, struct label *inplabel, struct mbuf *m, struct label *mlabel) { struct mac_biba *p, *i; if (!mac_biba_enabled) return (0); p = SLOT(mlabel); i = SLOT(inplabel); return (mac_biba_equal_single(p, i) ? 0 : EACCES); } static int mac_biba_check_kld_load(struct ucred *cred, struct vnode *vp, struct label *label) { struct mac_biba *subj, *obj; int error; if (!mac_biba_enabled) return (0); subj = SLOT(cred->cr_label); error = mac_biba_subject_privileged(subj); if (error) return (error); obj = SLOT(label); if (!mac_biba_high_single(obj)) return (EACCES); return (0); } static int mac_biba_check_kld_unload(struct ucred *cred) { struct mac_biba *subj; if (!mac_biba_enabled) return (0); subj = SLOT(cred->cr_label); return (mac_biba_subject_privileged(subj)); } static int mac_biba_check_mount_stat(struct ucred *cred, struct mount *mp, struct label *mntlabel) { struct mac_biba *subj, *obj; if (!mac_biba_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(mntlabel); if (!mac_biba_dominate_single(obj, subj)) return (EACCES); return (0); } static int -mac_biba_check_pipe_ioctl(struct ucred *cred, struct pipe *pipe, +mac_biba_check_pipe_ioctl(struct ucred *cred, struct pipepair *pp, struct label *pipelabel, unsigned long cmd, void /* caddr_t */ *data) { if(!mac_biba_enabled) return (0); /* XXX: This will be implemented soon... */ return (0); } static int -mac_biba_check_pipe_poll(struct ucred *cred, struct pipe *pipe, +mac_biba_check_pipe_poll(struct ucred *cred, struct pipepair *pp, struct label *pipelabel) { struct mac_biba *subj, *obj; if (!mac_biba_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT((pipelabel)); if (!mac_biba_dominate_single(obj, subj)) return (EACCES); return (0); } static int -mac_biba_check_pipe_read(struct ucred *cred, struct pipe *pipe, +mac_biba_check_pipe_read(struct ucred *cred, struct pipepair *pp, struct label *pipelabel) { struct mac_biba *subj, *obj; if (!mac_biba_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT((pipelabel)); if (!mac_biba_dominate_single(obj, subj)) return (EACCES); return (0); } static int -mac_biba_check_pipe_relabel(struct ucred *cred, struct pipe *pipe, +mac_biba_check_pipe_relabel(struct ucred *cred, struct pipepair *pp, struct label *pipelabel, struct label *newlabel) { struct mac_biba *subj, *obj, *new; int error; new = SLOT(newlabel); subj = SLOT(cred->cr_label); obj = SLOT(pipelabel); /* * If there is a Biba label update for a pipe, it must be a * single update. */ error = biba_atmostflags(new, MAC_BIBA_FLAG_SINGLE); if (error) return (error); /* * To perform a relabel of a pipe (Biba label or not), Biba must * authorize the relabel. */ if (!mac_biba_single_in_range(obj, subj)) return (EPERM); /* * If the Biba label is to be changed, authorize as appropriate. */ if (new->mb_flags & MAC_BIBA_FLAG_SINGLE) { /* * To change the Biba label on a pipe, the new pipe label * must be in the subject range. */ if (!mac_biba_single_in_range(new, subj)) return (EPERM); /* * To change the Biba label on a pipe to be EQUAL, the * subject must have appropriate privilege. */ if (mac_biba_contains_equal(new)) { error = mac_biba_subject_privileged(subj); if (error) return (error); } } return (0); } static int -mac_biba_check_pipe_stat(struct ucred *cred, struct pipe *pipe, +mac_biba_check_pipe_stat(struct ucred *cred, struct pipepair *pp, struct label *pipelabel) { struct mac_biba *subj, *obj; if (!mac_biba_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT((pipelabel)); if (!mac_biba_dominate_single(obj, subj)) return (EACCES); return (0); } static int -mac_biba_check_pipe_write(struct ucred *cred, struct pipe *pipe, +mac_biba_check_pipe_write(struct ucred *cred, struct pipepair *pp, struct label *pipelabel) { struct mac_biba *subj, *obj; if (!mac_biba_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT((pipelabel)); if (!mac_biba_dominate_single(subj, obj)) return (EACCES); return (0); } static int mac_biba_check_proc_debug(struct ucred *cred, struct proc *proc) { struct mac_biba *subj, *obj; if (!mac_biba_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(proc->p_ucred->cr_label); /* XXX: range checks */ if (!mac_biba_dominate_single(obj, subj)) return (ESRCH); if (!mac_biba_dominate_single(subj, obj)) return (EACCES); return (0); } static int mac_biba_check_proc_sched(struct ucred *cred, struct proc *proc) { struct mac_biba *subj, *obj; if (!mac_biba_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(proc->p_ucred->cr_label); /* XXX: range checks */ if (!mac_biba_dominate_single(obj, subj)) return (ESRCH); if (!mac_biba_dominate_single(subj, obj)) return (EACCES); return (0); } static int mac_biba_check_proc_signal(struct ucred *cred, struct proc *proc, int signum) { struct mac_biba *subj, *obj; if (!mac_biba_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(proc->p_ucred->cr_label); /* XXX: range checks */ if (!mac_biba_dominate_single(obj, subj)) return (ESRCH); if (!mac_biba_dominate_single(subj, obj)) return (EACCES); return (0); } static int mac_biba_check_socket_deliver(struct socket *so, struct label *socketlabel, struct mbuf *m, struct label *mbuflabel) { struct mac_biba *p, *s; if (!mac_biba_enabled) return (0); p = SLOT(mbuflabel); s = SLOT(socketlabel); return (mac_biba_equal_single(p, s) ? 0 : EACCES); } static int mac_biba_check_socket_relabel(struct ucred *cred, struct socket *so, struct label *socketlabel, struct label *newlabel) { struct mac_biba *subj, *obj, *new; int error; new = SLOT(newlabel); subj = SLOT(cred->cr_label); obj = SLOT(socketlabel); /* * If there is a Biba label update for the socket, it may be * an update of single. */ error = biba_atmostflags(new, MAC_BIBA_FLAG_SINGLE); if (error) return (error); /* * To relabel a socket, the old socket single must be in the subject * range. */ if (!mac_biba_single_in_range(obj, subj)) return (EPERM); /* * If the Biba label is to be changed, authorize as appropriate. */ if (new->mb_flags & MAC_BIBA_FLAG_SINGLE) { /* * To relabel a socket, the new socket single must be in * the subject range. */ if (!mac_biba_single_in_range(new, subj)) return (EPERM); /* * To change the Biba label on the socket to contain EQUAL, * the subject must have appropriate privilege. */ if (mac_biba_contains_equal(new)) { error = mac_biba_subject_privileged(subj); if (error) return (error); } } return (0); } static int mac_biba_check_socket_visible(struct ucred *cred, struct socket *socket, struct label *socketlabel) { struct mac_biba *subj, *obj; if (!mac_biba_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(socketlabel); if (!mac_biba_dominate_single(obj, subj)) return (ENOENT); return (0); } static int mac_biba_check_sysarch_ioperm(struct ucred *cred) { struct mac_biba *subj; int error; if (!mac_biba_enabled) return (0); subj = SLOT(cred->cr_label); error = mac_biba_subject_privileged(subj); if (error) return (error); return (0); } static int mac_biba_check_system_acct(struct ucred *cred, struct vnode *vp, struct label *label) { struct mac_biba *subj, *obj; int error; if (!mac_biba_enabled) return (0); subj = SLOT(cred->cr_label); error = mac_biba_subject_privileged(subj); if (error) return (error); if (label == NULL) return (0); obj = SLOT(label); if (!mac_biba_high_single(obj)) return (EACCES); return (0); } static int mac_biba_check_system_settime(struct ucred *cred) { struct mac_biba *subj; int error; if (!mac_biba_enabled) return (0); subj = SLOT(cred->cr_label); error = mac_biba_subject_privileged(subj); if (error) return (error); return (0); } static int mac_biba_check_system_swapon(struct ucred *cred, struct vnode *vp, struct label *label) { struct mac_biba *subj, *obj; int error; if (!mac_biba_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(label); error = mac_biba_subject_privileged(subj); if (error) return (error); if (!mac_biba_high_single(obj)) return (EACCES); return (0); } static int mac_biba_check_system_swapoff(struct ucred *cred, struct vnode *vp, struct label *label) { struct mac_biba *subj, *obj; int error; if (!mac_biba_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(label); error = mac_biba_subject_privileged(subj); if (error) return (error); return (0); } static int mac_biba_check_system_sysctl(struct ucred *cred, int *name, u_int namelen, void *old, size_t *oldlenp, int inkernel, void *new, size_t newlen) { struct mac_biba *subj; int error; if (!mac_biba_enabled) return (0); subj = SLOT(cred->cr_label); /* * In general, treat sysctl variables as biba/high, but also * require privilege to change them, since they are a * communications channel between grades. Exempt MIB * queries from this due to undocmented sysctl magic. * XXXMAC: This probably requires some more review. */ if (new != NULL) { if (namelen > 0 && name[0] == 0) return (0); if (!mac_biba_subject_dominate_high(subj)) return (EACCES); error = mac_biba_subject_privileged(subj); if (error) return (error); } return (0); } static int mac_biba_check_vnode_chdir(struct ucred *cred, struct vnode *dvp, struct label *dlabel) { struct mac_biba *subj, *obj; if (!mac_biba_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(dlabel); if (!mac_biba_dominate_single(obj, subj)) return (EACCES); return (0); } static int mac_biba_check_vnode_chroot(struct ucred *cred, struct vnode *dvp, struct label *dlabel) { struct mac_biba *subj, *obj; if (!mac_biba_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(dlabel); if (!mac_biba_dominate_single(obj, subj)) return (EACCES); return (0); } static int mac_biba_check_vnode_create(struct ucred *cred, struct vnode *dvp, struct label *dlabel, struct componentname *cnp, struct vattr *vap) { struct mac_biba *subj, *obj; if (!mac_biba_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(dlabel); if (!mac_biba_dominate_single(subj, obj)) return (EACCES); return (0); } static int mac_biba_check_vnode_delete(struct ucred *cred, struct vnode *dvp, struct label *dlabel, struct vnode *vp, struct label *label, struct componentname *cnp) { struct mac_biba *subj, *obj; if (!mac_biba_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(dlabel); if (!mac_biba_dominate_single(subj, obj)) return (EACCES); obj = SLOT(label); if (!mac_biba_dominate_single(subj, obj)) return (EACCES); return (0); } static int mac_biba_check_vnode_deleteacl(struct ucred *cred, struct vnode *vp, struct label *label, acl_type_t type) { struct mac_biba *subj, *obj; if (!mac_biba_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(label); if (!mac_biba_dominate_single(subj, obj)) return (EACCES); return (0); } static int mac_biba_check_vnode_deleteextattr(struct ucred *cred, struct vnode *vp, struct label *label, int attrnamespace, const char *name) { struct mac_biba *subj, *obj; if (!mac_biba_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(label); if (!mac_biba_dominate_single(subj, obj)) return (EACCES); return (0); } static int mac_biba_check_vnode_exec(struct ucred *cred, struct vnode *vp, struct label *label, struct image_params *imgp, struct label *execlabel) { struct mac_biba *subj, *obj, *exec; int error; if (execlabel != NULL) { /* * We currently don't permit labels to be changed at * exec-time as part of Biba, so disallow non-NULL * Biba label elements in the execlabel. */ exec = SLOT(execlabel); error = biba_atmostflags(exec, 0); if (error) return (error); } if (!mac_biba_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(label); if (!mac_biba_dominate_single(obj, subj)) return (EACCES); return (0); } static int mac_biba_check_vnode_getacl(struct ucred *cred, struct vnode *vp, struct label *label, acl_type_t type) { struct mac_biba *subj, *obj; if (!mac_biba_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(label); if (!mac_biba_dominate_single(obj, subj)) return (EACCES); return (0); } static int mac_biba_check_vnode_getextattr(struct ucred *cred, struct vnode *vp, struct label *label, int attrnamespace, const char *name, struct uio *uio) { struct mac_biba *subj, *obj; if (!mac_biba_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(label); if (!mac_biba_dominate_single(obj, subj)) return (EACCES); return (0); } static int mac_biba_check_vnode_link(struct ucred *cred, struct vnode *dvp, struct label *dlabel, struct vnode *vp, struct label *label, struct componentname *cnp) { struct mac_biba *subj, *obj; if (!mac_biba_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(dlabel); if (!mac_biba_dominate_single(subj, obj)) return (EACCES); obj = SLOT(label); if (!mac_biba_dominate_single(subj, obj)) return (EACCES); return (0); } static int mac_biba_check_vnode_listextattr(struct ucred *cred, struct vnode *vp, struct label *label, int attrnamespace) { struct mac_biba *subj, *obj; if (!mac_biba_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(label); if (!mac_biba_dominate_single(obj, subj)) return (EACCES); return (0); } static int mac_biba_check_vnode_lookup(struct ucred *cred, struct vnode *dvp, struct label *dlabel, struct componentname *cnp) { struct mac_biba *subj, *obj; if (!mac_biba_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(dlabel); if (!mac_biba_dominate_single(obj, subj)) return (EACCES); return (0); } static int mac_biba_check_vnode_mmap(struct ucred *cred, struct vnode *vp, struct label *label, int prot) { struct mac_biba *subj, *obj; /* * Rely on the use of open()-time protections to handle * non-revocation cases. */ if (!mac_biba_enabled || !revocation_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(label); if (prot & (VM_PROT_READ | VM_PROT_EXECUTE)) { if (!mac_biba_dominate_single(obj, subj)) return (EACCES); } if (prot & VM_PROT_WRITE) { if (!mac_biba_dominate_single(subj, obj)) return (EACCES); } return (0); } static int mac_biba_check_vnode_open(struct ucred *cred, struct vnode *vp, struct label *vnodelabel, int acc_mode) { struct mac_biba *subj, *obj; if (!mac_biba_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(vnodelabel); /* XXX privilege override for admin? */ if (acc_mode & (VREAD | VEXEC | VSTAT)) { if (!mac_biba_dominate_single(obj, subj)) return (EACCES); } if (acc_mode & (VWRITE | VAPPEND | VADMIN)) { if (!mac_biba_dominate_single(subj, obj)) return (EACCES); } return (0); } static int mac_biba_check_vnode_poll(struct ucred *active_cred, struct ucred *file_cred, struct vnode *vp, struct label *label) { struct mac_biba *subj, *obj; if (!mac_biba_enabled || !revocation_enabled) return (0); subj = SLOT(active_cred->cr_label); obj = SLOT(label); if (!mac_biba_dominate_single(obj, subj)) return (EACCES); return (0); } static int mac_biba_check_vnode_read(struct ucred *active_cred, struct ucred *file_cred, struct vnode *vp, struct label *label) { struct mac_biba *subj, *obj; if (!mac_biba_enabled || !revocation_enabled) return (0); subj = SLOT(active_cred->cr_label); obj = SLOT(label); if (!mac_biba_dominate_single(obj, subj)) return (EACCES); return (0); } static int mac_biba_check_vnode_readdir(struct ucred *cred, struct vnode *dvp, struct label *dlabel) { struct mac_biba *subj, *obj; if (!mac_biba_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(dlabel); if (!mac_biba_dominate_single(obj, subj)) return (EACCES); return (0); } static int mac_biba_check_vnode_readlink(struct ucred *cred, struct vnode *vp, struct label *label) { struct mac_biba *subj, *obj; if (!mac_biba_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(label); if (!mac_biba_dominate_single(obj, subj)) return (EACCES); return (0); } static int mac_biba_check_vnode_relabel(struct ucred *cred, struct vnode *vp, struct label *vnodelabel, struct label *newlabel) { struct mac_biba *old, *new, *subj; int error; old = SLOT(vnodelabel); new = SLOT(newlabel); subj = SLOT(cred->cr_label); /* * If there is a Biba label update for the vnode, it must be a * single label. */ error = biba_atmostflags(new, MAC_BIBA_FLAG_SINGLE); if (error) return (error); /* * To perform a relabel of the vnode (Biba label or not), Biba must * authorize the relabel. */ if (!mac_biba_single_in_range(old, subj)) return (EPERM); /* * If the Biba label is to be changed, authorize as appropriate. */ if (new->mb_flags & MAC_BIBA_FLAG_SINGLE) { /* * To change the Biba label on a vnode, the new vnode label * must be in the subject range. */ if (!mac_biba_single_in_range(new, subj)) return (EPERM); /* * To change the Biba label on the vnode to be EQUAL, * the subject must have appropriate privilege. */ if (mac_biba_contains_equal(new)) { error = mac_biba_subject_privileged(subj); if (error) return (error); } } return (0); } static int mac_biba_check_vnode_rename_from(struct ucred *cred, struct vnode *dvp, struct label *dlabel, struct vnode *vp, struct label *label, struct componentname *cnp) { struct mac_biba *subj, *obj; if (!mac_biba_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(dlabel); if (!mac_biba_dominate_single(subj, obj)) return (EACCES); obj = SLOT(label); if (!mac_biba_dominate_single(subj, obj)) return (EACCES); return (0); } static int mac_biba_check_vnode_rename_to(struct ucred *cred, struct vnode *dvp, struct label *dlabel, struct vnode *vp, struct label *label, int samedir, struct componentname *cnp) { struct mac_biba *subj, *obj; if (!mac_biba_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(dlabel); if (!mac_biba_dominate_single(subj, obj)) return (EACCES); if (vp != NULL) { obj = SLOT(label); if (!mac_biba_dominate_single(subj, obj)) return (EACCES); } return (0); } static int mac_biba_check_vnode_revoke(struct ucred *cred, struct vnode *vp, struct label *label) { struct mac_biba *subj, *obj; if (!mac_biba_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(label); if (!mac_biba_dominate_single(subj, obj)) return (EACCES); return (0); } static int mac_biba_check_vnode_setacl(struct ucred *cred, struct vnode *vp, struct label *label, acl_type_t type, struct acl *acl) { struct mac_biba *subj, *obj; if (!mac_biba_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(label); if (!mac_biba_dominate_single(subj, obj)) return (EACCES); return (0); } static int mac_biba_check_vnode_setextattr(struct ucred *cred, struct vnode *vp, struct label *vnodelabel, int attrnamespace, const char *name, struct uio *uio) { struct mac_biba *subj, *obj; if (!mac_biba_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(vnodelabel); if (!mac_biba_dominate_single(subj, obj)) return (EACCES); /* XXX: protect the MAC EA in a special way? */ return (0); } static int mac_biba_check_vnode_setflags(struct ucred *cred, struct vnode *vp, struct label *vnodelabel, u_long flags) { struct mac_biba *subj, *obj; if (!mac_biba_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(vnodelabel); if (!mac_biba_dominate_single(subj, obj)) return (EACCES); return (0); } static int mac_biba_check_vnode_setmode(struct ucred *cred, struct vnode *vp, struct label *vnodelabel, mode_t mode) { struct mac_biba *subj, *obj; if (!mac_biba_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(vnodelabel); if (!mac_biba_dominate_single(subj, obj)) return (EACCES); return (0); } static int mac_biba_check_vnode_setowner(struct ucred *cred, struct vnode *vp, struct label *vnodelabel, uid_t uid, gid_t gid) { struct mac_biba *subj, *obj; if (!mac_biba_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(vnodelabel); if (!mac_biba_dominate_single(subj, obj)) return (EACCES); return (0); } static int mac_biba_check_vnode_setutimes(struct ucred *cred, struct vnode *vp, struct label *vnodelabel, struct timespec atime, struct timespec mtime) { struct mac_biba *subj, *obj; if (!mac_biba_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(vnodelabel); if (!mac_biba_dominate_single(subj, obj)) return (EACCES); return (0); } static int mac_biba_check_vnode_stat(struct ucred *active_cred, struct ucred *file_cred, struct vnode *vp, struct label *vnodelabel) { struct mac_biba *subj, *obj; if (!mac_biba_enabled) return (0); subj = SLOT(active_cred->cr_label); obj = SLOT(vnodelabel); if (!mac_biba_dominate_single(obj, subj)) return (EACCES); return (0); } static int mac_biba_check_vnode_write(struct ucred *active_cred, struct ucred *file_cred, struct vnode *vp, struct label *label) { struct mac_biba *subj, *obj; if (!mac_biba_enabled || !revocation_enabled) return (0); subj = SLOT(active_cred->cr_label); obj = SLOT(label); if (!mac_biba_dominate_single(subj, obj)) return (EACCES); return (0); } static struct mac_policy_ops mac_biba_ops = { .mpo_init = mac_biba_init, .mpo_init_bpfdesc_label = mac_biba_init_label, .mpo_init_cred_label = mac_biba_init_label, .mpo_init_devfsdirent_label = mac_biba_init_label, .mpo_init_ifnet_label = mac_biba_init_label, .mpo_init_inpcb_label = mac_biba_init_label_waitcheck, .mpo_init_ipq_label = mac_biba_init_label_waitcheck, .mpo_init_mbuf_label = mac_biba_init_label_waitcheck, .mpo_init_mount_label = mac_biba_init_label, .mpo_init_mount_fs_label = mac_biba_init_label, .mpo_init_pipe_label = mac_biba_init_label, .mpo_init_socket_label = mac_biba_init_label_waitcheck, .mpo_init_socket_peer_label = mac_biba_init_label_waitcheck, .mpo_init_vnode_label = mac_biba_init_label, .mpo_destroy_bpfdesc_label = mac_biba_destroy_label, .mpo_destroy_cred_label = mac_biba_destroy_label, .mpo_destroy_devfsdirent_label = mac_biba_destroy_label, .mpo_destroy_ifnet_label = mac_biba_destroy_label, .mpo_destroy_inpcb_label = mac_biba_destroy_label, .mpo_destroy_ipq_label = mac_biba_destroy_label, .mpo_destroy_mbuf_label = mac_biba_destroy_label, .mpo_destroy_mount_label = mac_biba_destroy_label, .mpo_destroy_mount_fs_label = mac_biba_destroy_label, .mpo_destroy_pipe_label = mac_biba_destroy_label, .mpo_destroy_socket_label = mac_biba_destroy_label, .mpo_destroy_socket_peer_label = mac_biba_destroy_label, .mpo_destroy_vnode_label = mac_biba_destroy_label, .mpo_copy_cred_label = mac_biba_copy_label, .mpo_copy_mbuf_label = mac_biba_copy_label, .mpo_copy_pipe_label = mac_biba_copy_label, .mpo_copy_socket_label = mac_biba_copy_label, .mpo_copy_vnode_label = mac_biba_copy_label, .mpo_externalize_cred_label = mac_biba_externalize_label, .mpo_externalize_ifnet_label = mac_biba_externalize_label, .mpo_externalize_pipe_label = mac_biba_externalize_label, .mpo_externalize_socket_label = mac_biba_externalize_label, .mpo_externalize_socket_peer_label = mac_biba_externalize_label, .mpo_externalize_vnode_label = mac_biba_externalize_label, .mpo_internalize_cred_label = mac_biba_internalize_label, .mpo_internalize_ifnet_label = mac_biba_internalize_label, .mpo_internalize_pipe_label = mac_biba_internalize_label, .mpo_internalize_socket_label = mac_biba_internalize_label, .mpo_internalize_vnode_label = mac_biba_internalize_label, .mpo_create_devfs_device = mac_biba_create_devfs_device, .mpo_create_devfs_directory = mac_biba_create_devfs_directory, .mpo_create_devfs_symlink = mac_biba_create_devfs_symlink, .mpo_create_mount = mac_biba_create_mount, .mpo_create_root_mount = mac_biba_create_root_mount, .mpo_relabel_vnode = mac_biba_relabel_vnode, .mpo_update_devfsdirent = mac_biba_update_devfsdirent, .mpo_associate_vnode_devfs = mac_biba_associate_vnode_devfs, .mpo_associate_vnode_extattr = mac_biba_associate_vnode_extattr, .mpo_associate_vnode_singlelabel = mac_biba_associate_vnode_singlelabel, .mpo_create_vnode_extattr = mac_biba_create_vnode_extattr, .mpo_setlabel_vnode_extattr = mac_biba_setlabel_vnode_extattr, .mpo_create_mbuf_from_socket = mac_biba_create_mbuf_from_socket, .mpo_create_pipe = mac_biba_create_pipe, .mpo_create_socket = mac_biba_create_socket, .mpo_create_socket_from_socket = mac_biba_create_socket_from_socket, .mpo_relabel_pipe = mac_biba_relabel_pipe, .mpo_relabel_socket = mac_biba_relabel_socket, .mpo_set_socket_peer_from_mbuf = mac_biba_set_socket_peer_from_mbuf, .mpo_set_socket_peer_from_socket = mac_biba_set_socket_peer_from_socket, .mpo_create_bpfdesc = mac_biba_create_bpfdesc, .mpo_create_datagram_from_ipq = mac_biba_create_datagram_from_ipq, .mpo_create_fragment = mac_biba_create_fragment, .mpo_create_ifnet = mac_biba_create_ifnet, .mpo_create_inpcb_from_socket = mac_biba_create_inpcb_from_socket, .mpo_create_ipq = mac_biba_create_ipq, .mpo_create_mbuf_from_inpcb = mac_biba_create_mbuf_from_inpcb, .mpo_create_mbuf_from_mbuf = mac_biba_create_mbuf_from_mbuf, .mpo_create_mbuf_linklayer = mac_biba_create_mbuf_linklayer, .mpo_create_mbuf_from_bpfdesc = mac_biba_create_mbuf_from_bpfdesc, .mpo_create_mbuf_from_ifnet = mac_biba_create_mbuf_from_ifnet, .mpo_create_mbuf_multicast_encap = mac_biba_create_mbuf_multicast_encap, .mpo_create_mbuf_netlayer = mac_biba_create_mbuf_netlayer, .mpo_fragment_match = mac_biba_fragment_match, .mpo_relabel_ifnet = mac_biba_relabel_ifnet, .mpo_update_ipq = mac_biba_update_ipq, .mpo_inpcb_sosetlabel = mac_biba_inpcb_sosetlabel, .mpo_create_proc0 = mac_biba_create_proc0, .mpo_create_proc1 = mac_biba_create_proc1, .mpo_relabel_cred = mac_biba_relabel_cred, .mpo_check_bpfdesc_receive = mac_biba_check_bpfdesc_receive, .mpo_check_cred_relabel = mac_biba_check_cred_relabel, .mpo_check_cred_visible = mac_biba_check_cred_visible, .mpo_check_ifnet_relabel = mac_biba_check_ifnet_relabel, .mpo_check_ifnet_transmit = mac_biba_check_ifnet_transmit, .mpo_check_inpcb_deliver = mac_biba_check_inpcb_deliver, .mpo_check_kld_load = mac_biba_check_kld_load, .mpo_check_kld_unload = mac_biba_check_kld_unload, .mpo_check_mount_stat = mac_biba_check_mount_stat, .mpo_check_pipe_ioctl = mac_biba_check_pipe_ioctl, .mpo_check_pipe_poll = mac_biba_check_pipe_poll, .mpo_check_pipe_read = mac_biba_check_pipe_read, .mpo_check_pipe_relabel = mac_biba_check_pipe_relabel, .mpo_check_pipe_stat = mac_biba_check_pipe_stat, .mpo_check_pipe_write = mac_biba_check_pipe_write, .mpo_check_proc_debug = mac_biba_check_proc_debug, .mpo_check_proc_sched = mac_biba_check_proc_sched, .mpo_check_proc_signal = mac_biba_check_proc_signal, .mpo_check_socket_deliver = mac_biba_check_socket_deliver, .mpo_check_socket_relabel = mac_biba_check_socket_relabel, .mpo_check_socket_visible = mac_biba_check_socket_visible, .mpo_check_sysarch_ioperm = mac_biba_check_sysarch_ioperm, .mpo_check_system_acct = mac_biba_check_system_acct, .mpo_check_system_settime = mac_biba_check_system_settime, .mpo_check_system_swapon = mac_biba_check_system_swapon, .mpo_check_system_swapoff = mac_biba_check_system_swapoff, .mpo_check_system_sysctl = mac_biba_check_system_sysctl, .mpo_check_vnode_access = mac_biba_check_vnode_open, .mpo_check_vnode_chdir = mac_biba_check_vnode_chdir, .mpo_check_vnode_chroot = mac_biba_check_vnode_chroot, .mpo_check_vnode_create = mac_biba_check_vnode_create, .mpo_check_vnode_delete = mac_biba_check_vnode_delete, .mpo_check_vnode_deleteacl = mac_biba_check_vnode_deleteacl, .mpo_check_vnode_deleteextattr = mac_biba_check_vnode_deleteextattr, .mpo_check_vnode_exec = mac_biba_check_vnode_exec, .mpo_check_vnode_getacl = mac_biba_check_vnode_getacl, .mpo_check_vnode_getextattr = mac_biba_check_vnode_getextattr, .mpo_check_vnode_link = mac_biba_check_vnode_link, .mpo_check_vnode_listextattr = mac_biba_check_vnode_listextattr, .mpo_check_vnode_lookup = mac_biba_check_vnode_lookup, .mpo_check_vnode_mmap = mac_biba_check_vnode_mmap, .mpo_check_vnode_mprotect = mac_biba_check_vnode_mmap, .mpo_check_vnode_open = mac_biba_check_vnode_open, .mpo_check_vnode_poll = mac_biba_check_vnode_poll, .mpo_check_vnode_read = mac_biba_check_vnode_read, .mpo_check_vnode_readdir = mac_biba_check_vnode_readdir, .mpo_check_vnode_readlink = mac_biba_check_vnode_readlink, .mpo_check_vnode_relabel = mac_biba_check_vnode_relabel, .mpo_check_vnode_rename_from = mac_biba_check_vnode_rename_from, .mpo_check_vnode_rename_to = mac_biba_check_vnode_rename_to, .mpo_check_vnode_revoke = mac_biba_check_vnode_revoke, .mpo_check_vnode_setacl = mac_biba_check_vnode_setacl, .mpo_check_vnode_setextattr = mac_biba_check_vnode_setextattr, .mpo_check_vnode_setflags = mac_biba_check_vnode_setflags, .mpo_check_vnode_setmode = mac_biba_check_vnode_setmode, .mpo_check_vnode_setowner = mac_biba_check_vnode_setowner, .mpo_check_vnode_setutimes = mac_biba_check_vnode_setutimes, .mpo_check_vnode_stat = mac_biba_check_vnode_stat, .mpo_check_vnode_write = mac_biba_check_vnode_write, }; MAC_POLICY_SET(&mac_biba_ops, mac_biba, "TrustedBSD MAC/Biba", MPC_LOADTIME_FLAG_NOTLATE | MPC_LOADTIME_FLAG_LABELMBUFS, &mac_biba_slot); Index: head/sys/security/mac_lomac/mac_lomac.c =================================================================== --- head/sys/security/mac_lomac/mac_lomac.c (revision 125292) +++ head/sys/security/mac_lomac/mac_lomac.c (revision 125293) @@ -1,2758 +1,2758 @@ /*- * Copyright (c) 1999, 2000, 2001, 2002 Robert N. M. Watson * Copyright (c) 2001, 2002, 2003 Networks Associates Technology, Inc. * All rights reserved. * * This software was developed by Robert Watson for the TrustedBSD Project. * * This software was developed for the FreeBSD Project in part by NAI Labs, * the Security Research Division of Network Associates, Inc. under * DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA * CHATS research program. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ /* * Developed by the TrustedBSD Project. * Low-watermark floating label mandatory integrity policy. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include struct mac_lomac_proc { struct mac_lomac mac_lomac; struct mtx mtx; }; SYSCTL_DECL(_security_mac); SYSCTL_NODE(_security_mac, OID_AUTO, lomac, CTLFLAG_RW, 0, "TrustedBSD mac_lomac policy controls"); static int mac_lomac_label_size = sizeof(struct mac_lomac); SYSCTL_INT(_security_mac_lomac, OID_AUTO, label_size, CTLFLAG_RD, &mac_lomac_label_size, 0, "Size of struct mac_lomac"); static int mac_lomac_enabled = 1; SYSCTL_INT(_security_mac_lomac, OID_AUTO, enabled, CTLFLAG_RW, &mac_lomac_enabled, 0, "Enforce MAC/LOMAC policy"); TUNABLE_INT("security.mac.lomac.enabled", &mac_lomac_enabled); static int destroyed_not_inited; SYSCTL_INT(_security_mac_lomac, OID_AUTO, destroyed_not_inited, CTLFLAG_RD, &destroyed_not_inited, 0, "Count of labels destroyed but not inited"); static int trust_all_interfaces = 0; SYSCTL_INT(_security_mac_lomac, OID_AUTO, trust_all_interfaces, CTLFLAG_RD, &trust_all_interfaces, 0, "Consider all interfaces 'trusted' by MAC/LOMAC"); TUNABLE_INT("security.mac.lomac.trust_all_interfaces", &trust_all_interfaces); static char trusted_interfaces[128]; SYSCTL_STRING(_security_mac_lomac, OID_AUTO, trusted_interfaces, CTLFLAG_RD, trusted_interfaces, 0, "Interfaces considered 'trusted' by MAC/LOMAC"); TUNABLE_STR("security.mac.lomac.trusted_interfaces", trusted_interfaces, sizeof(trusted_interfaces)); static int ptys_equal = 0; SYSCTL_INT(_security_mac_lomac, OID_AUTO, ptys_equal, CTLFLAG_RW, &ptys_equal, 0, "Label pty devices as lomac/equal on create"); TUNABLE_INT("security.mac.lomac.ptys_equal", &ptys_equal); static int revocation_enabled = 1; SYSCTL_INT(_security_mac_lomac, OID_AUTO, revocation_enabled, CTLFLAG_RW, &revocation_enabled, 0, "Revoke access to objects on relabel"); TUNABLE_INT("security.mac.lomac.revocation_enabled", &revocation_enabled); static int mac_lomac_slot; #define SLOT(l) ((struct mac_lomac *)LABEL_TO_SLOT((l), mac_lomac_slot).l_ptr) #define PSLOT(l) ((struct mac_lomac_proc *) \ LABEL_TO_SLOT((l), mac_lomac_slot).l_ptr) MALLOC_DEFINE(M_MACLOMAC, "lomac label", "MAC/LOMAC labels"); static struct mac_lomac * lomac_alloc(int flag) { struct mac_lomac *mac_lomac; mac_lomac = malloc(sizeof(struct mac_lomac), M_MACLOMAC, M_ZERO | flag); return (mac_lomac); } static void lomac_free(struct mac_lomac *mac_lomac) { if (mac_lomac != NULL) free(mac_lomac, M_MACLOMAC); else atomic_add_int(&destroyed_not_inited, 1); } static int lomac_atmostflags(struct mac_lomac *mac_lomac, int flags) { if ((mac_lomac->ml_flags & flags) != mac_lomac->ml_flags) return (EINVAL); return (0); } static int mac_lomac_dominate_element(struct mac_lomac_element *a, struct mac_lomac_element *b) { switch (a->mle_type) { case MAC_LOMAC_TYPE_EQUAL: case MAC_LOMAC_TYPE_HIGH: return (1); case MAC_LOMAC_TYPE_LOW: switch (b->mle_type) { case MAC_LOMAC_TYPE_GRADE: case MAC_LOMAC_TYPE_HIGH: return (0); case MAC_LOMAC_TYPE_EQUAL: case MAC_LOMAC_TYPE_LOW: return (1); default: panic("mac_lomac_dominate_element: b->mle_type invalid"); } case MAC_LOMAC_TYPE_GRADE: switch (b->mle_type) { case MAC_LOMAC_TYPE_EQUAL: case MAC_LOMAC_TYPE_LOW: return (1); case MAC_LOMAC_TYPE_HIGH: return (0); case MAC_LOMAC_TYPE_GRADE: return (a->mle_grade >= b->mle_grade); default: panic("mac_lomac_dominate_element: b->mle_type invalid"); } default: panic("mac_lomac_dominate_element: a->mle_type invalid"); } } static int mac_lomac_range_in_range(struct mac_lomac *rangea, struct mac_lomac *rangeb) { return (mac_lomac_dominate_element(&rangeb->ml_rangehigh, &rangea->ml_rangehigh) && mac_lomac_dominate_element(&rangea->ml_rangelow, &rangeb->ml_rangelow)); } static int mac_lomac_single_in_range(struct mac_lomac *single, struct mac_lomac *range) { KASSERT((single->ml_flags & MAC_LOMAC_FLAG_SINGLE) != 0, ("mac_lomac_single_in_range: a not single")); KASSERT((range->ml_flags & MAC_LOMAC_FLAG_RANGE) != 0, ("mac_lomac_single_in_range: b not range")); return (mac_lomac_dominate_element(&range->ml_rangehigh, &single->ml_single) && mac_lomac_dominate_element(&single->ml_single, &range->ml_rangelow)); } static int mac_lomac_auxsingle_in_range(struct mac_lomac *single, struct mac_lomac *range) { KASSERT((single->ml_flags & MAC_LOMAC_FLAG_AUX) != 0, ("mac_lomac_single_in_range: a not auxsingle")); KASSERT((range->ml_flags & MAC_LOMAC_FLAG_RANGE) != 0, ("mac_lomac_single_in_range: b not range")); return (mac_lomac_dominate_element(&range->ml_rangehigh, &single->ml_auxsingle) && mac_lomac_dominate_element(&single->ml_auxsingle, &range->ml_rangelow)); } static int mac_lomac_dominate_single(struct mac_lomac *a, struct mac_lomac *b) { KASSERT((a->ml_flags & MAC_LOMAC_FLAG_SINGLE) != 0, ("mac_lomac_dominate_single: a not single")); KASSERT((b->ml_flags & MAC_LOMAC_FLAG_SINGLE) != 0, ("mac_lomac_dominate_single: b not single")); return (mac_lomac_dominate_element(&a->ml_single, &b->ml_single)); } static int mac_lomac_subject_dominate(struct mac_lomac *a, struct mac_lomac *b) { KASSERT((~a->ml_flags & (MAC_LOMAC_FLAG_SINGLE | MAC_LOMAC_FLAG_RANGE)) == 0, ("mac_lomac_dominate_single: a not subject")); KASSERT((b->ml_flags & MAC_LOMAC_FLAG_SINGLE) != 0, ("mac_lomac_dominate_single: b not single")); return (mac_lomac_dominate_element(&a->ml_rangehigh, &b->ml_single)); } static int mac_lomac_equal_element(struct mac_lomac_element *a, struct mac_lomac_element *b) { if (a->mle_type == MAC_LOMAC_TYPE_EQUAL || b->mle_type == MAC_LOMAC_TYPE_EQUAL) return (1); return (a->mle_type == b->mle_type && a->mle_grade == b->mle_grade); } static int mac_lomac_equal_single(struct mac_lomac *a, struct mac_lomac *b) { KASSERT((a->ml_flags & MAC_LOMAC_FLAG_SINGLE) != 0, ("mac_lomac_equal_single: a not single")); KASSERT((b->ml_flags & MAC_LOMAC_FLAG_SINGLE) != 0, ("mac_lomac_equal_single: b not single")); return (mac_lomac_equal_element(&a->ml_single, &b->ml_single)); } static int mac_lomac_contains_equal(struct mac_lomac *mac_lomac) { if (mac_lomac->ml_flags & MAC_LOMAC_FLAG_SINGLE) if (mac_lomac->ml_single.mle_type == MAC_LOMAC_TYPE_EQUAL) return (1); if (mac_lomac->ml_flags & MAC_LOMAC_FLAG_AUX) if (mac_lomac->ml_auxsingle.mle_type == MAC_LOMAC_TYPE_EQUAL) return (1); if (mac_lomac->ml_flags & MAC_LOMAC_FLAG_RANGE) { if (mac_lomac->ml_rangelow.mle_type == MAC_LOMAC_TYPE_EQUAL) return (1); if (mac_lomac->ml_rangehigh.mle_type == MAC_LOMAC_TYPE_EQUAL) return (1); } return (0); } static int mac_lomac_subject_privileged(struct mac_lomac *mac_lomac) { KASSERT((mac_lomac->ml_flags & MAC_LOMAC_FLAGS_BOTH) == MAC_LOMAC_FLAGS_BOTH, ("mac_lomac_subject_privileged: subject doesn't have both labels")); /* If the single is EQUAL, it's ok. */ if (mac_lomac->ml_single.mle_type == MAC_LOMAC_TYPE_EQUAL) return (0); /* If either range endpoint is EQUAL, it's ok. */ if (mac_lomac->ml_rangelow.mle_type == MAC_LOMAC_TYPE_EQUAL || mac_lomac->ml_rangehigh.mle_type == MAC_LOMAC_TYPE_EQUAL) return (0); /* If the range is low-high, it's ok. */ if (mac_lomac->ml_rangelow.mle_type == MAC_LOMAC_TYPE_LOW && mac_lomac->ml_rangehigh.mle_type == MAC_LOMAC_TYPE_HIGH) return (0); /* It's not ok. */ return (EPERM); } static int mac_lomac_high_single(struct mac_lomac *mac_lomac) { KASSERT((mac_lomac->ml_flags & MAC_LOMAC_FLAG_SINGLE) != 0, ("mac_lomac_high_single: mac_lomac not single")); return (mac_lomac->ml_single.mle_type == MAC_LOMAC_TYPE_HIGH); } static int mac_lomac_valid(struct mac_lomac *mac_lomac) { if (mac_lomac->ml_flags & MAC_LOMAC_FLAG_SINGLE) { switch (mac_lomac->ml_single.mle_type) { case MAC_LOMAC_TYPE_GRADE: case MAC_LOMAC_TYPE_EQUAL: case MAC_LOMAC_TYPE_HIGH: case MAC_LOMAC_TYPE_LOW: break; default: return (EINVAL); } } else { if (mac_lomac->ml_single.mle_type != MAC_LOMAC_TYPE_UNDEF) return (EINVAL); } if (mac_lomac->ml_flags & MAC_LOMAC_FLAG_AUX) { switch (mac_lomac->ml_auxsingle.mle_type) { case MAC_LOMAC_TYPE_GRADE: case MAC_LOMAC_TYPE_EQUAL: case MAC_LOMAC_TYPE_HIGH: case MAC_LOMAC_TYPE_LOW: break; default: return (EINVAL); } } else { if (mac_lomac->ml_auxsingle.mle_type != MAC_LOMAC_TYPE_UNDEF) return (EINVAL); } if (mac_lomac->ml_flags & MAC_LOMAC_FLAG_RANGE) { switch (mac_lomac->ml_rangelow.mle_type) { case MAC_LOMAC_TYPE_GRADE: case MAC_LOMAC_TYPE_EQUAL: case MAC_LOMAC_TYPE_HIGH: case MAC_LOMAC_TYPE_LOW: break; default: return (EINVAL); } switch (mac_lomac->ml_rangehigh.mle_type) { case MAC_LOMAC_TYPE_GRADE: case MAC_LOMAC_TYPE_EQUAL: case MAC_LOMAC_TYPE_HIGH: case MAC_LOMAC_TYPE_LOW: break; default: return (EINVAL); } if (!mac_lomac_dominate_element(&mac_lomac->ml_rangehigh, &mac_lomac->ml_rangelow)) return (EINVAL); } else { if (mac_lomac->ml_rangelow.mle_type != MAC_LOMAC_TYPE_UNDEF || mac_lomac->ml_rangehigh.mle_type != MAC_LOMAC_TYPE_UNDEF) return (EINVAL); } return (0); } static void mac_lomac_set_range(struct mac_lomac *mac_lomac, u_short typelow, u_short gradelow, u_short typehigh, u_short gradehigh) { mac_lomac->ml_rangelow.mle_type = typelow; mac_lomac->ml_rangelow.mle_grade = gradelow; mac_lomac->ml_rangehigh.mle_type = typehigh; mac_lomac->ml_rangehigh.mle_grade = gradehigh; mac_lomac->ml_flags |= MAC_LOMAC_FLAG_RANGE; } static void mac_lomac_set_single(struct mac_lomac *mac_lomac, u_short type, u_short grade) { mac_lomac->ml_single.mle_type = type; mac_lomac->ml_single.mle_grade = grade; mac_lomac->ml_flags |= MAC_LOMAC_FLAG_SINGLE; } static void mac_lomac_copy_range(struct mac_lomac *labelfrom, struct mac_lomac *labelto) { KASSERT((labelfrom->ml_flags & MAC_LOMAC_FLAG_RANGE) != 0, ("mac_lomac_copy_range: labelfrom not range")); labelto->ml_rangelow = labelfrom->ml_rangelow; labelto->ml_rangehigh = labelfrom->ml_rangehigh; labelto->ml_flags |= MAC_LOMAC_FLAG_RANGE; } static void mac_lomac_copy_single(struct mac_lomac *labelfrom, struct mac_lomac *labelto) { KASSERT((labelfrom->ml_flags & MAC_LOMAC_FLAG_SINGLE) != 0, ("mac_lomac_copy_single: labelfrom not single")); labelto->ml_single = labelfrom->ml_single; labelto->ml_flags |= MAC_LOMAC_FLAG_SINGLE; } static void mac_lomac_copy_auxsingle(struct mac_lomac *labelfrom, struct mac_lomac *labelto) { KASSERT((labelfrom->ml_flags & MAC_LOMAC_FLAG_AUX) != 0, ("mac_lomac_copy_auxsingle: labelfrom not auxsingle")); labelto->ml_auxsingle = labelfrom->ml_auxsingle; labelto->ml_flags |= MAC_LOMAC_FLAG_AUX; } static void mac_lomac_copy(struct mac_lomac *source, struct mac_lomac *dest) { if (source->ml_flags & MAC_LOMAC_FLAG_SINGLE) mac_lomac_copy_single(source, dest); if (source->ml_flags & MAC_LOMAC_FLAG_AUX) mac_lomac_copy_auxsingle(source, dest); if (source->ml_flags & MAC_LOMAC_FLAG_RANGE) mac_lomac_copy_range(source, dest); } static int mac_lomac_to_string(struct sbuf *sb, struct mac_lomac *mac_lomac); static int maybe_demote(struct mac_lomac *subjlabel, struct mac_lomac *objlabel, const char *actionname, const char *objname, struct vnode *vpq) { struct sbuf subjlabel_sb, subjtext_sb, objlabel_sb; char *subjlabeltext, *objlabeltext, *subjtext; struct mac_lomac cached_subjlabel; struct mac_lomac_proc *subj; struct vattr va; struct proc *p; pid_t pgid; subj = PSLOT(curthread->td_proc->p_label); p = curthread->td_proc; mtx_lock(&subj->mtx); if (subj->mac_lomac.ml_flags & MAC_LOMAC_FLAG_UPDATE) { /* * Check to see if the pending demotion would be more or * less severe than this one, and keep the more severe. * This can only happen for a multi-threaded application. */ if (mac_lomac_dominate_single(objlabel, &subj->mac_lomac)) { mtx_unlock(&subj->mtx); return (0); } } bzero(&subj->mac_lomac, sizeof(subj->mac_lomac)); /* * Always demote the single label. */ mac_lomac_copy_single(objlabel, &subj->mac_lomac); /* * Start with the original range, then minimize each side of * the range to the point of not dominating the object. The * high side will always be demoted, of course. */ mac_lomac_copy_range(subjlabel, &subj->mac_lomac); if (!mac_lomac_dominate_element(&objlabel->ml_single, &subj->mac_lomac.ml_rangelow)) subj->mac_lomac.ml_rangelow = objlabel->ml_single; subj->mac_lomac.ml_rangehigh = objlabel->ml_single; subj->mac_lomac.ml_flags |= MAC_LOMAC_FLAG_UPDATE; mtx_lock_spin(&sched_lock); curthread->td_flags |= TDF_ASTPENDING; curthread->td_proc->p_sflag |= PS_MACPEND; mtx_unlock_spin(&sched_lock); /* * Avoid memory allocation while holding a mutex; cache the * label. */ mac_lomac_copy_single(&subj->mac_lomac, &cached_subjlabel); mtx_unlock(&subj->mtx); sbuf_new(&subjlabel_sb, NULL, 0, SBUF_AUTOEXTEND); mac_lomac_to_string(&subjlabel_sb, subjlabel); sbuf_finish(&subjlabel_sb); subjlabeltext = sbuf_data(&subjlabel_sb); sbuf_new(&subjtext_sb, NULL, 0, SBUF_AUTOEXTEND); mac_lomac_to_string(&subjtext_sb, &subj->mac_lomac); sbuf_finish(&subjtext_sb); subjtext = sbuf_data(&subjtext_sb); sbuf_new(&objlabel_sb, NULL, 0, SBUF_AUTOEXTEND); mac_lomac_to_string(&objlabel_sb, objlabel); sbuf_finish(&objlabel_sb); objlabeltext = sbuf_data(&objlabel_sb); pgid = p->p_pgrp->pg_id; /* XXX could be stale? */ if (vpq != NULL && VOP_GETATTR(vpq, &va, curthread->td_ucred, curthread) == 0) { log(LOG_INFO, "LOMAC: level-%s subject p%dg%du%d:%s demoted to" " level %s after %s a level-%s %s (inode=%ld, " "mountpount=%s)\n", subjlabeltext, p->p_pid, pgid, curthread->td_ucred->cr_uid, p->p_comm, subjtext, actionname, objlabeltext, objname, va.va_fileid, vpq->v_mount->mnt_stat.f_mntonname); } else { log(LOG_INFO, "LOMAC: level-%s subject p%dg%du%d:%s demoted to" " level %s after %s a level-%s %s\n", subjlabeltext, p->p_pid, pgid, curthread->td_ucred->cr_uid, p->p_comm, subjtext, actionname, objlabeltext, objname); } sbuf_delete(&subjlabel_sb); sbuf_delete(&subjtext_sb); sbuf_delete(&objlabel_sb); return (0); } /* * Relabel "to" to "from" only if "from" is a valid label (contains * at least a single), as for a relabel operation which may or may * not involve a relevant label. */ static void try_relabel(struct mac_lomac *from, struct mac_lomac *to) { if (from->ml_flags & MAC_LOMAC_FLAG_SINGLE) { bzero(to, sizeof(*to)); mac_lomac_copy(from, to); } } /* * Policy module operations. */ static void mac_lomac_init(struct mac_policy_conf *conf) { } /* * Label operations. */ static void mac_lomac_init_label(struct label *label) { SLOT(label) = lomac_alloc(M_WAITOK); } static int mac_lomac_init_label_waitcheck(struct label *label, int flag) { SLOT(label) = lomac_alloc(flag); if (SLOT(label) == NULL) return (ENOMEM); return (0); } static void mac_lomac_init_proc_label(struct label *label) { PSLOT(label) = malloc(sizeof(struct mac_lomac_proc), M_MACLOMAC, M_ZERO | M_WAITOK); mtx_init(&PSLOT(label)->mtx, "MAC/Lomac proc lock", NULL, MTX_DEF); } static void mac_lomac_destroy_label(struct label *label) { lomac_free(SLOT(label)); SLOT(label) = NULL; } static void mac_lomac_destroy_proc_label(struct label *label) { mtx_destroy(&PSLOT(label)->mtx); FREE(PSLOT(label), M_MACLOMAC); PSLOT(label) = NULL; } static int mac_lomac_element_to_string(struct sbuf *sb, struct mac_lomac_element *element) { switch (element->mle_type) { case MAC_LOMAC_TYPE_HIGH: return (sbuf_printf(sb, "high")); case MAC_LOMAC_TYPE_LOW: return (sbuf_printf(sb, "low")); case MAC_LOMAC_TYPE_EQUAL: return (sbuf_printf(sb, "equal")); case MAC_LOMAC_TYPE_GRADE: return (sbuf_printf(sb, "%d", element->mle_grade)); default: panic("mac_lomac_element_to_string: invalid type (%d)", element->mle_type); } } static int mac_lomac_to_string(struct sbuf *sb, struct mac_lomac *mac_lomac) { if (mac_lomac->ml_flags & MAC_LOMAC_FLAG_SINGLE) { if (mac_lomac_element_to_string(sb, &mac_lomac->ml_single) == -1) return (EINVAL); } if (mac_lomac->ml_flags & MAC_LOMAC_FLAG_AUX) { if (sbuf_putc(sb, '[') == -1) return (EINVAL); if (mac_lomac_element_to_string(sb, &mac_lomac->ml_auxsingle) == -1) return (EINVAL); if (sbuf_putc(sb, ']') == -1) return (EINVAL); } if (mac_lomac->ml_flags & MAC_LOMAC_FLAG_RANGE) { if (sbuf_putc(sb, '(') == -1) return (EINVAL); if (mac_lomac_element_to_string(sb, &mac_lomac->ml_rangelow) == -1) return (EINVAL); if (sbuf_putc(sb, '-') == -1) return (EINVAL); if (mac_lomac_element_to_string(sb, &mac_lomac->ml_rangehigh) == -1) return (EINVAL); if (sbuf_putc(sb, ')') == -1) return (EINVAL); } return (0); } static int mac_lomac_externalize_label(struct label *label, char *element_name, struct sbuf *sb, int *claimed) { struct mac_lomac *mac_lomac; if (strcmp(MAC_LOMAC_LABEL_NAME, element_name) != 0) return (0); (*claimed)++; mac_lomac = SLOT(label); return (mac_lomac_to_string(sb, mac_lomac)); } static int mac_lomac_parse_element(struct mac_lomac_element *element, char *string) { if (strcmp(string, "high") == 0 || strcmp(string, "hi") == 0) { element->mle_type = MAC_LOMAC_TYPE_HIGH; element->mle_grade = MAC_LOMAC_TYPE_UNDEF; } else if (strcmp(string, "low") == 0 || strcmp(string, "lo") == 0) { element->mle_type = MAC_LOMAC_TYPE_LOW; element->mle_grade = MAC_LOMAC_TYPE_UNDEF; } else if (strcmp(string, "equal") == 0 || strcmp(string, "eq") == 0) { element->mle_type = MAC_LOMAC_TYPE_EQUAL; element->mle_grade = MAC_LOMAC_TYPE_UNDEF; } else { char *p0, *p1; int d; p0 = string; d = strtol(p0, &p1, 10); if (d < 0 || d > 65535) return (EINVAL); element->mle_type = MAC_LOMAC_TYPE_GRADE; element->mle_grade = d; if (p1 == p0 || *p1 != '\0') return (EINVAL); } return (0); } /* * Note: destructively consumes the string, make a local copy before * calling if that's a problem. */ static int mac_lomac_parse(struct mac_lomac *mac_lomac, char *string) { char *range, *rangeend, *rangehigh, *rangelow, *single, *auxsingle, *auxsingleend; int error; /* Do we have a range? */ single = string; range = index(string, '('); if (range == single) single = NULL; auxsingle = index(string, '['); if (auxsingle == single) single = NULL; if (range != NULL && auxsingle != NULL) return (EINVAL); rangelow = rangehigh = NULL; if (range != NULL) { /* Nul terminate the end of the single string. */ *range = '\0'; range++; rangelow = range; rangehigh = index(rangelow, '-'); if (rangehigh == NULL) return (EINVAL); rangehigh++; if (*rangelow == '\0' || *rangehigh == '\0') return (EINVAL); rangeend = index(rangehigh, ')'); if (rangeend == NULL) return (EINVAL); if (*(rangeend + 1) != '\0') return (EINVAL); /* Nul terminate the ends of the ranges. */ *(rangehigh - 1) = '\0'; *rangeend = '\0'; } KASSERT((rangelow != NULL && rangehigh != NULL) || (rangelow == NULL && rangehigh == NULL), ("mac_lomac_internalize_label: range mismatch")); if (auxsingle != NULL) { /* Nul terminate the end of the single string. */ *auxsingle = '\0'; auxsingle++; auxsingleend = index(auxsingle, ']'); if (auxsingleend == NULL) return (EINVAL); if (*(auxsingleend + 1) != '\0') return (EINVAL); /* Nul terminate the end of the auxsingle. */ *auxsingleend = '\0'; } bzero(mac_lomac, sizeof(*mac_lomac)); if (single != NULL) { error = mac_lomac_parse_element(&mac_lomac->ml_single, single); if (error) return (error); mac_lomac->ml_flags |= MAC_LOMAC_FLAG_SINGLE; } if (auxsingle != NULL) { error = mac_lomac_parse_element(&mac_lomac->ml_auxsingle, auxsingle); if (error) return (error); mac_lomac->ml_flags |= MAC_LOMAC_FLAG_AUX; } if (rangelow != NULL) { error = mac_lomac_parse_element(&mac_lomac->ml_rangelow, rangelow); if (error) return (error); error = mac_lomac_parse_element(&mac_lomac->ml_rangehigh, rangehigh); if (error) return (error); mac_lomac->ml_flags |= MAC_LOMAC_FLAG_RANGE; } error = mac_lomac_valid(mac_lomac); if (error) return (error); return (0); } static int mac_lomac_internalize_label(struct label *label, char *element_name, char *element_data, int *claimed) { struct mac_lomac *mac_lomac, mac_lomac_temp; int error; if (strcmp(MAC_LOMAC_LABEL_NAME, element_name) != 0) return (0); (*claimed)++; error = mac_lomac_parse(&mac_lomac_temp, element_data); if (error) return (error); mac_lomac = SLOT(label); *mac_lomac = mac_lomac_temp; return (0); } static void mac_lomac_copy_label(struct label *src, struct label *dest) { *SLOT(dest) = *SLOT(src); } /* * Labeling event operations: file system objects, and things that look * a lot like file system objects. */ static void mac_lomac_create_devfs_device(struct mount *mp, dev_t dev, struct devfs_dirent *devfs_dirent, struct label *label) { struct mac_lomac *mac_lomac; int lomac_type; mac_lomac = SLOT(label); if (strcmp(dev->si_name, "null") == 0 || strcmp(dev->si_name, "zero") == 0 || strcmp(dev->si_name, "random") == 0 || strncmp(dev->si_name, "fd/", strlen("fd/")) == 0 || strncmp(dev->si_name, "ttyv", strlen("ttyv")) == 0) lomac_type = MAC_LOMAC_TYPE_EQUAL; else if (ptys_equal && (strncmp(dev->si_name, "ttyp", strlen("ttyp")) == 0 || strncmp(dev->si_name, "ptyp", strlen("ptyp")) == 0)) lomac_type = MAC_LOMAC_TYPE_EQUAL; else lomac_type = MAC_LOMAC_TYPE_HIGH; mac_lomac_set_single(mac_lomac, lomac_type, 0); } static void mac_lomac_create_devfs_directory(struct mount *mp, char *dirname, int dirnamelen, struct devfs_dirent *devfs_dirent, struct label *label) { struct mac_lomac *mac_lomac; mac_lomac = SLOT(label); mac_lomac_set_single(mac_lomac, MAC_LOMAC_TYPE_HIGH, 0); } static void mac_lomac_create_devfs_symlink(struct ucred *cred, struct mount *mp, struct devfs_dirent *dd, struct label *ddlabel, struct devfs_dirent *de, struct label *delabel) { struct mac_lomac *source, *dest; source = SLOT(cred->cr_label); dest = SLOT(delabel); mac_lomac_copy_single(source, dest); } static void mac_lomac_create_mount(struct ucred *cred, struct mount *mp, struct label *mntlabel, struct label *fslabel) { struct mac_lomac *source, *dest; source = SLOT(cred->cr_label); dest = SLOT(mntlabel); mac_lomac_copy_single(source, dest); dest = SLOT(fslabel); mac_lomac_copy_single(source, dest); } static void mac_lomac_create_root_mount(struct ucred *cred, struct mount *mp, struct label *mntlabel, struct label *fslabel) { struct mac_lomac *mac_lomac; /* Always mount root as high integrity. */ mac_lomac = SLOT(fslabel); mac_lomac_set_single(mac_lomac, MAC_LOMAC_TYPE_HIGH, 0); mac_lomac = SLOT(mntlabel); mac_lomac_set_single(mac_lomac, MAC_LOMAC_TYPE_HIGH, 0); } static void mac_lomac_relabel_vnode(struct ucred *cred, struct vnode *vp, struct label *vnodelabel, struct label *label) { struct mac_lomac *source, *dest; source = SLOT(label); dest = SLOT(vnodelabel); try_relabel(source, dest); } static void mac_lomac_update_devfsdirent(struct mount *mp, struct devfs_dirent *devfs_dirent, struct label *direntlabel, struct vnode *vp, struct label *vnodelabel) { struct mac_lomac *source, *dest; source = SLOT(vnodelabel); dest = SLOT(direntlabel); mac_lomac_copy(source, dest); } static void mac_lomac_associate_vnode_devfs(struct mount *mp, struct label *fslabel, struct devfs_dirent *de, struct label *delabel, struct vnode *vp, struct label *vlabel) { struct mac_lomac *source, *dest; source = SLOT(delabel); dest = SLOT(vlabel); mac_lomac_copy_single(source, dest); } static int mac_lomac_associate_vnode_extattr(struct mount *mp, struct label *fslabel, struct vnode *vp, struct label *vlabel) { struct mac_lomac temp, *source, *dest; int buflen, error; source = SLOT(fslabel); dest = SLOT(vlabel); buflen = sizeof(temp); bzero(&temp, buflen); error = vn_extattr_get(vp, IO_NODELOCKED, MAC_LOMAC_EXTATTR_NAMESPACE, MAC_LOMAC_EXTATTR_NAME, &buflen, (char *)&temp, curthread); if (error == ENOATTR || error == EOPNOTSUPP) { /* Fall back to the fslabel. */ mac_lomac_copy_single(source, dest); return (0); } else if (error) return (error); if (buflen != sizeof(temp)) { if (buflen != sizeof(temp) - sizeof(temp.ml_auxsingle)) { printf("mac_lomac_associate_vnode_extattr: bad size %d\n", buflen); return (EPERM); } bzero(&temp.ml_auxsingle, sizeof(temp.ml_auxsingle)); buflen = sizeof(temp); (void)vn_extattr_set(vp, IO_NODELOCKED, MAC_LOMAC_EXTATTR_NAMESPACE, MAC_LOMAC_EXTATTR_NAME, buflen, (char *)&temp, curthread); } if (mac_lomac_valid(&temp) != 0) { printf("mac_lomac_associate_vnode_extattr: invalid\n"); return (EPERM); } if ((temp.ml_flags & MAC_LOMAC_FLAGS_BOTH) != MAC_LOMAC_FLAG_SINGLE) { printf("mac_lomac_associate_vnode_extattr: not single\n"); return (EPERM); } mac_lomac_copy_single(&temp, dest); return (0); } static void mac_lomac_associate_vnode_singlelabel(struct mount *mp, struct label *fslabel, struct vnode *vp, struct label *vlabel) { struct mac_lomac *source, *dest; source = SLOT(fslabel); dest = SLOT(vlabel); mac_lomac_copy_single(source, dest); } static int mac_lomac_create_vnode_extattr(struct ucred *cred, struct mount *mp, struct label *fslabel, struct vnode *dvp, struct label *dlabel, struct vnode *vp, struct label *vlabel, struct componentname *cnp) { struct mac_lomac *source, *dest, *dir, temp; size_t buflen; int error; buflen = sizeof(temp); bzero(&temp, buflen); source = SLOT(cred->cr_label); dest = SLOT(vlabel); dir = SLOT(dlabel); if (dir->ml_flags & MAC_LOMAC_FLAG_AUX) { mac_lomac_copy_auxsingle(dir, &temp); mac_lomac_set_single(&temp, dir->ml_auxsingle.mle_type, dir->ml_auxsingle.mle_grade); } else { mac_lomac_copy_single(source, &temp); } error = vn_extattr_set(vp, IO_NODELOCKED, MAC_LOMAC_EXTATTR_NAMESPACE, MAC_LOMAC_EXTATTR_NAME, buflen, (char *)&temp, curthread); if (error == 0) mac_lomac_copy(&temp, dest); return (error); } static int mac_lomac_setlabel_vnode_extattr(struct ucred *cred, struct vnode *vp, struct label *vlabel, struct label *intlabel) { struct mac_lomac *source, temp; size_t buflen; int error; buflen = sizeof(temp); bzero(&temp, buflen); source = SLOT(intlabel); if ((source->ml_flags & MAC_LOMAC_FLAG_SINGLE) == 0) return (0); mac_lomac_copy_single(source, &temp); error = vn_extattr_set(vp, IO_NODELOCKED, MAC_LOMAC_EXTATTR_NAMESPACE, MAC_LOMAC_EXTATTR_NAME, buflen, (char *)&temp, curthread); return (error); } /* * Labeling event operations: IPC object. */ static void mac_lomac_create_inpcb_from_socket(struct socket *so, struct label *solabel, struct inpcb *inp, struct label *inplabel) { struct mac_lomac *source, *dest; source = SLOT(solabel); dest = SLOT(inplabel); mac_lomac_copy_single(source, dest); } static void mac_lomac_create_mbuf_from_socket(struct socket *so, struct label *socketlabel, struct mbuf *m, struct label *mbuflabel) { struct mac_lomac *source, *dest; source = SLOT(socketlabel); dest = SLOT(mbuflabel); mac_lomac_copy_single(source, dest); } static void mac_lomac_create_socket(struct ucred *cred, struct socket *socket, struct label *socketlabel) { struct mac_lomac *source, *dest; source = SLOT(cred->cr_label); dest = SLOT(socketlabel); mac_lomac_copy_single(source, dest); } static void -mac_lomac_create_pipe(struct ucred *cred, struct pipe *pipe, +mac_lomac_create_pipe(struct ucred *cred, struct pipepair *pp, struct label *pipelabel) { struct mac_lomac *source, *dest; source = SLOT(cred->cr_label); dest = SLOT(pipelabel); mac_lomac_copy_single(source, dest); } static void mac_lomac_create_socket_from_socket(struct socket *oldsocket, struct label *oldsocketlabel, struct socket *newsocket, struct label *newsocketlabel) { struct mac_lomac *source, *dest; source = SLOT(oldsocketlabel); dest = SLOT(newsocketlabel); mac_lomac_copy_single(source, dest); } static void mac_lomac_relabel_socket(struct ucred *cred, struct socket *socket, struct label *socketlabel, struct label *newlabel) { struct mac_lomac *source, *dest; source = SLOT(newlabel); dest = SLOT(socketlabel); try_relabel(source, dest); } static void -mac_lomac_relabel_pipe(struct ucred *cred, struct pipe *pipe, +mac_lomac_relabel_pipe(struct ucred *cred, struct pipepair *pp, struct label *pipelabel, struct label *newlabel) { struct mac_lomac *source, *dest; source = SLOT(newlabel); dest = SLOT(pipelabel); try_relabel(source, dest); } static void mac_lomac_set_socket_peer_from_mbuf(struct mbuf *mbuf, struct label *mbuflabel, struct socket *socket, struct label *socketpeerlabel) { struct mac_lomac *source, *dest; source = SLOT(mbuflabel); dest = SLOT(socketpeerlabel); mac_lomac_copy_single(source, dest); } /* * Labeling event operations: network objects. */ static void mac_lomac_set_socket_peer_from_socket(struct socket *oldsocket, struct label *oldsocketlabel, struct socket *newsocket, struct label *newsocketpeerlabel) { struct mac_lomac *source, *dest; source = SLOT(oldsocketlabel); dest = SLOT(newsocketpeerlabel); mac_lomac_copy_single(source, dest); } static void mac_lomac_create_bpfdesc(struct ucred *cred, struct bpf_d *bpf_d, struct label *bpflabel) { struct mac_lomac *source, *dest; source = SLOT(cred->cr_label); dest = SLOT(bpflabel); mac_lomac_copy_single(source, dest); } static void mac_lomac_create_ifnet(struct ifnet *ifnet, struct label *ifnetlabel) { char tifname[IFNAMSIZ], *p, *q; char tiflist[sizeof(trusted_interfaces)]; struct mac_lomac *dest; int len, grade; dest = SLOT(ifnetlabel); if (ifnet->if_type == IFT_LOOP) { grade = MAC_LOMAC_TYPE_EQUAL; goto set; } if (trust_all_interfaces) { grade = MAC_LOMAC_TYPE_HIGH; goto set; } grade = MAC_LOMAC_TYPE_LOW; if (trusted_interfaces[0] == '\0' || !strvalid(trusted_interfaces, sizeof(trusted_interfaces))) goto set; bzero(tiflist, sizeof(tiflist)); for (p = trusted_interfaces, q = tiflist; *p != '\0'; p++, q++) if(*p != ' ' && *p != '\t') *q = *p; for (p = q = tiflist;; p++) { if (*p == ',' || *p == '\0') { len = p - q; if (len < IFNAMSIZ) { bzero(tifname, sizeof(tifname)); bcopy(q, tifname, len); if (strcmp(tifname, ifnet->if_xname) == 0) { grade = MAC_LOMAC_TYPE_HIGH; break; } } else { *p = '\0'; printf("MAC/LOMAC warning: interface name " "\"%s\" is too long (must be < %d)\n", q, IFNAMSIZ); } if (*p == '\0') break; q = p + 1; } } set: mac_lomac_set_single(dest, grade, 0); mac_lomac_set_range(dest, grade, 0, grade, 0); } static void mac_lomac_create_ipq(struct mbuf *fragment, struct label *fragmentlabel, struct ipq *ipq, struct label *ipqlabel) { struct mac_lomac *source, *dest; source = SLOT(fragmentlabel); dest = SLOT(ipqlabel); mac_lomac_copy_single(source, dest); } static void mac_lomac_create_datagram_from_ipq(struct ipq *ipq, struct label *ipqlabel, struct mbuf *datagram, struct label *datagramlabel) { struct mac_lomac *source, *dest; source = SLOT(ipqlabel); dest = SLOT(datagramlabel); /* Just use the head, since we require them all to match. */ mac_lomac_copy_single(source, dest); } static void mac_lomac_create_fragment(struct mbuf *datagram, struct label *datagramlabel, struct mbuf *fragment, struct label *fragmentlabel) { struct mac_lomac *source, *dest; source = SLOT(datagramlabel); dest = SLOT(fragmentlabel); mac_lomac_copy_single(source, dest); } static void mac_lomac_create_mbuf_from_inpcb(struct inpcb *inp, struct label *inplabel, struct mbuf *m, struct label *mlabel) { struct mac_lomac *source, *dest; source = SLOT(inplabel); dest = SLOT(mlabel); mac_lomac_copy_single(source, dest); } static void mac_lomac_create_mbuf_from_mbuf(struct mbuf *oldmbuf, struct label *oldmbuflabel, struct mbuf *newmbuf, struct label *newmbuflabel) { struct mac_lomac *source, *dest; source = SLOT(oldmbuflabel); dest = SLOT(newmbuflabel); /* * Because the source mbuf may not yet have been "created", * just initialized, we do a conditional copy. Since we don't * allow mbufs to have ranges, do a KASSERT to make sure that * doesn't happen. */ KASSERT((source->ml_flags & MAC_LOMAC_FLAG_RANGE) == 0, ("mac_lomac_create_mbuf_from_mbuf: source mbuf has range")); mac_lomac_copy(source, dest); } static void mac_lomac_create_mbuf_linklayer(struct ifnet *ifnet, struct label *ifnetlabel, struct mbuf *mbuf, struct label *mbuflabel) { struct mac_lomac *dest; dest = SLOT(mbuflabel); mac_lomac_set_single(dest, MAC_LOMAC_TYPE_EQUAL, 0); } static void mac_lomac_create_mbuf_from_bpfdesc(struct bpf_d *bpf_d, struct label *bpflabel, struct mbuf *mbuf, struct label *mbuflabel) { struct mac_lomac *source, *dest; source = SLOT(bpflabel); dest = SLOT(mbuflabel); mac_lomac_copy_single(source, dest); } static void mac_lomac_create_mbuf_from_ifnet(struct ifnet *ifnet, struct label *ifnetlabel, struct mbuf *m, struct label *mbuflabel) { struct mac_lomac *source, *dest; source = SLOT(ifnetlabel); dest = SLOT(mbuflabel); mac_lomac_copy_single(source, dest); } static void mac_lomac_create_mbuf_multicast_encap(struct mbuf *oldmbuf, struct label *oldmbuflabel, struct ifnet *ifnet, struct label *ifnetlabel, struct mbuf *newmbuf, struct label *newmbuflabel) { struct mac_lomac *source, *dest; source = SLOT(oldmbuflabel); dest = SLOT(newmbuflabel); mac_lomac_copy_single(source, dest); } static void mac_lomac_create_mbuf_netlayer(struct mbuf *oldmbuf, struct label *oldmbuflabel, struct mbuf *newmbuf, struct label *newmbuflabel) { struct mac_lomac *source, *dest; source = SLOT(oldmbuflabel); dest = SLOT(newmbuflabel); mac_lomac_copy_single(source, dest); } static int mac_lomac_fragment_match(struct mbuf *fragment, struct label *fragmentlabel, struct ipq *ipq, struct label *ipqlabel) { struct mac_lomac *a, *b; a = SLOT(ipqlabel); b = SLOT(fragmentlabel); return (mac_lomac_equal_single(a, b)); } static void mac_lomac_relabel_ifnet(struct ucred *cred, struct ifnet *ifnet, struct label *ifnetlabel, struct label *newlabel) { struct mac_lomac *source, *dest; source = SLOT(newlabel); dest = SLOT(ifnetlabel); try_relabel(source, dest); } static void mac_lomac_update_ipq(struct mbuf *fragment, struct label *fragmentlabel, struct ipq *ipq, struct label *ipqlabel) { /* NOOP: we only accept matching labels, so no need to update */ } static void mac_lomac_inpcb_sosetlabel(struct socket *so, struct label *solabel, struct inpcb *inp, struct label *inplabel) { struct mac_lomac *source, *dest; source = SLOT(solabel); dest = SLOT(inplabel); mac_lomac_copy_single(source, dest); } /* * Labeling event operations: processes. */ static void mac_lomac_execve_transition(struct ucred *old, struct ucred *new, struct vnode *vp, struct label *vnodelabel, struct label *interpvnodelabel, struct image_params *imgp, struct label *execlabel) { struct mac_lomac *source, *dest, *obj, *robj; source = SLOT(old->cr_label); dest = SLOT(new->cr_label); obj = SLOT(vnodelabel); robj = interpvnodelabel != NULL ? SLOT(interpvnodelabel) : obj; mac_lomac_copy(source, dest); /* * If there's an auxiliary label on the real object, respect it * and assume that this level should be assumed immediately if * a higher level is currently in place. */ if (robj->ml_flags & MAC_LOMAC_FLAG_AUX && !mac_lomac_dominate_element(&robj->ml_auxsingle, &dest->ml_single) && mac_lomac_auxsingle_in_range(robj, dest)) mac_lomac_set_single(dest, robj->ml_auxsingle.mle_type, robj->ml_auxsingle.mle_grade); /* * Restructuring to use the execve transitioning mechanism * instead of the normal demotion mechanism here would be * difficult, so just copy the label over and perform standard * demotion. This is also non-optimal because it will result * in the intermediate label "new" being created and immediately * recycled. */ if (mac_lomac_enabled && revocation_enabled && !mac_lomac_dominate_single(obj, source)) (void)maybe_demote(source, obj, "executing", "file", vp); } static int mac_lomac_execve_will_transition(struct ucred *old, struct vnode *vp, struct label *vnodelabel, struct label *interpvnodelabel, struct image_params *imgp, struct label *execlabel) { struct mac_lomac *subj, *obj, *robj; if (!mac_lomac_enabled || !revocation_enabled) return (0); subj = SLOT(old->cr_label); obj = SLOT(vnodelabel); robj = interpvnodelabel != NULL ? SLOT(interpvnodelabel) : obj; return ((robj->ml_flags & MAC_LOMAC_FLAG_AUX && !mac_lomac_dominate_element(&robj->ml_auxsingle, &subj->ml_single) && mac_lomac_auxsingle_in_range(robj, subj)) || !mac_lomac_dominate_single(obj, subj)); } static void mac_lomac_create_proc0(struct ucred *cred) { struct mac_lomac *dest; dest = SLOT(cred->cr_label); mac_lomac_set_single(dest, MAC_LOMAC_TYPE_EQUAL, 0); mac_lomac_set_range(dest, MAC_LOMAC_TYPE_LOW, 0, MAC_LOMAC_TYPE_HIGH, 0); } static void mac_lomac_create_proc1(struct ucred *cred) { struct mac_lomac *dest; dest = SLOT(cred->cr_label); mac_lomac_set_single(dest, MAC_LOMAC_TYPE_HIGH, 0); mac_lomac_set_range(dest, MAC_LOMAC_TYPE_LOW, 0, MAC_LOMAC_TYPE_HIGH, 0); } static void mac_lomac_relabel_cred(struct ucred *cred, struct label *newlabel) { struct mac_lomac *source, *dest; source = SLOT(newlabel); dest = SLOT(cred->cr_label); try_relabel(source, dest); } /* * Access control checks. */ static int mac_lomac_check_bpfdesc_receive(struct bpf_d *bpf_d, struct label *bpflabel, struct ifnet *ifnet, struct label *ifnetlabel) { struct mac_lomac *a, *b; if (!mac_lomac_enabled) return (0); a = SLOT(bpflabel); b = SLOT(ifnetlabel); if (mac_lomac_equal_single(a, b)) return (0); return (EACCES); } static int mac_lomac_check_cred_relabel(struct ucred *cred, struct label *newlabel) { struct mac_lomac *subj, *new; int error; subj = SLOT(cred->cr_label); new = SLOT(newlabel); /* * If there is a LOMAC label update for the credential, it may * be an update of the single, range, or both. */ error = lomac_atmostflags(new, MAC_LOMAC_FLAGS_BOTH); if (error) return (error); /* * If the LOMAC label is to be changed, authorize as appropriate. */ if (new->ml_flags & MAC_LOMAC_FLAGS_BOTH) { /* * Fill in the missing parts from the previous label. */ if ((new->ml_flags & MAC_LOMAC_FLAG_SINGLE) == 0) mac_lomac_copy_single(subj, new); if ((new->ml_flags & MAC_LOMAC_FLAG_RANGE) == 0) mac_lomac_copy_range(subj, new); /* * To change the LOMAC range on a credential, the new * range label must be in the current range. */ if (!mac_lomac_range_in_range(new, subj)) return (EPERM); /* * To change the LOMAC single label on a credential, the * new single label must be in the new range. Implicitly * from the previous check, the new single is in the old * range. */ if (!mac_lomac_single_in_range(new, new)) return (EPERM); /* * To have EQUAL in any component of the new credential * LOMAC label, the subject must already have EQUAL in * their label. */ if (mac_lomac_contains_equal(new)) { error = mac_lomac_subject_privileged(subj); if (error) return (error); } /* * XXXMAC: Additional consistency tests regarding the * single and range of the new label might be performed * here. */ } return (0); } static int mac_lomac_check_cred_visible(struct ucred *u1, struct ucred *u2) { struct mac_lomac *subj, *obj; if (!mac_lomac_enabled) return (0); subj = SLOT(u1->cr_label); obj = SLOT(u2->cr_label); /* XXX: range */ if (!mac_lomac_dominate_single(obj, subj)) return (ESRCH); return (0); } static int mac_lomac_check_ifnet_relabel(struct ucred *cred, struct ifnet *ifnet, struct label *ifnetlabel, struct label *newlabel) { struct mac_lomac *subj, *new; int error; subj = SLOT(cred->cr_label); new = SLOT(newlabel); /* * If there is a LOMAC label update for the interface, it may * be an update of the single, range, or both. */ error = lomac_atmostflags(new, MAC_LOMAC_FLAGS_BOTH); if (error) return (error); /* * Relabling network interfaces requires LOMAC privilege. */ error = mac_lomac_subject_privileged(subj); if (error) return (error); /* * If the LOMAC label is to be changed, authorize as appropriate. */ if (new->ml_flags & MAC_LOMAC_FLAGS_BOTH) { /* * Fill in the missing parts from the previous label. */ if ((new->ml_flags & MAC_LOMAC_FLAG_SINGLE) == 0) mac_lomac_copy_single(subj, new); if ((new->ml_flags & MAC_LOMAC_FLAG_RANGE) == 0) mac_lomac_copy_range(subj, new); /* * Rely on the traditional superuser status for the LOMAC * interface relabel requirements. XXXMAC: This will go * away. */ error = suser_cred(cred, 0); if (error) return (EPERM); /* * XXXMAC: Additional consistency tests regarding the single * and the range of the new label might be performed here. */ } return (0); } static int mac_lomac_check_ifnet_transmit(struct ifnet *ifnet, struct label *ifnetlabel, struct mbuf *m, struct label *mbuflabel) { struct mac_lomac *p, *i; if (!mac_lomac_enabled) return (0); p = SLOT(mbuflabel); i = SLOT(ifnetlabel); return (mac_lomac_single_in_range(p, i) ? 0 : EACCES); } static int mac_lomac_check_inpcb_deliver(struct inpcb *inp, struct label *inplabel, struct mbuf *m, struct label *mlabel) { struct mac_lomac *p, *i; if (!mac_lomac_enabled) return (0); p = SLOT(mlabel); i = SLOT(inplabel); return (mac_lomac_equal_single(p, i) ? 0 : EACCES); } static int mac_lomac_check_kld_load(struct ucred *cred, struct vnode *vp, struct label *label) { struct mac_lomac *subj, *obj; if (!mac_lomac_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(label); if (mac_lomac_subject_privileged(subj)) return (EPERM); if (!mac_lomac_high_single(obj)) return (EACCES); return (0); } static int mac_lomac_check_kld_unload(struct ucred *cred) { struct mac_lomac *subj; if (!mac_lomac_enabled) return (0); subj = SLOT(cred->cr_label); if (mac_lomac_subject_privileged(subj)) return (EPERM); return (0); } static int -mac_lomac_check_pipe_ioctl(struct ucred *cred, struct pipe *pipe, +mac_lomac_check_pipe_ioctl(struct ucred *cred, struct pipepair *pp, struct label *pipelabel, unsigned long cmd, void /* caddr_t */ *data) { if(!mac_lomac_enabled) return (0); /* XXX: This will be implemented soon... */ return (0); } static int -mac_lomac_check_pipe_read(struct ucred *cred, struct pipe *pipe, +mac_lomac_check_pipe_read(struct ucred *cred, struct pipepair *pp, struct label *pipelabel) { struct mac_lomac *subj, *obj; if (!mac_lomac_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT((pipelabel)); if (!mac_lomac_dominate_single(obj, subj)) return (maybe_demote(subj, obj, "reading", "pipe", NULL)); return (0); } static int -mac_lomac_check_pipe_relabel(struct ucred *cred, struct pipe *pipe, +mac_lomac_check_pipe_relabel(struct ucred *cred, struct pipepair *pp, struct label *pipelabel, struct label *newlabel) { struct mac_lomac *subj, *obj, *new; int error; new = SLOT(newlabel); subj = SLOT(cred->cr_label); obj = SLOT(pipelabel); /* * If there is a LOMAC label update for a pipe, it must be a * single update. */ error = lomac_atmostflags(new, MAC_LOMAC_FLAG_SINGLE); if (error) return (error); /* * To perform a relabel of a pipe (LOMAC label or not), LOMAC must * authorize the relabel. */ if (!mac_lomac_single_in_range(obj, subj)) return (EPERM); /* * If the LOMAC label is to be changed, authorize as appropriate. */ if (new->ml_flags & MAC_LOMAC_FLAG_SINGLE) { /* * To change the LOMAC label on a pipe, the new pipe label * must be in the subject range. */ if (!mac_lomac_single_in_range(new, subj)) return (EPERM); /* * To change the LOMAC label on a pipe to be EQUAL, the * subject must have appropriate privilege. */ if (mac_lomac_contains_equal(new)) { error = mac_lomac_subject_privileged(subj); if (error) return (error); } } return (0); } static int -mac_lomac_check_pipe_write(struct ucred *cred, struct pipe *pipe, +mac_lomac_check_pipe_write(struct ucred *cred, struct pipepair *pp, struct label *pipelabel) { struct mac_lomac *subj, *obj; if (!mac_lomac_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT((pipelabel)); if (!mac_lomac_subject_dominate(subj, obj)) return (EACCES); return (0); } static int mac_lomac_check_proc_debug(struct ucred *cred, struct proc *proc) { struct mac_lomac *subj, *obj; if (!mac_lomac_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(proc->p_ucred->cr_label); /* XXX: range checks */ if (!mac_lomac_dominate_single(obj, subj)) return (ESRCH); if (!mac_lomac_subject_dominate(subj, obj)) return (EACCES); return (0); } static int mac_lomac_check_proc_sched(struct ucred *cred, struct proc *proc) { struct mac_lomac *subj, *obj; if (!mac_lomac_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(proc->p_ucred->cr_label); /* XXX: range checks */ if (!mac_lomac_dominate_single(obj, subj)) return (ESRCH); if (!mac_lomac_subject_dominate(subj, obj)) return (EACCES); return (0); } static int mac_lomac_check_proc_signal(struct ucred *cred, struct proc *proc, int signum) { struct mac_lomac *subj, *obj; if (!mac_lomac_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(proc->p_ucred->cr_label); /* XXX: range checks */ if (!mac_lomac_dominate_single(obj, subj)) return (ESRCH); if (!mac_lomac_subject_dominate(subj, obj)) return (EACCES); return (0); } static int mac_lomac_check_socket_deliver(struct socket *so, struct label *socketlabel, struct mbuf *m, struct label *mbuflabel) { struct mac_lomac *p, *s; if (!mac_lomac_enabled) return (0); p = SLOT(mbuflabel); s = SLOT(socketlabel); return (mac_lomac_equal_single(p, s) ? 0 : EACCES); } static int mac_lomac_check_socket_relabel(struct ucred *cred, struct socket *socket, struct label *socketlabel, struct label *newlabel) { struct mac_lomac *subj, *obj, *new; int error; new = SLOT(newlabel); subj = SLOT(cred->cr_label); obj = SLOT(socketlabel); /* * If there is a LOMAC label update for the socket, it may be * an update of single. */ error = lomac_atmostflags(new, MAC_LOMAC_FLAG_SINGLE); if (error) return (error); /* * To relabel a socket, the old socket single must be in the subject * range. */ if (!mac_lomac_single_in_range(obj, subj)) return (EPERM); /* * If the LOMAC label is to be changed, authorize as appropriate. */ if (new->ml_flags & MAC_LOMAC_FLAG_SINGLE) { /* * To relabel a socket, the new socket single must be in * the subject range. */ if (!mac_lomac_single_in_range(new, subj)) return (EPERM); /* * To change the LOMAC label on the socket to contain EQUAL, * the subject must have appropriate privilege. */ if (mac_lomac_contains_equal(new)) { error = mac_lomac_subject_privileged(subj); if (error) return (error); } } return (0); } static int mac_lomac_check_socket_visible(struct ucred *cred, struct socket *socket, struct label *socketlabel) { struct mac_lomac *subj, *obj; if (!mac_lomac_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(socketlabel); if (!mac_lomac_dominate_single(obj, subj)) return (ENOENT); return (0); } static int mac_lomac_check_system_swapon(struct ucred *cred, struct vnode *vp, struct label *label) { struct mac_lomac *subj, *obj; if (!mac_lomac_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(label); if (mac_lomac_subject_privileged(subj)) return (EPERM); if (!mac_lomac_high_single(obj)) return (EACCES); return (0); } static int mac_lomac_check_system_sysctl(struct ucred *cred, int *name, u_int namelen, void *old, size_t *oldlenp, int inkernel, void *new, size_t newlen) { struct mac_lomac *subj; if (!mac_lomac_enabled) return (0); subj = SLOT(cred->cr_label); /* * In general, treat sysctl variables as lomac/high, but also * require privilege to change them, since they are a * communications channel between grades. Exempt MIB * queries from this due to undocmented sysctl magic. * XXXMAC: This probably requires some more review. */ if (new != NULL) { if (namelen > 0 && name[0] == 0) return (0); #ifdef notdef if (!mac_lomac_subject_dominate_high(subj)) return (EACCES); #endif if (mac_lomac_subject_privileged(subj)) return (EPERM); } return (0); } static int mac_lomac_check_vnode_create(struct ucred *cred, struct vnode *dvp, struct label *dlabel, struct componentname *cnp, struct vattr *vap) { struct mac_lomac *subj, *obj; if (!mac_lomac_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(dlabel); if (!mac_lomac_subject_dominate(subj, obj)) return (EACCES); if (obj->ml_flags & MAC_LOMAC_FLAG_AUX && !mac_lomac_dominate_element(&subj->ml_single, &obj->ml_auxsingle)) return (EACCES); return (0); } static int mac_lomac_check_vnode_delete(struct ucred *cred, struct vnode *dvp, struct label *dlabel, struct vnode *vp, struct label *label, struct componentname *cnp) { struct mac_lomac *subj, *obj; if (!mac_lomac_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(dlabel); if (!mac_lomac_subject_dominate(subj, obj)) return (EACCES); obj = SLOT(label); if (!mac_lomac_subject_dominate(subj, obj)) return (EACCES); return (0); } static int mac_lomac_check_vnode_deleteacl(struct ucred *cred, struct vnode *vp, struct label *label, acl_type_t type) { struct mac_lomac *subj, *obj; if (!mac_lomac_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(label); if (!mac_lomac_subject_dominate(subj, obj)) return (EACCES); return (0); } static int mac_lomac_check_vnode_link(struct ucred *cred, struct vnode *dvp, struct label *dlabel, struct vnode *vp, struct label *label, struct componentname *cnp) { struct mac_lomac *subj, *obj; if (!mac_lomac_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(dlabel); if (!mac_lomac_subject_dominate(subj, obj)) return (EACCES); obj = SLOT(label); if (!mac_lomac_subject_dominate(subj, obj)) return (EACCES); return (0); } static int mac_lomac_check_vnode_mmap(struct ucred *cred, struct vnode *vp, struct label *label, int prot) { struct mac_lomac *subj, *obj; /* * Rely on the use of open()-time protections to handle * non-revocation cases. */ if (!mac_lomac_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(label); if (prot & VM_PROT_WRITE) { if (!mac_lomac_subject_dominate(subj, obj)) return (EACCES); } if (prot & (VM_PROT_READ | VM_PROT_EXECUTE)) { if (!mac_lomac_dominate_single(obj, subj)) return (maybe_demote(subj, obj, "mapping", "file", vp)); } return (0); } static int mac_lomac_check_vnode_mprotect(struct ucred *cred, struct vnode *vp, struct label *label, int prot) { struct mac_lomac *subj, *obj; /* * Rely on the use of open()-time protections to handle * non-revocation cases. */ if (!mac_lomac_enabled || !revocation_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(label); if (prot & VM_PROT_WRITE) { if (!mac_lomac_subject_dominate(subj, obj)) return (EACCES); } if (prot & (VM_PROT_READ | VM_PROT_EXECUTE)) { if (!mac_lomac_dominate_single(obj, subj)) return (EACCES); } return (0); } static void mac_lomac_check_vnode_mmap_downgrade(struct ucred *cred, struct vnode *vp, struct label *label, /* XXX vm_prot_t */ int *prot) { struct mac_lomac *subj, *obj; /* * Rely on the use of open()-time protections to handle * non-revocation cases. */ if (!mac_lomac_enabled || !revocation_enabled) return; subj = SLOT(cred->cr_label); obj = SLOT(label); if (!mac_lomac_subject_dominate(subj, obj)) *prot &= ~VM_PROT_WRITE; } static int mac_lomac_check_vnode_open(struct ucred *cred, struct vnode *vp, struct label *vnodelabel, int acc_mode) { struct mac_lomac *subj, *obj; if (!mac_lomac_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(vnodelabel); /* XXX privilege override for admin? */ if (acc_mode & (VWRITE | VAPPEND | VADMIN)) { if (!mac_lomac_subject_dominate(subj, obj)) return (EACCES); } return (0); } static int mac_lomac_check_vnode_read(struct ucred *active_cred, struct ucred *file_cred, struct vnode *vp, struct label *label) { struct mac_lomac *subj, *obj; if (!mac_lomac_enabled || !revocation_enabled) return (0); subj = SLOT(active_cred->cr_label); obj = SLOT(label); if (!mac_lomac_dominate_single(obj, subj)) return (maybe_demote(subj, obj, "reading", "file", vp)); return (0); } static int mac_lomac_check_vnode_relabel(struct ucred *cred, struct vnode *vp, struct label *vnodelabel, struct label *newlabel) { struct mac_lomac *old, *new, *subj; int error; old = SLOT(vnodelabel); new = SLOT(newlabel); subj = SLOT(cred->cr_label); /* * If there is a LOMAC label update for the vnode, it must be a * single label, with an optional explicit auxiliary single. */ error = lomac_atmostflags(new, MAC_LOMAC_FLAG_SINGLE | MAC_LOMAC_FLAG_AUX); if (error) return (error); /* * To perform a relabel of the vnode (LOMAC label or not), LOMAC must * authorize the relabel. */ if (!mac_lomac_single_in_range(old, subj)) return (EPERM); /* * If the LOMAC label is to be changed, authorize as appropriate. */ if (new->ml_flags & MAC_LOMAC_FLAG_SINGLE) { /* * To change the LOMAC label on a vnode, the new vnode label * must be in the subject range. */ if (!mac_lomac_single_in_range(new, subj)) return (EPERM); /* * To change the LOMAC label on the vnode to be EQUAL, * the subject must have appropriate privilege. */ if (mac_lomac_contains_equal(new)) { error = mac_lomac_subject_privileged(subj); if (error) return (error); } } if (new->ml_flags & MAC_LOMAC_FLAG_AUX) { /* * Fill in the missing parts from the previous label. */ if ((new->ml_flags & MAC_LOMAC_FLAG_SINGLE) == 0) mac_lomac_copy_single(subj, new); /* * To change the auxiliary LOMAC label on a vnode, the new * vnode label must be in the subject range. */ if (!mac_lomac_auxsingle_in_range(new, subj)) return (EPERM); /* * To change the auxiliary LOMAC label on the vnode to be * EQUAL, the subject must have appropriate privilege. */ if (mac_lomac_contains_equal(new)) { error = mac_lomac_subject_privileged(subj); if (error) return (error); } } return (0); } static int mac_lomac_check_vnode_rename_from(struct ucred *cred, struct vnode *dvp, struct label *dlabel, struct vnode *vp, struct label *label, struct componentname *cnp) { struct mac_lomac *subj, *obj; if (!mac_lomac_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(dlabel); if (!mac_lomac_subject_dominate(subj, obj)) return (EACCES); obj = SLOT(label); if (!mac_lomac_subject_dominate(subj, obj)) return (EACCES); return (0); } static int mac_lomac_check_vnode_rename_to(struct ucred *cred, struct vnode *dvp, struct label *dlabel, struct vnode *vp, struct label *label, int samedir, struct componentname *cnp) { struct mac_lomac *subj, *obj; if (!mac_lomac_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(dlabel); if (!mac_lomac_subject_dominate(subj, obj)) return (EACCES); if (vp != NULL) { obj = SLOT(label); if (!mac_lomac_subject_dominate(subj, obj)) return (EACCES); } return (0); } static int mac_lomac_check_vnode_revoke(struct ucred *cred, struct vnode *vp, struct label *label) { struct mac_lomac *subj, *obj; if (!mac_lomac_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(label); if (!mac_lomac_subject_dominate(subj, obj)) return (EACCES); return (0); } static int mac_lomac_check_vnode_setacl(struct ucred *cred, struct vnode *vp, struct label *label, acl_type_t type, struct acl *acl) { struct mac_lomac *subj, *obj; if (!mac_lomac_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(label); if (!mac_lomac_subject_dominate(subj, obj)) return (EACCES); return (0); } static int mac_lomac_check_vnode_setextattr(struct ucred *cred, struct vnode *vp, struct label *vnodelabel, int attrnamespace, const char *name, struct uio *uio) { struct mac_lomac *subj, *obj; if (!mac_lomac_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(vnodelabel); if (!mac_lomac_subject_dominate(subj, obj)) return (EACCES); /* XXX: protect the MAC EA in a special way? */ return (0); } static int mac_lomac_check_vnode_setflags(struct ucred *cred, struct vnode *vp, struct label *vnodelabel, u_long flags) { struct mac_lomac *subj, *obj; if (!mac_lomac_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(vnodelabel); if (!mac_lomac_subject_dominate(subj, obj)) return (EACCES); return (0); } static int mac_lomac_check_vnode_setmode(struct ucred *cred, struct vnode *vp, struct label *vnodelabel, mode_t mode) { struct mac_lomac *subj, *obj; if (!mac_lomac_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(vnodelabel); if (!mac_lomac_subject_dominate(subj, obj)) return (EACCES); return (0); } static int mac_lomac_check_vnode_setowner(struct ucred *cred, struct vnode *vp, struct label *vnodelabel, uid_t uid, gid_t gid) { struct mac_lomac *subj, *obj; if (!mac_lomac_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(vnodelabel); if (!mac_lomac_subject_dominate(subj, obj)) return (EACCES); return (0); } static int mac_lomac_check_vnode_setutimes(struct ucred *cred, struct vnode *vp, struct label *vnodelabel, struct timespec atime, struct timespec mtime) { struct mac_lomac *subj, *obj; if (!mac_lomac_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(vnodelabel); if (!mac_lomac_subject_dominate(subj, obj)) return (EACCES); return (0); } static int mac_lomac_check_vnode_write(struct ucred *active_cred, struct ucred *file_cred, struct vnode *vp, struct label *label) { struct mac_lomac *subj, *obj; if (!mac_lomac_enabled || !revocation_enabled) return (0); subj = SLOT(active_cred->cr_label); obj = SLOT(label); if (!mac_lomac_subject_dominate(subj, obj)) return (EACCES); return (0); } static void mac_lomac_thread_userret(struct thread *td) { struct proc *p = td->td_proc; struct mac_lomac_proc *subj = PSLOT(p->p_label); struct ucred *newcred, *oldcred; int dodrop; mtx_lock(&subj->mtx); if (subj->mac_lomac.ml_flags & MAC_LOMAC_FLAG_UPDATE) { dodrop = 0; mtx_unlock(&subj->mtx); newcred = crget(); /* * Prevent a lock order reversal in * mac_cred_mmapped_drop_perms; ideally, the other * user of subj->mtx wouldn't be holding Giant. */ mtx_lock(&Giant); PROC_LOCK(p); mtx_lock(&subj->mtx); /* * Check if we lost the race while allocating the cred. */ if ((subj->mac_lomac.ml_flags & MAC_LOMAC_FLAG_UPDATE) == 0) { crfree(newcred); goto out; } oldcred = p->p_ucred; crcopy(newcred, oldcred); crhold(newcred); mac_lomac_copy(&subj->mac_lomac, SLOT(newcred->cr_label)); p->p_ucred = newcred; crfree(oldcred); dodrop = 1; out: mtx_unlock(&subj->mtx); PROC_UNLOCK(p); if (dodrop) mac_cred_mmapped_drop_perms(curthread, newcred); mtx_unlock(&Giant); } else { mtx_unlock(&subj->mtx); } } static struct mac_policy_ops mac_lomac_ops = { .mpo_init = mac_lomac_init, .mpo_init_bpfdesc_label = mac_lomac_init_label, .mpo_init_cred_label = mac_lomac_init_label, .mpo_init_devfsdirent_label = mac_lomac_init_label, .mpo_init_ifnet_label = mac_lomac_init_label, .mpo_init_inpcb_label = mac_lomac_init_label_waitcheck, .mpo_init_ipq_label = mac_lomac_init_label_waitcheck, .mpo_init_mbuf_label = mac_lomac_init_label_waitcheck, .mpo_init_mount_label = mac_lomac_init_label, .mpo_init_mount_fs_label = mac_lomac_init_label, .mpo_init_pipe_label = mac_lomac_init_label, .mpo_init_proc_label = mac_lomac_init_proc_label, .mpo_init_socket_label = mac_lomac_init_label_waitcheck, .mpo_init_socket_peer_label = mac_lomac_init_label_waitcheck, .mpo_init_vnode_label = mac_lomac_init_label, .mpo_destroy_bpfdesc_label = mac_lomac_destroy_label, .mpo_destroy_cred_label = mac_lomac_destroy_label, .mpo_destroy_devfsdirent_label = mac_lomac_destroy_label, .mpo_destroy_ifnet_label = mac_lomac_destroy_label, .mpo_destroy_inpcb_label = mac_lomac_destroy_label, .mpo_destroy_ipq_label = mac_lomac_destroy_label, .mpo_destroy_mbuf_label = mac_lomac_destroy_label, .mpo_destroy_mount_label = mac_lomac_destroy_label, .mpo_destroy_mount_fs_label = mac_lomac_destroy_label, .mpo_destroy_pipe_label = mac_lomac_destroy_label, .mpo_destroy_proc_label = mac_lomac_destroy_proc_label, .mpo_destroy_socket_label = mac_lomac_destroy_label, .mpo_destroy_socket_peer_label = mac_lomac_destroy_label, .mpo_destroy_vnode_label = mac_lomac_destroy_label, .mpo_copy_cred_label = mac_lomac_copy_label, .mpo_copy_mbuf_label = mac_lomac_copy_label, .mpo_copy_pipe_label = mac_lomac_copy_label, .mpo_copy_socket_label = mac_lomac_copy_label, .mpo_copy_vnode_label = mac_lomac_copy_label, .mpo_externalize_cred_label = mac_lomac_externalize_label, .mpo_externalize_ifnet_label = mac_lomac_externalize_label, .mpo_externalize_pipe_label = mac_lomac_externalize_label, .mpo_externalize_socket_label = mac_lomac_externalize_label, .mpo_externalize_socket_peer_label = mac_lomac_externalize_label, .mpo_externalize_vnode_label = mac_lomac_externalize_label, .mpo_internalize_cred_label = mac_lomac_internalize_label, .mpo_internalize_ifnet_label = mac_lomac_internalize_label, .mpo_internalize_pipe_label = mac_lomac_internalize_label, .mpo_internalize_socket_label = mac_lomac_internalize_label, .mpo_internalize_vnode_label = mac_lomac_internalize_label, .mpo_create_devfs_device = mac_lomac_create_devfs_device, .mpo_create_devfs_directory = mac_lomac_create_devfs_directory, .mpo_create_devfs_symlink = mac_lomac_create_devfs_symlink, .mpo_create_mount = mac_lomac_create_mount, .mpo_create_root_mount = mac_lomac_create_root_mount, .mpo_relabel_vnode = mac_lomac_relabel_vnode, .mpo_update_devfsdirent = mac_lomac_update_devfsdirent, .mpo_associate_vnode_devfs = mac_lomac_associate_vnode_devfs, .mpo_associate_vnode_extattr = mac_lomac_associate_vnode_extattr, .mpo_associate_vnode_singlelabel = mac_lomac_associate_vnode_singlelabel, .mpo_create_vnode_extattr = mac_lomac_create_vnode_extattr, .mpo_setlabel_vnode_extattr = mac_lomac_setlabel_vnode_extattr, .mpo_create_mbuf_from_socket = mac_lomac_create_mbuf_from_socket, .mpo_create_pipe = mac_lomac_create_pipe, .mpo_create_socket = mac_lomac_create_socket, .mpo_create_socket_from_socket = mac_lomac_create_socket_from_socket, .mpo_relabel_pipe = mac_lomac_relabel_pipe, .mpo_relabel_socket = mac_lomac_relabel_socket, .mpo_set_socket_peer_from_mbuf = mac_lomac_set_socket_peer_from_mbuf, .mpo_set_socket_peer_from_socket = mac_lomac_set_socket_peer_from_socket, .mpo_create_bpfdesc = mac_lomac_create_bpfdesc, .mpo_create_datagram_from_ipq = mac_lomac_create_datagram_from_ipq, .mpo_create_fragment = mac_lomac_create_fragment, .mpo_create_ifnet = mac_lomac_create_ifnet, .mpo_create_inpcb_from_socket = mac_lomac_create_inpcb_from_socket, .mpo_create_ipq = mac_lomac_create_ipq, .mpo_create_mbuf_from_inpcb = mac_lomac_create_mbuf_from_inpcb, .mpo_create_mbuf_from_mbuf = mac_lomac_create_mbuf_from_mbuf, .mpo_create_mbuf_linklayer = mac_lomac_create_mbuf_linklayer, .mpo_create_mbuf_from_bpfdesc = mac_lomac_create_mbuf_from_bpfdesc, .mpo_create_mbuf_from_ifnet = mac_lomac_create_mbuf_from_ifnet, .mpo_create_mbuf_multicast_encap = mac_lomac_create_mbuf_multicast_encap, .mpo_create_mbuf_netlayer = mac_lomac_create_mbuf_netlayer, .mpo_fragment_match = mac_lomac_fragment_match, .mpo_relabel_ifnet = mac_lomac_relabel_ifnet, .mpo_update_ipq = mac_lomac_update_ipq, .mpo_inpcb_sosetlabel = mac_lomac_inpcb_sosetlabel, .mpo_execve_transition = mac_lomac_execve_transition, .mpo_execve_will_transition = mac_lomac_execve_will_transition, .mpo_create_proc0 = mac_lomac_create_proc0, .mpo_create_proc1 = mac_lomac_create_proc1, .mpo_relabel_cred = mac_lomac_relabel_cred, .mpo_check_bpfdesc_receive = mac_lomac_check_bpfdesc_receive, .mpo_check_cred_relabel = mac_lomac_check_cred_relabel, .mpo_check_cred_visible = mac_lomac_check_cred_visible, .mpo_check_ifnet_relabel = mac_lomac_check_ifnet_relabel, .mpo_check_ifnet_transmit = mac_lomac_check_ifnet_transmit, .mpo_check_inpcb_deliver = mac_lomac_check_inpcb_deliver, .mpo_check_kld_load = mac_lomac_check_kld_load, .mpo_check_kld_unload = mac_lomac_check_kld_unload, .mpo_check_pipe_ioctl = mac_lomac_check_pipe_ioctl, .mpo_check_pipe_read = mac_lomac_check_pipe_read, .mpo_check_pipe_relabel = mac_lomac_check_pipe_relabel, .mpo_check_pipe_write = mac_lomac_check_pipe_write, .mpo_check_proc_debug = mac_lomac_check_proc_debug, .mpo_check_proc_sched = mac_lomac_check_proc_sched, .mpo_check_proc_signal = mac_lomac_check_proc_signal, .mpo_check_socket_deliver = mac_lomac_check_socket_deliver, .mpo_check_socket_relabel = mac_lomac_check_socket_relabel, .mpo_check_socket_visible = mac_lomac_check_socket_visible, .mpo_check_system_swapon = mac_lomac_check_system_swapon, .mpo_check_system_sysctl = mac_lomac_check_system_sysctl, .mpo_check_vnode_access = mac_lomac_check_vnode_open, .mpo_check_vnode_create = mac_lomac_check_vnode_create, .mpo_check_vnode_delete = mac_lomac_check_vnode_delete, .mpo_check_vnode_deleteacl = mac_lomac_check_vnode_deleteacl, .mpo_check_vnode_link = mac_lomac_check_vnode_link, .mpo_check_vnode_mmap = mac_lomac_check_vnode_mmap, .mpo_check_vnode_mmap_downgrade = mac_lomac_check_vnode_mmap_downgrade, .mpo_check_vnode_mprotect = mac_lomac_check_vnode_mprotect, .mpo_check_vnode_open = mac_lomac_check_vnode_open, .mpo_check_vnode_read = mac_lomac_check_vnode_read, .mpo_check_vnode_relabel = mac_lomac_check_vnode_relabel, .mpo_check_vnode_rename_from = mac_lomac_check_vnode_rename_from, .mpo_check_vnode_rename_to = mac_lomac_check_vnode_rename_to, .mpo_check_vnode_revoke = mac_lomac_check_vnode_revoke, .mpo_check_vnode_setacl = mac_lomac_check_vnode_setacl, .mpo_check_vnode_setextattr = mac_lomac_check_vnode_setextattr, .mpo_check_vnode_setflags = mac_lomac_check_vnode_setflags, .mpo_check_vnode_setmode = mac_lomac_check_vnode_setmode, .mpo_check_vnode_setowner = mac_lomac_check_vnode_setowner, .mpo_check_vnode_setutimes = mac_lomac_check_vnode_setutimes, .mpo_check_vnode_write = mac_lomac_check_vnode_write, .mpo_thread_userret = mac_lomac_thread_userret, }; MAC_POLICY_SET(&mac_lomac_ops, mac_lomac, "TrustedBSD MAC/LOMAC", MPC_LOADTIME_FLAG_NOTLATE | MPC_LOADTIME_FLAG_LABELMBUFS, &mac_lomac_slot); Index: head/sys/security/mac_mls/mac_mls.c =================================================================== --- head/sys/security/mac_mls/mac_mls.c (revision 125292) +++ head/sys/security/mac_mls/mac_mls.c (revision 125293) @@ -1,2554 +1,2554 @@ /*- * Copyright (c) 1999, 2000, 2001, 2002 Robert N. M. Watson * Copyright (c) 2001, 2002, 2003 Networks Associates Technology, Inc. * All rights reserved. * * This software was developed by Robert Watson for the TrustedBSD Project. * * This software was developed for the FreeBSD Project in part by Network * Associates Laboratories, the Security Research Division of Network * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), * as part of the DARPA CHATS research program. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ /* * Developed by the TrustedBSD Project. * MLS fixed label mandatory confidentiality policy. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include SYSCTL_DECL(_security_mac); SYSCTL_NODE(_security_mac, OID_AUTO, mls, CTLFLAG_RW, 0, "TrustedBSD mac_mls policy controls"); static int mac_mls_label_size = sizeof(struct mac_mls); SYSCTL_INT(_security_mac_mls, OID_AUTO, label_size, CTLFLAG_RD, &mac_mls_label_size, 0, "Size of struct mac_mls"); static int mac_mls_enabled = 1; SYSCTL_INT(_security_mac_mls, OID_AUTO, enabled, CTLFLAG_RW, &mac_mls_enabled, 0, "Enforce MAC/MLS policy"); TUNABLE_INT("security.mac.mls.enabled", &mac_mls_enabled); static int destroyed_not_inited; SYSCTL_INT(_security_mac_mls, OID_AUTO, destroyed_not_inited, CTLFLAG_RD, &destroyed_not_inited, 0, "Count of labels destroyed but not inited"); static int ptys_equal = 0; SYSCTL_INT(_security_mac_mls, OID_AUTO, ptys_equal, CTLFLAG_RW, &ptys_equal, 0, "Label pty devices as mls/equal on create"); TUNABLE_INT("security.mac.mls.ptys_equal", &ptys_equal); static int revocation_enabled = 0; SYSCTL_INT(_security_mac_mls, OID_AUTO, revocation_enabled, CTLFLAG_RW, &revocation_enabled, 0, "Revoke access to objects on relabel"); TUNABLE_INT("security.mac.mls.revocation_enabled", &revocation_enabled); static int max_compartments = MAC_MLS_MAX_COMPARTMENTS; SYSCTL_INT(_security_mac_mls, OID_AUTO, max_compartments, CTLFLAG_RD, &max_compartments, 0, "Maximum compartments the policy supports"); static int mac_mls_slot; #define SLOT(l) ((struct mac_mls *)LABEL_TO_SLOT((l), mac_mls_slot).l_ptr) static uma_zone_t zone_mls; static __inline int mls_bit_set_empty(u_char *set) { int i; for (i = 0; i < MAC_MLS_MAX_COMPARTMENTS >> 3; i++) if (set[i] != 0) return (0); return (1); } static struct mac_mls * mls_alloc(int flag) { return (uma_zalloc(zone_mls, flag | M_ZERO)); } static void mls_free(struct mac_mls *mac_mls) { if (mac_mls != NULL) uma_zfree(zone_mls, mac_mls); else atomic_add_int(&destroyed_not_inited, 1); } static int mls_atmostflags(struct mac_mls *mac_mls, int flags) { if ((mac_mls->mm_flags & flags) != mac_mls->mm_flags) return (EINVAL); return (0); } static int mac_mls_dominate_element(struct mac_mls_element *a, struct mac_mls_element *b) { int bit; switch (a->mme_type) { case MAC_MLS_TYPE_EQUAL: case MAC_MLS_TYPE_HIGH: return (1); case MAC_MLS_TYPE_LOW: switch (b->mme_type) { case MAC_MLS_TYPE_LEVEL: case MAC_MLS_TYPE_HIGH: return (0); case MAC_MLS_TYPE_EQUAL: case MAC_MLS_TYPE_LOW: return (1); default: panic("mac_mls_dominate_element: b->mme_type invalid"); } case MAC_MLS_TYPE_LEVEL: switch (b->mme_type) { case MAC_MLS_TYPE_EQUAL: case MAC_MLS_TYPE_LOW: return (1); case MAC_MLS_TYPE_HIGH: return (0); case MAC_MLS_TYPE_LEVEL: for (bit = 1; bit <= MAC_MLS_MAX_COMPARTMENTS; bit++) if (!MAC_MLS_BIT_TEST(bit, a->mme_compartments) && MAC_MLS_BIT_TEST(bit, b->mme_compartments)) return (0); return (a->mme_level >= b->mme_level); default: panic("mac_mls_dominate_element: b->mme_type invalid"); } default: panic("mac_mls_dominate_element: a->mme_type invalid"); } return (0); } static int mac_mls_range_in_range(struct mac_mls *rangea, struct mac_mls *rangeb) { return (mac_mls_dominate_element(&rangeb->mm_rangehigh, &rangea->mm_rangehigh) && mac_mls_dominate_element(&rangea->mm_rangelow, &rangeb->mm_rangelow)); } static int mac_mls_single_in_range(struct mac_mls *single, struct mac_mls *range) { KASSERT((single->mm_flags & MAC_MLS_FLAG_SINGLE) != 0, ("mac_mls_single_in_range: a not single")); KASSERT((range->mm_flags & MAC_MLS_FLAG_RANGE) != 0, ("mac_mls_single_in_range: b not range")); return (mac_mls_dominate_element(&range->mm_rangehigh, &single->mm_single) && mac_mls_dominate_element(&single->mm_single, &range->mm_rangelow)); return (1); } static int mac_mls_dominate_single(struct mac_mls *a, struct mac_mls *b) { KASSERT((a->mm_flags & MAC_MLS_FLAG_SINGLE) != 0, ("mac_mls_dominate_single: a not single")); KASSERT((b->mm_flags & MAC_MLS_FLAG_SINGLE) != 0, ("mac_mls_dominate_single: b not single")); return (mac_mls_dominate_element(&a->mm_single, &b->mm_single)); } static int mac_mls_equal_element(struct mac_mls_element *a, struct mac_mls_element *b) { if (a->mme_type == MAC_MLS_TYPE_EQUAL || b->mme_type == MAC_MLS_TYPE_EQUAL) return (1); return (a->mme_type == b->mme_type && a->mme_level == b->mme_level); } static int mac_mls_equal_single(struct mac_mls *a, struct mac_mls *b) { KASSERT((a->mm_flags & MAC_MLS_FLAG_SINGLE) != 0, ("mac_mls_equal_single: a not single")); KASSERT((b->mm_flags & MAC_MLS_FLAG_SINGLE) != 0, ("mac_mls_equal_single: b not single")); return (mac_mls_equal_element(&a->mm_single, &b->mm_single)); } static int mac_mls_contains_equal(struct mac_mls *mac_mls) { if (mac_mls->mm_flags & MAC_MLS_FLAG_SINGLE) if (mac_mls->mm_single.mme_type == MAC_MLS_TYPE_EQUAL) return (1); if (mac_mls->mm_flags & MAC_MLS_FLAG_RANGE) { if (mac_mls->mm_rangelow.mme_type == MAC_MLS_TYPE_EQUAL) return (1); if (mac_mls->mm_rangehigh.mme_type == MAC_MLS_TYPE_EQUAL) return (1); } return (0); } static int mac_mls_subject_privileged(struct mac_mls *mac_mls) { KASSERT((mac_mls->mm_flags & MAC_MLS_FLAGS_BOTH) == MAC_MLS_FLAGS_BOTH, ("mac_mls_subject_privileged: subject doesn't have both labels")); /* If the single is EQUAL, it's ok. */ if (mac_mls->mm_single.mme_type == MAC_MLS_TYPE_EQUAL) return (0); /* If either range endpoint is EQUAL, it's ok. */ if (mac_mls->mm_rangelow.mme_type == MAC_MLS_TYPE_EQUAL || mac_mls->mm_rangehigh.mme_type == MAC_MLS_TYPE_EQUAL) return (0); /* If the range is low-high, it's ok. */ if (mac_mls->mm_rangelow.mme_type == MAC_MLS_TYPE_LOW && mac_mls->mm_rangehigh.mme_type == MAC_MLS_TYPE_HIGH) return (0); /* It's not ok. */ return (EPERM); } static int mac_mls_valid(struct mac_mls *mac_mls) { if (mac_mls->mm_flags & MAC_MLS_FLAG_SINGLE) { switch (mac_mls->mm_single.mme_type) { case MAC_MLS_TYPE_LEVEL: break; case MAC_MLS_TYPE_EQUAL: case MAC_MLS_TYPE_HIGH: case MAC_MLS_TYPE_LOW: if (mac_mls->mm_single.mme_level != 0 || !MAC_MLS_BIT_SET_EMPTY( mac_mls->mm_single.mme_compartments)) return (EINVAL); break; default: return (EINVAL); } } else { if (mac_mls->mm_single.mme_type != MAC_MLS_TYPE_UNDEF) return (EINVAL); } if (mac_mls->mm_flags & MAC_MLS_FLAG_RANGE) { switch (mac_mls->mm_rangelow.mme_type) { case MAC_MLS_TYPE_LEVEL: break; case MAC_MLS_TYPE_EQUAL: case MAC_MLS_TYPE_HIGH: case MAC_MLS_TYPE_LOW: if (mac_mls->mm_rangelow.mme_level != 0 || !MAC_MLS_BIT_SET_EMPTY( mac_mls->mm_rangelow.mme_compartments)) return (EINVAL); break; default: return (EINVAL); } switch (mac_mls->mm_rangehigh.mme_type) { case MAC_MLS_TYPE_LEVEL: break; case MAC_MLS_TYPE_EQUAL: case MAC_MLS_TYPE_HIGH: case MAC_MLS_TYPE_LOW: if (mac_mls->mm_rangehigh.mme_level != 0 || !MAC_MLS_BIT_SET_EMPTY( mac_mls->mm_rangehigh.mme_compartments)) return (EINVAL); break; default: return (EINVAL); } if (!mac_mls_dominate_element(&mac_mls->mm_rangehigh, &mac_mls->mm_rangelow)) return (EINVAL); } else { if (mac_mls->mm_rangelow.mme_type != MAC_MLS_TYPE_UNDEF || mac_mls->mm_rangehigh.mme_type != MAC_MLS_TYPE_UNDEF) return (EINVAL); } return (0); } static void mac_mls_set_range(struct mac_mls *mac_mls, u_short typelow, u_short levellow, u_char *compartmentslow, u_short typehigh, u_short levelhigh, u_char *compartmentshigh) { mac_mls->mm_rangelow.mme_type = typelow; mac_mls->mm_rangelow.mme_level = levellow; if (compartmentslow != NULL) memcpy(mac_mls->mm_rangelow.mme_compartments, compartmentslow, sizeof(mac_mls->mm_rangelow.mme_compartments)); mac_mls->mm_rangehigh.mme_type = typehigh; mac_mls->mm_rangehigh.mme_level = levelhigh; if (compartmentshigh != NULL) memcpy(mac_mls->mm_rangehigh.mme_compartments, compartmentshigh, sizeof(mac_mls->mm_rangehigh.mme_compartments)); mac_mls->mm_flags |= MAC_MLS_FLAG_RANGE; } static void mac_mls_set_single(struct mac_mls *mac_mls, u_short type, u_short level, u_char *compartments) { mac_mls->mm_single.mme_type = type; mac_mls->mm_single.mme_level = level; if (compartments != NULL) memcpy(mac_mls->mm_single.mme_compartments, compartments, sizeof(mac_mls->mm_single.mme_compartments)); mac_mls->mm_flags |= MAC_MLS_FLAG_SINGLE; } static void mac_mls_copy_range(struct mac_mls *labelfrom, struct mac_mls *labelto) { KASSERT((labelfrom->mm_flags & MAC_MLS_FLAG_RANGE) != 0, ("mac_mls_copy_range: labelfrom not range")); labelto->mm_rangelow = labelfrom->mm_rangelow; labelto->mm_rangehigh = labelfrom->mm_rangehigh; labelto->mm_flags |= MAC_MLS_FLAG_RANGE; } static void mac_mls_copy_single(struct mac_mls *labelfrom, struct mac_mls *labelto) { KASSERT((labelfrom->mm_flags & MAC_MLS_FLAG_SINGLE) != 0, ("mac_mls_copy_single: labelfrom not single")); labelto->mm_single = labelfrom->mm_single; labelto->mm_flags |= MAC_MLS_FLAG_SINGLE; } static void mac_mls_copy(struct mac_mls *source, struct mac_mls *dest) { if (source->mm_flags & MAC_MLS_FLAG_SINGLE) mac_mls_copy_single(source, dest); if (source->mm_flags & MAC_MLS_FLAG_RANGE) mac_mls_copy_range(source, dest); } /* * Policy module operations. */ static void mac_mls_init(struct mac_policy_conf *conf) { zone_mls = uma_zcreate("mac_mls", sizeof(struct mac_mls), NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); } /* * Label operations. */ static void mac_mls_init_label(struct label *label) { SLOT(label) = mls_alloc(M_WAITOK); } static int mac_mls_init_label_waitcheck(struct label *label, int flag) { SLOT(label) = mls_alloc(flag); if (SLOT(label) == NULL) return (ENOMEM); return (0); } static void mac_mls_destroy_label(struct label *label) { mls_free(SLOT(label)); SLOT(label) = NULL; } /* * mac_mls_element_to_string() accepts an sbuf and MLS element. It * converts the MLS element to a string and stores the result in the * sbuf; if there isn't space in the sbuf, -1 is returned. */ static int mac_mls_element_to_string(struct sbuf *sb, struct mac_mls_element *element) { int i, first; switch (element->mme_type) { case MAC_MLS_TYPE_HIGH: return (sbuf_printf(sb, "high")); case MAC_MLS_TYPE_LOW: return (sbuf_printf(sb, "low")); case MAC_MLS_TYPE_EQUAL: return (sbuf_printf(sb, "equal")); case MAC_MLS_TYPE_LEVEL: if (sbuf_printf(sb, "%d", element->mme_level) == -1) return (-1); first = 1; for (i = 1; i <= MAC_MLS_MAX_COMPARTMENTS; i++) { if (MAC_MLS_BIT_TEST(i, element->mme_compartments)) { if (first) { if (sbuf_putc(sb, ':') == -1) return (-1); if (sbuf_printf(sb, "%d", i) == -1) return (-1); first = 0; } else { if (sbuf_printf(sb, "+%d", i) == -1) return (-1); } } } return (0); default: panic("mac_mls_element_to_string: invalid type (%d)", element->mme_type); } } /* * mac_mls_to_string() converts an MLS label to a string, and places * the results in the passed sbuf. It returns 0 on success, or EINVAL * if there isn't room in the sbuf. Note: the sbuf will be modified * even in a failure case, so the caller may need to revert the sbuf * by restoring the offset if that's undesired. */ static int mac_mls_to_string(struct sbuf *sb, struct mac_mls *mac_mls) { if (mac_mls->mm_flags & MAC_MLS_FLAG_SINGLE) { if (mac_mls_element_to_string(sb, &mac_mls->mm_single) == -1) return (EINVAL); } if (mac_mls->mm_flags & MAC_MLS_FLAG_RANGE) { if (sbuf_putc(sb, '(') == -1) return (EINVAL); if (mac_mls_element_to_string(sb, &mac_mls->mm_rangelow) == -1) return (EINVAL); if (sbuf_putc(sb, '-') == -1) return (EINVAL); if (mac_mls_element_to_string(sb, &mac_mls->mm_rangehigh) == -1) return (EINVAL); if (sbuf_putc(sb, ')') == -1) return (EINVAL); } return (0); } static int mac_mls_externalize_label(struct label *label, char *element_name, struct sbuf *sb, int *claimed) { struct mac_mls *mac_mls; if (strcmp(MAC_MLS_LABEL_NAME, element_name) != 0) return (0); (*claimed)++; mac_mls = SLOT(label); return (mac_mls_to_string(sb, mac_mls)); } static int mac_mls_parse_element(struct mac_mls_element *element, char *string) { char *compartment, *end, *level; int value; if (strcmp(string, "high") == 0 || strcmp(string, "hi") == 0) { element->mme_type = MAC_MLS_TYPE_HIGH; element->mme_level = MAC_MLS_TYPE_UNDEF; } else if (strcmp(string, "low") == 0 || strcmp(string, "lo") == 0) { element->mme_type = MAC_MLS_TYPE_LOW; element->mme_level = MAC_MLS_TYPE_UNDEF; } else if (strcmp(string, "equal") == 0 || strcmp(string, "eq") == 0) { element->mme_type = MAC_MLS_TYPE_EQUAL; element->mme_level = MAC_MLS_TYPE_UNDEF; } else { element->mme_type = MAC_MLS_TYPE_LEVEL; /* * Numeric level piece of the element. */ level = strsep(&string, ":"); value = strtol(level, &end, 10); if (end == level || *end != '\0') return (EINVAL); if (value < 0 || value > 65535) return (EINVAL); element->mme_level = value; /* * Optional compartment piece of the element. If none * are included, we assume that the label has no * compartments. */ if (string == NULL) return (0); if (*string == '\0') return (0); while ((compartment = strsep(&string, "+")) != NULL) { value = strtol(compartment, &end, 10); if (compartment == end || *end != '\0') return (EINVAL); if (value < 1 || value > MAC_MLS_MAX_COMPARTMENTS) return (EINVAL); MAC_MLS_BIT_SET(value, element->mme_compartments); } } return (0); } /* * Note: destructively consumes the string, make a local copy before * calling if that's a problem. */ static int mac_mls_parse(struct mac_mls *mac_mls, char *string) { char *rangehigh, *rangelow, *single; int error; single = strsep(&string, "("); if (*single == '\0') single = NULL; if (string != NULL) { rangelow = strsep(&string, "-"); if (string == NULL) return (EINVAL); rangehigh = strsep(&string, ")"); if (string == NULL) return (EINVAL); if (*string != '\0') return (EINVAL); } else { rangelow = NULL; rangehigh = NULL; } KASSERT((rangelow != NULL && rangehigh != NULL) || (rangelow == NULL && rangehigh == NULL), ("mac_mls_parse: range mismatch")); bzero(mac_mls, sizeof(*mac_mls)); if (single != NULL) { error = mac_mls_parse_element(&mac_mls->mm_single, single); if (error) return (error); mac_mls->mm_flags |= MAC_MLS_FLAG_SINGLE; } if (rangelow != NULL) { error = mac_mls_parse_element(&mac_mls->mm_rangelow, rangelow); if (error) return (error); error = mac_mls_parse_element(&mac_mls->mm_rangehigh, rangehigh); if (error) return (error); mac_mls->mm_flags |= MAC_MLS_FLAG_RANGE; } error = mac_mls_valid(mac_mls); if (error) return (error); return (0); } static int mac_mls_internalize_label(struct label *label, char *element_name, char *element_data, int *claimed) { struct mac_mls *mac_mls, mac_mls_temp; int error; if (strcmp(MAC_MLS_LABEL_NAME, element_name) != 0) return (0); (*claimed)++; error = mac_mls_parse(&mac_mls_temp, element_data); if (error) return (error); mac_mls = SLOT(label); *mac_mls = mac_mls_temp; return (0); } static void mac_mls_copy_label(struct label *src, struct label *dest) { *SLOT(dest) = *SLOT(src); } /* * Labeling event operations: file system objects, and things that look * a lot like file system objects. */ static void mac_mls_create_devfs_device(struct mount *mp, dev_t dev, struct devfs_dirent *devfs_dirent, struct label *label) { struct mac_mls *mac_mls; int mls_type; mac_mls = SLOT(label); if (strcmp(dev->si_name, "null") == 0 || strcmp(dev->si_name, "zero") == 0 || strcmp(dev->si_name, "random") == 0 || strncmp(dev->si_name, "fd/", strlen("fd/")) == 0) mls_type = MAC_MLS_TYPE_EQUAL; else if (strcmp(dev->si_name, "kmem") == 0 || strcmp(dev->si_name, "mem") == 0) mls_type = MAC_MLS_TYPE_HIGH; else if (ptys_equal && (strncmp(dev->si_name, "ttyp", strlen("ttyp")) == 0 || strncmp(dev->si_name, "ptyp", strlen("ptyp")) == 0)) mls_type = MAC_MLS_TYPE_EQUAL; else mls_type = MAC_MLS_TYPE_LOW; mac_mls_set_single(mac_mls, mls_type, 0, NULL); } static void mac_mls_create_devfs_directory(struct mount *mp, char *dirname, int dirnamelen, struct devfs_dirent *devfs_dirent, struct label *label) { struct mac_mls *mac_mls; mac_mls = SLOT(label); mac_mls_set_single(mac_mls, MAC_MLS_TYPE_LOW, 0, NULL); } static void mac_mls_create_devfs_symlink(struct ucred *cred, struct mount *mp, struct devfs_dirent *dd, struct label *ddlabel, struct devfs_dirent *de, struct label *delabel) { struct mac_mls *source, *dest; source = SLOT(cred->cr_label); dest = SLOT(delabel); mac_mls_copy_single(source, dest); } static void mac_mls_create_mount(struct ucred *cred, struct mount *mp, struct label *mntlabel, struct label *fslabel) { struct mac_mls *source, *dest; source = SLOT(cred->cr_label); dest = SLOT(mntlabel); mac_mls_copy_single(source, dest); dest = SLOT(fslabel); mac_mls_copy_single(source, dest); } static void mac_mls_create_root_mount(struct ucred *cred, struct mount *mp, struct label *mntlabel, struct label *fslabel) { struct mac_mls *mac_mls; /* Always mount root as high integrity. */ mac_mls = SLOT(fslabel); mac_mls_set_single(mac_mls, MAC_MLS_TYPE_LOW, 0, NULL); mac_mls = SLOT(mntlabel); mac_mls_set_single(mac_mls, MAC_MLS_TYPE_LOW, 0, NULL); } static void mac_mls_relabel_vnode(struct ucred *cred, struct vnode *vp, struct label *vnodelabel, struct label *label) { struct mac_mls *source, *dest; source = SLOT(label); dest = SLOT(vnodelabel); mac_mls_copy(source, dest); } static void mac_mls_update_devfsdirent(struct mount *mp, struct devfs_dirent *devfs_dirent, struct label *direntlabel, struct vnode *vp, struct label *vnodelabel) { struct mac_mls *source, *dest; source = SLOT(vnodelabel); dest = SLOT(direntlabel); mac_mls_copy_single(source, dest); } static void mac_mls_associate_vnode_devfs(struct mount *mp, struct label *fslabel, struct devfs_dirent *de, struct label *delabel, struct vnode *vp, struct label *vlabel) { struct mac_mls *source, *dest; source = SLOT(delabel); dest = SLOT(vlabel); mac_mls_copy_single(source, dest); } static int mac_mls_associate_vnode_extattr(struct mount *mp, struct label *fslabel, struct vnode *vp, struct label *vlabel) { struct mac_mls temp, *source, *dest; int buflen, error; source = SLOT(fslabel); dest = SLOT(vlabel); buflen = sizeof(temp); bzero(&temp, buflen); error = vn_extattr_get(vp, IO_NODELOCKED, MAC_MLS_EXTATTR_NAMESPACE, MAC_MLS_EXTATTR_NAME, &buflen, (char *) &temp, curthread); if (error == ENOATTR || error == EOPNOTSUPP) { /* Fall back to the fslabel. */ mac_mls_copy_single(source, dest); return (0); } else if (error) return (error); if (buflen != sizeof(temp)) { printf("mac_mls_associate_vnode_extattr: bad size %d\n", buflen); return (EPERM); } if (mac_mls_valid(&temp) != 0) { printf("mac_mls_associate_vnode_extattr: invalid\n"); return (EPERM); } if ((temp.mm_flags & MAC_MLS_FLAGS_BOTH) != MAC_MLS_FLAG_SINGLE) { printf("mac_mls_associated_vnode_extattr: not single\n"); return (EPERM); } mac_mls_copy_single(&temp, dest); return (0); } static void mac_mls_associate_vnode_singlelabel(struct mount *mp, struct label *fslabel, struct vnode *vp, struct label *vlabel) { struct mac_mls *source, *dest; source = SLOT(fslabel); dest = SLOT(vlabel); mac_mls_copy_single(source, dest); } static int mac_mls_create_vnode_extattr(struct ucred *cred, struct mount *mp, struct label *fslabel, struct vnode *dvp, struct label *dlabel, struct vnode *vp, struct label *vlabel, struct componentname *cnp) { struct mac_mls *source, *dest, temp; size_t buflen; int error; buflen = sizeof(temp); bzero(&temp, buflen); source = SLOT(cred->cr_label); dest = SLOT(vlabel); mac_mls_copy_single(source, &temp); error = vn_extattr_set(vp, IO_NODELOCKED, MAC_MLS_EXTATTR_NAMESPACE, MAC_MLS_EXTATTR_NAME, buflen, (char *) &temp, curthread); if (error == 0) mac_mls_copy_single(source, dest); return (error); } static int mac_mls_setlabel_vnode_extattr(struct ucred *cred, struct vnode *vp, struct label *vlabel, struct label *intlabel) { struct mac_mls *source, temp; size_t buflen; int error; buflen = sizeof(temp); bzero(&temp, buflen); source = SLOT(intlabel); if ((source->mm_flags & MAC_MLS_FLAG_SINGLE) == 0) return (0); mac_mls_copy_single(source, &temp); error = vn_extattr_set(vp, IO_NODELOCKED, MAC_MLS_EXTATTR_NAMESPACE, MAC_MLS_EXTATTR_NAME, buflen, (char *) &temp, curthread); return (error); } /* * Labeling event operations: IPC object. */ static void mac_mls_create_inpcb_from_socket(struct socket *so, struct label *solabel, struct inpcb *inp, struct label *inplabel) { struct mac_mls *source, *dest; source = SLOT(solabel); dest = SLOT(inplabel); mac_mls_copy_single(source, dest); } static void mac_mls_create_mbuf_from_socket(struct socket *so, struct label *socketlabel, struct mbuf *m, struct label *mbuflabel) { struct mac_mls *source, *dest; source = SLOT(socketlabel); dest = SLOT(mbuflabel); mac_mls_copy_single(source, dest); } static void mac_mls_create_socket(struct ucred *cred, struct socket *socket, struct label *socketlabel) { struct mac_mls *source, *dest; source = SLOT(cred->cr_label); dest = SLOT(socketlabel); mac_mls_copy_single(source, dest); } static void -mac_mls_create_pipe(struct ucred *cred, struct pipe *pipe, +mac_mls_create_pipe(struct ucred *cred, struct pipepair *pp, struct label *pipelabel) { struct mac_mls *source, *dest; source = SLOT(cred->cr_label); dest = SLOT(pipelabel); mac_mls_copy_single(source, dest); } static void mac_mls_create_socket_from_socket(struct socket *oldsocket, struct label *oldsocketlabel, struct socket *newsocket, struct label *newsocketlabel) { struct mac_mls *source, *dest; source = SLOT(oldsocketlabel); dest = SLOT(newsocketlabel); mac_mls_copy_single(source, dest); } static void mac_mls_relabel_socket(struct ucred *cred, struct socket *socket, struct label *socketlabel, struct label *newlabel) { struct mac_mls *source, *dest; source = SLOT(newlabel); dest = SLOT(socketlabel); mac_mls_copy(source, dest); } static void -mac_mls_relabel_pipe(struct ucred *cred, struct pipe *pipe, +mac_mls_relabel_pipe(struct ucred *cred, struct pipepair *pp, struct label *pipelabel, struct label *newlabel) { struct mac_mls *source, *dest; source = SLOT(newlabel); dest = SLOT(pipelabel); mac_mls_copy(source, dest); } static void mac_mls_set_socket_peer_from_mbuf(struct mbuf *mbuf, struct label *mbuflabel, struct socket *socket, struct label *socketpeerlabel) { struct mac_mls *source, *dest; source = SLOT(mbuflabel); dest = SLOT(socketpeerlabel); mac_mls_copy_single(source, dest); } /* * Labeling event operations: network objects. */ static void mac_mls_set_socket_peer_from_socket(struct socket *oldsocket, struct label *oldsocketlabel, struct socket *newsocket, struct label *newsocketpeerlabel) { struct mac_mls *source, *dest; source = SLOT(oldsocketlabel); dest = SLOT(newsocketpeerlabel); mac_mls_copy_single(source, dest); } static void mac_mls_create_bpfdesc(struct ucred *cred, struct bpf_d *bpf_d, struct label *bpflabel) { struct mac_mls *source, *dest; source = SLOT(cred->cr_label); dest = SLOT(bpflabel); mac_mls_copy_single(source, dest); } static void mac_mls_create_ifnet(struct ifnet *ifnet, struct label *ifnetlabel) { struct mac_mls *dest; int type; dest = SLOT(ifnetlabel); if (ifnet->if_type == IFT_LOOP) type = MAC_MLS_TYPE_EQUAL; else type = MAC_MLS_TYPE_LOW; mac_mls_set_single(dest, type, 0, NULL); mac_mls_set_range(dest, type, 0, NULL, type, 0, NULL); } static void mac_mls_create_ipq(struct mbuf *fragment, struct label *fragmentlabel, struct ipq *ipq, struct label *ipqlabel) { struct mac_mls *source, *dest; source = SLOT(fragmentlabel); dest = SLOT(ipqlabel); mac_mls_copy_single(source, dest); } static void mac_mls_create_datagram_from_ipq(struct ipq *ipq, struct label *ipqlabel, struct mbuf *datagram, struct label *datagramlabel) { struct mac_mls *source, *dest; source = SLOT(ipqlabel); dest = SLOT(datagramlabel); /* Just use the head, since we require them all to match. */ mac_mls_copy_single(source, dest); } static void mac_mls_create_fragment(struct mbuf *datagram, struct label *datagramlabel, struct mbuf *fragment, struct label *fragmentlabel) { struct mac_mls *source, *dest; source = SLOT(datagramlabel); dest = SLOT(fragmentlabel); mac_mls_copy_single(source, dest); } static void mac_mls_create_mbuf_from_inpcb(struct inpcb *inp, struct label *inplabel, struct mbuf *m, struct label *mlabel) { struct mac_mls *source, *dest; source = SLOT(inplabel); dest = SLOT(mlabel); mac_mls_copy_single(source, dest); } static void mac_mls_create_mbuf_from_mbuf(struct mbuf *oldmbuf, struct label *oldmbuflabel, struct mbuf *newmbuf, struct label *newmbuflabel) { struct mac_mls *source, *dest; source = SLOT(oldmbuflabel); dest = SLOT(newmbuflabel); /* * Because the source mbuf may not yet have been "created", * just initialized, we do a conditional copy. Since we don't * allow mbufs to have ranges, do a KASSERT to make sure that * doesn't happen. */ KASSERT((source->mm_flags & MAC_MLS_FLAG_RANGE) == 0, ("mac_mls_create_mbuf_from_mbuf: source mbuf has range")); mac_mls_copy(source, dest); } static void mac_mls_create_mbuf_linklayer(struct ifnet *ifnet, struct label *ifnetlabel, struct mbuf *mbuf, struct label *mbuflabel) { struct mac_mls *dest; dest = SLOT(mbuflabel); mac_mls_set_single(dest, MAC_MLS_TYPE_EQUAL, 0, NULL); } static void mac_mls_create_mbuf_from_bpfdesc(struct bpf_d *bpf_d, struct label *bpflabel, struct mbuf *mbuf, struct label *mbuflabel) { struct mac_mls *source, *dest; source = SLOT(bpflabel); dest = SLOT(mbuflabel); mac_mls_copy_single(source, dest); } static void mac_mls_create_mbuf_from_ifnet(struct ifnet *ifnet, struct label *ifnetlabel, struct mbuf *m, struct label *mbuflabel) { struct mac_mls *source, *dest; source = SLOT(ifnetlabel); dest = SLOT(mbuflabel); mac_mls_copy_single(source, dest); } static void mac_mls_create_mbuf_multicast_encap(struct mbuf *oldmbuf, struct label *oldmbuflabel, struct ifnet *ifnet, struct label *ifnetlabel, struct mbuf *newmbuf, struct label *newmbuflabel) { struct mac_mls *source, *dest; source = SLOT(oldmbuflabel); dest = SLOT(newmbuflabel); mac_mls_copy_single(source, dest); } static void mac_mls_create_mbuf_netlayer(struct mbuf *oldmbuf, struct label *oldmbuflabel, struct mbuf *newmbuf, struct label *newmbuflabel) { struct mac_mls *source, *dest; source = SLOT(oldmbuflabel); dest = SLOT(newmbuflabel); mac_mls_copy_single(source, dest); } static int mac_mls_fragment_match(struct mbuf *fragment, struct label *fragmentlabel, struct ipq *ipq, struct label *ipqlabel) { struct mac_mls *a, *b; a = SLOT(ipqlabel); b = SLOT(fragmentlabel); return (mac_mls_equal_single(a, b)); } static void mac_mls_relabel_ifnet(struct ucred *cred, struct ifnet *ifnet, struct label *ifnetlabel, struct label *newlabel) { struct mac_mls *source, *dest; source = SLOT(newlabel); dest = SLOT(ifnetlabel); mac_mls_copy(source, dest); } static void mac_mls_update_ipq(struct mbuf *fragment, struct label *fragmentlabel, struct ipq *ipq, struct label *ipqlabel) { /* NOOP: we only accept matching labels, so no need to update */ } static void mac_mls_inpcb_sosetlabel(struct socket *so, struct label *solabel, struct inpcb *inp, struct label *inplabel) { struct mac_mls *source, *dest; source = SLOT(solabel); dest = SLOT(inplabel); mac_mls_copy(source, dest); } /* * Labeling event operations: processes. */ static void mac_mls_create_proc0(struct ucred *cred) { struct mac_mls *dest; dest = SLOT(cred->cr_label); mac_mls_set_single(dest, MAC_MLS_TYPE_EQUAL, 0, NULL); mac_mls_set_range(dest, MAC_MLS_TYPE_LOW, 0, NULL, MAC_MLS_TYPE_HIGH, 0, NULL); } static void mac_mls_create_proc1(struct ucred *cred) { struct mac_mls *dest; dest = SLOT(cred->cr_label); mac_mls_set_single(dest, MAC_MLS_TYPE_LOW, 0, NULL); mac_mls_set_range(dest, MAC_MLS_TYPE_LOW, 0, NULL, MAC_MLS_TYPE_HIGH, 0, NULL); } static void mac_mls_relabel_cred(struct ucred *cred, struct label *newlabel) { struct mac_mls *source, *dest; source = SLOT(newlabel); dest = SLOT(cred->cr_label); mac_mls_copy(source, dest); } /* * Access control checks. */ static int mac_mls_check_bpfdesc_receive(struct bpf_d *bpf_d, struct label *bpflabel, struct ifnet *ifnet, struct label *ifnetlabel) { struct mac_mls *a, *b; if (!mac_mls_enabled) return (0); a = SLOT(bpflabel); b = SLOT(ifnetlabel); if (mac_mls_equal_single(a, b)) return (0); return (EACCES); } static int mac_mls_check_cred_relabel(struct ucred *cred, struct label *newlabel) { struct mac_mls *subj, *new; int error; subj = SLOT(cred->cr_label); new = SLOT(newlabel); /* * If there is an MLS label update for the credential, it may be * an update of single, range, or both. */ error = mls_atmostflags(new, MAC_MLS_FLAGS_BOTH); if (error) return (error); /* * If the MLS label is to be changed, authorize as appropriate. */ if (new->mm_flags & MAC_MLS_FLAGS_BOTH) { /* * If the change request modifies both the MLS label single * and range, check that the new single will be in the * new range. */ if ((new->mm_flags & MAC_MLS_FLAGS_BOTH) == MAC_MLS_FLAGS_BOTH && !mac_mls_single_in_range(new, new)) return (EINVAL); /* * To change the MLS single label on a credential, the * new single label must be in the current range. */ if (new->mm_flags & MAC_MLS_FLAG_SINGLE && !mac_mls_single_in_range(new, subj)) return (EPERM); /* * To change the MLS range label on a credential, the * new range must be in the current range. */ if (new->mm_flags & MAC_MLS_FLAG_RANGE && !mac_mls_range_in_range(new, subj)) return (EPERM); /* * To have EQUAL in any component of the new credential * MLS label, the subject must already have EQUAL in * their label. */ if (mac_mls_contains_equal(new)) { error = mac_mls_subject_privileged(subj); if (error) return (error); } } return (0); } static int mac_mls_check_cred_visible(struct ucred *u1, struct ucred *u2) { struct mac_mls *subj, *obj; if (!mac_mls_enabled) return (0); subj = SLOT(u1->cr_label); obj = SLOT(u2->cr_label); /* XXX: range */ if (!mac_mls_dominate_single(subj, obj)) return (ESRCH); return (0); } static int mac_mls_check_ifnet_relabel(struct ucred *cred, struct ifnet *ifnet, struct label *ifnetlabel, struct label *newlabel) { struct mac_mls *subj, *new; int error; subj = SLOT(cred->cr_label); new = SLOT(newlabel); /* * If there is an MLS label update for the interface, it may * be an update of single, range, or both. */ error = mls_atmostflags(new, MAC_MLS_FLAGS_BOTH); if (error) return (error); /* * Relabeling network interfaces requires MLS privilege. */ error = mac_mls_subject_privileged(subj); return (0); } static int mac_mls_check_ifnet_transmit(struct ifnet *ifnet, struct label *ifnetlabel, struct mbuf *m, struct label *mbuflabel) { struct mac_mls *p, *i; if (!mac_mls_enabled) return (0); p = SLOT(mbuflabel); i = SLOT(ifnetlabel); return (mac_mls_single_in_range(p, i) ? 0 : EACCES); } static int mac_mls_check_inpcb_deliver(struct inpcb *inp, struct label *inplabel, struct mbuf *m, struct label *mlabel) { struct mac_mls *p, *i; if (!mac_mls_enabled) return (0); p = SLOT(mlabel); i = SLOT(inplabel); return (mac_mls_equal_single(p, i) ? 0 : EACCES); } static int mac_mls_check_mount_stat(struct ucred *cred, struct mount *mp, struct label *mntlabel) { struct mac_mls *subj, *obj; if (!mac_mls_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(mntlabel); if (!mac_mls_dominate_single(subj, obj)) return (EACCES); return (0); } static int -mac_mls_check_pipe_ioctl(struct ucred *cred, struct pipe *pipe, +mac_mls_check_pipe_ioctl(struct ucred *cred, struct pipepair *pp, struct label *pipelabel, unsigned long cmd, void /* caddr_t */ *data) { if(!mac_mls_enabled) return (0); /* XXX: This will be implemented soon... */ return (0); } static int -mac_mls_check_pipe_poll(struct ucred *cred, struct pipe *pipe, +mac_mls_check_pipe_poll(struct ucred *cred, struct pipepair *pp, struct label *pipelabel) { struct mac_mls *subj, *obj; if (!mac_mls_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT((pipelabel)); if (!mac_mls_dominate_single(subj, obj)) return (EACCES); return (0); } static int -mac_mls_check_pipe_read(struct ucred *cred, struct pipe *pipe, +mac_mls_check_pipe_read(struct ucred *cred, struct pipepair *pp, struct label *pipelabel) { struct mac_mls *subj, *obj; if (!mac_mls_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT((pipelabel)); if (!mac_mls_dominate_single(subj, obj)) return (EACCES); return (0); } static int -mac_mls_check_pipe_relabel(struct ucred *cred, struct pipe *pipe, +mac_mls_check_pipe_relabel(struct ucred *cred, struct pipepair *pp, struct label *pipelabel, struct label *newlabel) { struct mac_mls *subj, *obj, *new; int error; new = SLOT(newlabel); subj = SLOT(cred->cr_label); obj = SLOT(pipelabel); /* * If there is an MLS label update for a pipe, it must be a * single update. */ error = mls_atmostflags(new, MAC_MLS_FLAG_SINGLE); if (error) return (error); /* * To perform a relabel of a pipe (MLS label or not), MLS must * authorize the relabel. */ if (!mac_mls_single_in_range(obj, subj)) return (EPERM); /* * If the MLS label is to be changed, authorize as appropriate. */ if (new->mm_flags & MAC_MLS_FLAG_SINGLE) { /* * To change the MLS label on a pipe, the new pipe label * must be in the subject range. */ if (!mac_mls_single_in_range(new, subj)) return (EPERM); /* * To change the MLS label on a pipe to be EQUAL, the * subject must have appropriate privilege. */ if (mac_mls_contains_equal(new)) { error = mac_mls_subject_privileged(subj); if (error) return (error); } } return (0); } static int -mac_mls_check_pipe_stat(struct ucred *cred, struct pipe *pipe, +mac_mls_check_pipe_stat(struct ucred *cred, struct pipepair *pp, struct label *pipelabel) { struct mac_mls *subj, *obj; if (!mac_mls_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT((pipelabel)); if (!mac_mls_dominate_single(subj, obj)) return (EACCES); return (0); } static int -mac_mls_check_pipe_write(struct ucred *cred, struct pipe *pipe, +mac_mls_check_pipe_write(struct ucred *cred, struct pipepair *pp, struct label *pipelabel) { struct mac_mls *subj, *obj; if (!mac_mls_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT((pipelabel)); if (!mac_mls_dominate_single(obj, subj)) return (EACCES); return (0); } static int mac_mls_check_proc_debug(struct ucred *cred, struct proc *proc) { struct mac_mls *subj, *obj; if (!mac_mls_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(proc->p_ucred->cr_label); /* XXX: range checks */ if (!mac_mls_dominate_single(subj, obj)) return (ESRCH); if (!mac_mls_dominate_single(obj, subj)) return (EACCES); return (0); } static int mac_mls_check_proc_sched(struct ucred *cred, struct proc *proc) { struct mac_mls *subj, *obj; if (!mac_mls_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(proc->p_ucred->cr_label); /* XXX: range checks */ if (!mac_mls_dominate_single(subj, obj)) return (ESRCH); if (!mac_mls_dominate_single(obj, subj)) return (EACCES); return (0); } static int mac_mls_check_proc_signal(struct ucred *cred, struct proc *proc, int signum) { struct mac_mls *subj, *obj; if (!mac_mls_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(proc->p_ucred->cr_label); /* XXX: range checks */ if (!mac_mls_dominate_single(subj, obj)) return (ESRCH); if (!mac_mls_dominate_single(obj, subj)) return (EACCES); return (0); } static int mac_mls_check_socket_deliver(struct socket *so, struct label *socketlabel, struct mbuf *m, struct label *mbuflabel) { struct mac_mls *p, *s; if (!mac_mls_enabled) return (0); p = SLOT(mbuflabel); s = SLOT(socketlabel); return (mac_mls_equal_single(p, s) ? 0 : EACCES); } static int mac_mls_check_socket_relabel(struct ucred *cred, struct socket *socket, struct label *socketlabel, struct label *newlabel) { struct mac_mls *subj, *obj, *new; int error; new = SLOT(newlabel); subj = SLOT(cred->cr_label); obj = SLOT(socketlabel); /* * If there is an MLS label update for the socket, it may be * an update of single. */ error = mls_atmostflags(new, MAC_MLS_FLAG_SINGLE); if (error) return (error); /* * To relabel a socket, the old socket single must be in the subject * range. */ if (!mac_mls_single_in_range(obj, subj)) return (EPERM); /* * If the MLS label is to be changed, authorize as appropriate. */ if (new->mm_flags & MAC_MLS_FLAG_SINGLE) { /* * To relabel a socket, the new socket single must be in * the subject range. */ if (!mac_mls_single_in_range(new, subj)) return (EPERM); /* * To change the MLS label on the socket to contain EQUAL, * the subject must have appropriate privilege. */ if (mac_mls_contains_equal(new)) { error = mac_mls_subject_privileged(subj); if (error) return (error); } } return (0); } static int mac_mls_check_socket_visible(struct ucred *cred, struct socket *socket, struct label *socketlabel) { struct mac_mls *subj, *obj; if (!mac_mls_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(socketlabel); if (!mac_mls_dominate_single(subj, obj)) return (ENOENT); return (0); } static int mac_mls_check_system_swapon(struct ucred *cred, struct vnode *vp, struct label *label) { struct mac_mls *subj, *obj; if (!mac_mls_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(label); if (!mac_mls_dominate_single(obj, subj) || !mac_mls_dominate_single(subj, obj)) return (EACCES); return (0); } static int mac_mls_check_vnode_chdir(struct ucred *cred, struct vnode *dvp, struct label *dlabel) { struct mac_mls *subj, *obj; if (!mac_mls_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(dlabel); if (!mac_mls_dominate_single(subj, obj)) return (EACCES); return (0); } static int mac_mls_check_vnode_chroot(struct ucred *cred, struct vnode *dvp, struct label *dlabel) { struct mac_mls *subj, *obj; if (!mac_mls_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(dlabel); if (!mac_mls_dominate_single(subj, obj)) return (EACCES); return (0); } static int mac_mls_check_vnode_create(struct ucred *cred, struct vnode *dvp, struct label *dlabel, struct componentname *cnp, struct vattr *vap) { struct mac_mls *subj, *obj; if (!mac_mls_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(dlabel); if (!mac_mls_dominate_single(obj, subj)) return (EACCES); return (0); } static int mac_mls_check_vnode_delete(struct ucred *cred, struct vnode *dvp, struct label *dlabel, struct vnode *vp, struct label *label, struct componentname *cnp) { struct mac_mls *subj, *obj; if (!mac_mls_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(dlabel); if (!mac_mls_dominate_single(obj, subj)) return (EACCES); obj = SLOT(label); if (!mac_mls_dominate_single(obj, subj)) return (EACCES); return (0); } static int mac_mls_check_vnode_deleteacl(struct ucred *cred, struct vnode *vp, struct label *label, acl_type_t type) { struct mac_mls *subj, *obj; if (!mac_mls_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(label); if (!mac_mls_dominate_single(obj, subj)) return (EACCES); return (0); } static int mac_mls_check_vnode_deleteextattr(struct ucred *cred, struct vnode *vp, struct label *label, int attrnamespace, const char *name) { struct mac_mls *subj, *obj; if (!mac_mls_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(label); if (!mac_mls_dominate_single(obj, subj)) return (EACCES); return (0); } static int mac_mls_check_vnode_exec(struct ucred *cred, struct vnode *vp, struct label *label, struct image_params *imgp, struct label *execlabel) { struct mac_mls *subj, *obj, *exec; int error; if (execlabel != NULL) { /* * We currently don't permit labels to be changed at * exec-time as part of MLS, so disallow non-NULL * MLS label elements in the execlabel. */ exec = SLOT(execlabel); error = mls_atmostflags(exec, 0); if (error) return (error); } if (!mac_mls_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(label); if (!mac_mls_dominate_single(subj, obj)) return (EACCES); return (0); } static int mac_mls_check_vnode_getacl(struct ucred *cred, struct vnode *vp, struct label *label, acl_type_t type) { struct mac_mls *subj, *obj; if (!mac_mls_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(label); if (!mac_mls_dominate_single(subj, obj)) return (EACCES); return (0); } static int mac_mls_check_vnode_getextattr(struct ucred *cred, struct vnode *vp, struct label *label, int attrnamespace, const char *name, struct uio *uio) { struct mac_mls *subj, *obj; if (!mac_mls_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(label); if (!mac_mls_dominate_single(subj, obj)) return (EACCES); return (0); } static int mac_mls_check_vnode_link(struct ucred *cred, struct vnode *dvp, struct label *dlabel, struct vnode *vp, struct label *label, struct componentname *cnp) { struct mac_mls *subj, *obj; if (!mac_mls_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(dlabel); if (!mac_mls_dominate_single(obj, subj)) return (EACCES); obj = SLOT(dlabel); if (!mac_mls_dominate_single(obj, subj)) return (EACCES); return (0); } static int mac_mls_check_vnode_listextattr(struct ucred *cred, struct vnode *vp, struct label *label, int attrnamespace) { struct mac_mls *subj, *obj; if (!mac_mls_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(label); if (!mac_mls_dominate_single(subj, obj)) return (EACCES); return (0); } static int mac_mls_check_vnode_lookup(struct ucred *cred, struct vnode *dvp, struct label *dlabel, struct componentname *cnp) { struct mac_mls *subj, *obj; if (!mac_mls_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(dlabel); if (!mac_mls_dominate_single(subj, obj)) return (EACCES); return (0); } static int mac_mls_check_vnode_mmap(struct ucred *cred, struct vnode *vp, struct label *label, int prot) { struct mac_mls *subj, *obj; /* * Rely on the use of open()-time protections to handle * non-revocation cases. */ if (!mac_mls_enabled || !revocation_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(label); if (prot & (VM_PROT_READ | VM_PROT_EXECUTE)) { if (!mac_mls_dominate_single(subj, obj)) return (EACCES); } if (prot & VM_PROT_WRITE) { if (!mac_mls_dominate_single(obj, subj)) return (EACCES); } return (0); } static int mac_mls_check_vnode_open(struct ucred *cred, struct vnode *vp, struct label *vnodelabel, int acc_mode) { struct mac_mls *subj, *obj; if (!mac_mls_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(vnodelabel); /* XXX privilege override for admin? */ if (acc_mode & (VREAD | VEXEC | VSTAT)) { if (!mac_mls_dominate_single(subj, obj)) return (EACCES); } if (acc_mode & (VWRITE | VAPPEND | VADMIN)) { if (!mac_mls_dominate_single(obj, subj)) return (EACCES); } return (0); } static int mac_mls_check_vnode_poll(struct ucred *active_cred, struct ucred *file_cred, struct vnode *vp, struct label *label) { struct mac_mls *subj, *obj; if (!mac_mls_enabled || !revocation_enabled) return (0); subj = SLOT(active_cred->cr_label); obj = SLOT(label); if (!mac_mls_dominate_single(subj, obj)) return (EACCES); return (0); } static int mac_mls_check_vnode_read(struct ucred *active_cred, struct ucred *file_cred, struct vnode *vp, struct label *label) { struct mac_mls *subj, *obj; if (!mac_mls_enabled || !revocation_enabled) return (0); subj = SLOT(active_cred->cr_label); obj = SLOT(label); if (!mac_mls_dominate_single(subj, obj)) return (EACCES); return (0); } static int mac_mls_check_vnode_readdir(struct ucred *cred, struct vnode *dvp, struct label *dlabel) { struct mac_mls *subj, *obj; if (!mac_mls_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(dlabel); if (!mac_mls_dominate_single(subj, obj)) return (EACCES); return (0); } static int mac_mls_check_vnode_readlink(struct ucred *cred, struct vnode *vp, struct label *vnodelabel) { struct mac_mls *subj, *obj; if (!mac_mls_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(vnodelabel); if (!mac_mls_dominate_single(subj, obj)) return (EACCES); return (0); } static int mac_mls_check_vnode_relabel(struct ucred *cred, struct vnode *vp, struct label *vnodelabel, struct label *newlabel) { struct mac_mls *old, *new, *subj; int error; old = SLOT(vnodelabel); new = SLOT(newlabel); subj = SLOT(cred->cr_label); /* * If there is an MLS label update for the vnode, it must be a * single label. */ error = mls_atmostflags(new, MAC_MLS_FLAG_SINGLE); if (error) return (error); /* * To perform a relabel of the vnode (MLS label or not), MLS must * authorize the relabel. */ if (!mac_mls_single_in_range(old, subj)) return (EPERM); /* * If the MLS label is to be changed, authorize as appropriate. */ if (new->mm_flags & MAC_MLS_FLAG_SINGLE) { /* * To change the MLS label on a vnode, the new vnode label * must be in the subject range. */ if (!mac_mls_single_in_range(new, subj)) return (EPERM); /* * To change the MLS label on the vnode to be EQUAL, * the subject must have appropriate privilege. */ if (mac_mls_contains_equal(new)) { error = mac_mls_subject_privileged(subj); if (error) return (error); } } return (0); } static int mac_mls_check_vnode_rename_from(struct ucred *cred, struct vnode *dvp, struct label *dlabel, struct vnode *vp, struct label *label, struct componentname *cnp) { struct mac_mls *subj, *obj; if (!mac_mls_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(dlabel); if (!mac_mls_dominate_single(obj, subj)) return (EACCES); obj = SLOT(label); if (!mac_mls_dominate_single(obj, subj)) return (EACCES); return (0); } static int mac_mls_check_vnode_rename_to(struct ucred *cred, struct vnode *dvp, struct label *dlabel, struct vnode *vp, struct label *label, int samedir, struct componentname *cnp) { struct mac_mls *subj, *obj; if (!mac_mls_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(dlabel); if (!mac_mls_dominate_single(obj, subj)) return (EACCES); if (vp != NULL) { obj = SLOT(label); if (!mac_mls_dominate_single(obj, subj)) return (EACCES); } return (0); } static int mac_mls_check_vnode_revoke(struct ucred *cred, struct vnode *vp, struct label *label) { struct mac_mls *subj, *obj; if (!mac_mls_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(label); if (!mac_mls_dominate_single(obj, subj)) return (EACCES); return (0); } static int mac_mls_check_vnode_setacl(struct ucred *cred, struct vnode *vp, struct label *label, acl_type_t type, struct acl *acl) { struct mac_mls *subj, *obj; if (!mac_mls_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(label); if (!mac_mls_dominate_single(obj, subj)) return (EACCES); return (0); } static int mac_mls_check_vnode_setextattr(struct ucred *cred, struct vnode *vp, struct label *vnodelabel, int attrnamespace, const char *name, struct uio *uio) { struct mac_mls *subj, *obj; if (!mac_mls_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(vnodelabel); if (!mac_mls_dominate_single(obj, subj)) return (EACCES); /* XXX: protect the MAC EA in a special way? */ return (0); } static int mac_mls_check_vnode_setflags(struct ucred *cred, struct vnode *vp, struct label *vnodelabel, u_long flags) { struct mac_mls *subj, *obj; if (!mac_mls_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(vnodelabel); if (!mac_mls_dominate_single(obj, subj)) return (EACCES); return (0); } static int mac_mls_check_vnode_setmode(struct ucred *cred, struct vnode *vp, struct label *vnodelabel, mode_t mode) { struct mac_mls *subj, *obj; if (!mac_mls_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(vnodelabel); if (!mac_mls_dominate_single(obj, subj)) return (EACCES); return (0); } static int mac_mls_check_vnode_setowner(struct ucred *cred, struct vnode *vp, struct label *vnodelabel, uid_t uid, gid_t gid) { struct mac_mls *subj, *obj; if (!mac_mls_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(vnodelabel); if (!mac_mls_dominate_single(obj, subj)) return (EACCES); return (0); } static int mac_mls_check_vnode_setutimes(struct ucred *cred, struct vnode *vp, struct label *vnodelabel, struct timespec atime, struct timespec mtime) { struct mac_mls *subj, *obj; if (!mac_mls_enabled) return (0); subj = SLOT(cred->cr_label); obj = SLOT(vnodelabel); if (!mac_mls_dominate_single(obj, subj)) return (EACCES); return (0); } static int mac_mls_check_vnode_stat(struct ucred *active_cred, struct ucred *file_cred, struct vnode *vp, struct label *vnodelabel) { struct mac_mls *subj, *obj; if (!mac_mls_enabled) return (0); subj = SLOT(active_cred->cr_label); obj = SLOT(vnodelabel); if (!mac_mls_dominate_single(subj, obj)) return (EACCES); return (0); } static int mac_mls_check_vnode_write(struct ucred *active_cred, struct ucred *file_cred, struct vnode *vp, struct label *label) { struct mac_mls *subj, *obj; if (!mac_mls_enabled || !revocation_enabled) return (0); subj = SLOT(active_cred->cr_label); obj = SLOT(label); if (!mac_mls_dominate_single(obj, subj)) return (EACCES); return (0); } static struct mac_policy_ops mac_mls_ops = { .mpo_init = mac_mls_init, .mpo_init_bpfdesc_label = mac_mls_init_label, .mpo_init_cred_label = mac_mls_init_label, .mpo_init_devfsdirent_label = mac_mls_init_label, .mpo_init_ifnet_label = mac_mls_init_label, .mpo_init_inpcb_label = mac_mls_init_label_waitcheck, .mpo_init_ipq_label = mac_mls_init_label_waitcheck, .mpo_init_mbuf_label = mac_mls_init_label_waitcheck, .mpo_init_mount_label = mac_mls_init_label, .mpo_init_mount_fs_label = mac_mls_init_label, .mpo_init_pipe_label = mac_mls_init_label, .mpo_init_socket_label = mac_mls_init_label_waitcheck, .mpo_init_socket_peer_label = mac_mls_init_label_waitcheck, .mpo_init_vnode_label = mac_mls_init_label, .mpo_destroy_bpfdesc_label = mac_mls_destroy_label, .mpo_destroy_cred_label = mac_mls_destroy_label, .mpo_destroy_devfsdirent_label = mac_mls_destroy_label, .mpo_destroy_ifnet_label = mac_mls_destroy_label, .mpo_destroy_inpcb_label = mac_mls_destroy_label, .mpo_destroy_ipq_label = mac_mls_destroy_label, .mpo_destroy_mbuf_label = mac_mls_destroy_label, .mpo_destroy_mount_label = mac_mls_destroy_label, .mpo_destroy_mount_fs_label = mac_mls_destroy_label, .mpo_destroy_pipe_label = mac_mls_destroy_label, .mpo_destroy_socket_label = mac_mls_destroy_label, .mpo_destroy_socket_peer_label = mac_mls_destroy_label, .mpo_destroy_vnode_label = mac_mls_destroy_label, .mpo_copy_cred_label = mac_mls_copy_label, .mpo_copy_mbuf_label = mac_mls_copy_label, .mpo_copy_pipe_label = mac_mls_copy_label, .mpo_copy_socket_label = mac_mls_copy_label, .mpo_copy_vnode_label = mac_mls_copy_label, .mpo_externalize_cred_label = mac_mls_externalize_label, .mpo_externalize_ifnet_label = mac_mls_externalize_label, .mpo_externalize_pipe_label = mac_mls_externalize_label, .mpo_externalize_socket_label = mac_mls_externalize_label, .mpo_externalize_socket_peer_label = mac_mls_externalize_label, .mpo_externalize_vnode_label = mac_mls_externalize_label, .mpo_internalize_cred_label = mac_mls_internalize_label, .mpo_internalize_ifnet_label = mac_mls_internalize_label, .mpo_internalize_pipe_label = mac_mls_internalize_label, .mpo_internalize_socket_label = mac_mls_internalize_label, .mpo_internalize_vnode_label = mac_mls_internalize_label, .mpo_create_devfs_device = mac_mls_create_devfs_device, .mpo_create_devfs_directory = mac_mls_create_devfs_directory, .mpo_create_devfs_symlink = mac_mls_create_devfs_symlink, .mpo_create_mount = mac_mls_create_mount, .mpo_create_root_mount = mac_mls_create_root_mount, .mpo_relabel_vnode = mac_mls_relabel_vnode, .mpo_update_devfsdirent = mac_mls_update_devfsdirent, .mpo_associate_vnode_devfs = mac_mls_associate_vnode_devfs, .mpo_associate_vnode_extattr = mac_mls_associate_vnode_extattr, .mpo_associate_vnode_singlelabel = mac_mls_associate_vnode_singlelabel, .mpo_create_vnode_extattr = mac_mls_create_vnode_extattr, .mpo_setlabel_vnode_extattr = mac_mls_setlabel_vnode_extattr, .mpo_create_mbuf_from_socket = mac_mls_create_mbuf_from_socket, .mpo_create_pipe = mac_mls_create_pipe, .mpo_create_socket = mac_mls_create_socket, .mpo_create_socket_from_socket = mac_mls_create_socket_from_socket, .mpo_relabel_pipe = mac_mls_relabel_pipe, .mpo_relabel_socket = mac_mls_relabel_socket, .mpo_set_socket_peer_from_mbuf = mac_mls_set_socket_peer_from_mbuf, .mpo_set_socket_peer_from_socket = mac_mls_set_socket_peer_from_socket, .mpo_create_bpfdesc = mac_mls_create_bpfdesc, .mpo_create_datagram_from_ipq = mac_mls_create_datagram_from_ipq, .mpo_create_fragment = mac_mls_create_fragment, .mpo_create_ifnet = mac_mls_create_ifnet, .mpo_create_inpcb_from_socket = mac_mls_create_inpcb_from_socket, .mpo_create_ipq = mac_mls_create_ipq, .mpo_create_mbuf_from_inpcb = mac_mls_create_mbuf_from_inpcb, .mpo_create_mbuf_from_mbuf = mac_mls_create_mbuf_from_mbuf, .mpo_create_mbuf_linklayer = mac_mls_create_mbuf_linklayer, .mpo_create_mbuf_from_bpfdesc = mac_mls_create_mbuf_from_bpfdesc, .mpo_create_mbuf_from_ifnet = mac_mls_create_mbuf_from_ifnet, .mpo_create_mbuf_multicast_encap = mac_mls_create_mbuf_multicast_encap, .mpo_create_mbuf_netlayer = mac_mls_create_mbuf_netlayer, .mpo_fragment_match = mac_mls_fragment_match, .mpo_relabel_ifnet = mac_mls_relabel_ifnet, .mpo_update_ipq = mac_mls_update_ipq, .mpo_inpcb_sosetlabel = mac_mls_inpcb_sosetlabel, .mpo_create_proc0 = mac_mls_create_proc0, .mpo_create_proc1 = mac_mls_create_proc1, .mpo_relabel_cred = mac_mls_relabel_cred, .mpo_check_bpfdesc_receive = mac_mls_check_bpfdesc_receive, .mpo_check_cred_relabel = mac_mls_check_cred_relabel, .mpo_check_cred_visible = mac_mls_check_cred_visible, .mpo_check_ifnet_relabel = mac_mls_check_ifnet_relabel, .mpo_check_ifnet_transmit = mac_mls_check_ifnet_transmit, .mpo_check_inpcb_deliver = mac_mls_check_inpcb_deliver, .mpo_check_mount_stat = mac_mls_check_mount_stat, .mpo_check_pipe_ioctl = mac_mls_check_pipe_ioctl, .mpo_check_pipe_poll = mac_mls_check_pipe_poll, .mpo_check_pipe_read = mac_mls_check_pipe_read, .mpo_check_pipe_relabel = mac_mls_check_pipe_relabel, .mpo_check_pipe_stat = mac_mls_check_pipe_stat, .mpo_check_pipe_write = mac_mls_check_pipe_write, .mpo_check_proc_debug = mac_mls_check_proc_debug, .mpo_check_proc_sched = mac_mls_check_proc_sched, .mpo_check_proc_signal = mac_mls_check_proc_signal, .mpo_check_socket_deliver = mac_mls_check_socket_deliver, .mpo_check_socket_relabel = mac_mls_check_socket_relabel, .mpo_check_socket_visible = mac_mls_check_socket_visible, .mpo_check_system_swapon = mac_mls_check_system_swapon, .mpo_check_vnode_access = mac_mls_check_vnode_open, .mpo_check_vnode_chdir = mac_mls_check_vnode_chdir, .mpo_check_vnode_chroot = mac_mls_check_vnode_chroot, .mpo_check_vnode_create = mac_mls_check_vnode_create, .mpo_check_vnode_delete = mac_mls_check_vnode_delete, .mpo_check_vnode_deleteacl = mac_mls_check_vnode_deleteacl, .mpo_check_vnode_deleteextattr = mac_mls_check_vnode_deleteextattr, .mpo_check_vnode_exec = mac_mls_check_vnode_exec, .mpo_check_vnode_getacl = mac_mls_check_vnode_getacl, .mpo_check_vnode_getextattr = mac_mls_check_vnode_getextattr, .mpo_check_vnode_link = mac_mls_check_vnode_link, .mpo_check_vnode_listextattr = mac_mls_check_vnode_listextattr, .mpo_check_vnode_lookup = mac_mls_check_vnode_lookup, .mpo_check_vnode_mmap = mac_mls_check_vnode_mmap, .mpo_check_vnode_mprotect = mac_mls_check_vnode_mmap, .mpo_check_vnode_open = mac_mls_check_vnode_open, .mpo_check_vnode_poll = mac_mls_check_vnode_poll, .mpo_check_vnode_read = mac_mls_check_vnode_read, .mpo_check_vnode_readdir = mac_mls_check_vnode_readdir, .mpo_check_vnode_readlink = mac_mls_check_vnode_readlink, .mpo_check_vnode_relabel = mac_mls_check_vnode_relabel, .mpo_check_vnode_rename_from = mac_mls_check_vnode_rename_from, .mpo_check_vnode_rename_to = mac_mls_check_vnode_rename_to, .mpo_check_vnode_revoke = mac_mls_check_vnode_revoke, .mpo_check_vnode_setacl = mac_mls_check_vnode_setacl, .mpo_check_vnode_setextattr = mac_mls_check_vnode_setextattr, .mpo_check_vnode_setflags = mac_mls_check_vnode_setflags, .mpo_check_vnode_setmode = mac_mls_check_vnode_setmode, .mpo_check_vnode_setowner = mac_mls_check_vnode_setowner, .mpo_check_vnode_setutimes = mac_mls_check_vnode_setutimes, .mpo_check_vnode_stat = mac_mls_check_vnode_stat, .mpo_check_vnode_write = mac_mls_check_vnode_write, }; MAC_POLICY_SET(&mac_mls_ops, mac_mls, "TrustedBSD MAC/MLS", MPC_LOADTIME_FLAG_NOTLATE | MPC_LOADTIME_FLAG_LABELMBUFS, &mac_mls_slot); Index: head/sys/security/mac_test/mac_test.c =================================================================== --- head/sys/security/mac_test/mac_test.c (revision 125292) +++ head/sys/security/mac_test/mac_test.c (revision 125293) @@ -1,2025 +1,2025 @@ /*- * Copyright (c) 1999, 2000, 2001, 2002 Robert N. M. Watson * Copyright (c) 2001, 2002, 2003 Networks Associates Technology, Inc. * All rights reserved. * * This software was developed by Robert Watson for the TrustedBSD Project. * * This software was developed for the FreeBSD Project in part by Network * Associates Laboratories, the Security Research Division of Network * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), * as part of the DARPA CHATS research program. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ /* * Developed by the TrustedBSD Project. * Generic mandatory access module that does nothing. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include SYSCTL_DECL(_security_mac); SYSCTL_NODE(_security_mac, OID_AUTO, test, CTLFLAG_RW, 0, "TrustedBSD mac_test policy controls"); static int mac_test_enabled = 1; SYSCTL_INT(_security_mac_test, OID_AUTO, enabled, CTLFLAG_RW, &mac_test_enabled, 0, "Enforce test policy"); #define BPFMAGIC 0xfe1ad1b6 #define DEVFSMAGIC 0x9ee79c32 #define IFNETMAGIC 0xc218b120 #define INPCBMAGIC 0x4440f7bb #define IPQMAGIC 0x206188ef #define MBUFMAGIC 0xbbefa5bb #define MOUNTMAGIC 0xc7c46e47 #define SOCKETMAGIC 0x9199c6cd #define PIPEMAGIC 0xdc6c9919 #define PROCMAGIC 0x3b4be98f #define CREDMAGIC 0x9a5a4987 #define VNODEMAGIC 0x1a67a45c #define EXMAGIC 0x849ba1fd #define SLOT(x) LABEL_TO_SLOT((x), test_slot).l_long #define ASSERT_BPF_LABEL(x) KASSERT(SLOT(x) == BPFMAGIC || \ SLOT(x) == 0, ("%s: Bad BPF label", __func__ )) #define ASSERT_DEVFS_LABEL(x) KASSERT(SLOT(x) == DEVFSMAGIC || \ SLOT(x) == 0, ("%s: Bad DEVFS label", __func__ )) #define ASSERT_IFNET_LABEL(x) KASSERT(SLOT(x) == IFNETMAGIC || \ SLOT(x) == 0, ("%s: Bad IFNET label", __func__ )) #define ASSERT_INPCB_LABEL(x) KASSERT(SLOT(x) == INPCBMAGIC || \ SLOT(x) == 0, ("%s: Bad INPCB label", __func__ )) #define ASSERT_IPQ_LABEL(x) KASSERT(SLOT(x) == IPQMAGIC || \ SLOT(x) == 0, ("%s: Bad IPQ label", __func__ )) #define ASSERT_MBUF_LABEL(x) KASSERT(SLOT(x) == MBUFMAGIC || \ SLOT(x) == 0, ("%s: Bad MBUF label", __func__ )) #define ASSERT_MOUNT_LABEL(x) KASSERT(SLOT(x) == MOUNTMAGIC || \ SLOT(x) == 0, ("%s: Bad MOUNT label", __func__ )) #define ASSERT_SOCKET_LABEL(x) KASSERT(SLOT(x) == SOCKETMAGIC || \ SLOT(x) == 0, ("%s: Bad SOCKET label", __func__ )) #define ASSERT_PIPE_LABEL(x) KASSERT(SLOT(x) == PIPEMAGIC || \ SLOT(x) == 0, ("%s: Bad PIPE label", __func__ )) #define ASSERT_PROC_LABEL(x) KASSERT(SLOT(x) == PROCMAGIC || \ SLOT(x) == 0, ("%s: Bad PROC label", __func__ )) #define ASSERT_CRED_LABEL(x) KASSERT(SLOT(x) == CREDMAGIC || \ SLOT(x) == 0, ("%s: Bad CRED label", __func__ )) #define ASSERT_VNODE_LABEL(x) KASSERT(SLOT(x) == VNODEMAGIC || \ SLOT(x) == 0, ("%s: Bad VNODE label", __func__ )) static int test_slot; SYSCTL_INT(_security_mac_test, OID_AUTO, slot, CTLFLAG_RD, &test_slot, 0, "Slot allocated by framework"); static int init_count_bpfdesc; SYSCTL_INT(_security_mac_test, OID_AUTO, init_count_bpfdesc, CTLFLAG_RD, &init_count_bpfdesc, 0, "bpfdesc init calls"); static int init_count_cred; SYSCTL_INT(_security_mac_test, OID_AUTO, init_count_cred, CTLFLAG_RD, &init_count_cred, 0, "cred init calls"); static int init_count_devfsdirent; SYSCTL_INT(_security_mac_test, OID_AUTO, init_count_devfsdirent, CTLFLAG_RD, &init_count_devfsdirent, 0, "devfsdirent init calls"); static int init_count_ifnet; SYSCTL_INT(_security_mac_test, OID_AUTO, init_count_ifnet, CTLFLAG_RD, &init_count_ifnet, 0, "ifnet init calls"); static int init_count_inpcb; SYSCTL_INT(_security_mac_test, OID_AUTO, init_count_inpcb, CTLFLAG_RD, &init_count_inpcb, 0, "inpcb init calls"); static int init_count_ipq; SYSCTL_INT(_security_mac_test, OID_AUTO, init_count_ipq, CTLFLAG_RD, &init_count_ipq, 0, "ipq init calls"); static int init_count_mbuf; SYSCTL_INT(_security_mac_test, OID_AUTO, init_count_mbuf, CTLFLAG_RD, &init_count_mbuf, 0, "mbuf init calls"); static int init_count_mount; SYSCTL_INT(_security_mac_test, OID_AUTO, init_count_mount, CTLFLAG_RD, &init_count_mount, 0, "mount init calls"); static int init_count_mount_fslabel; SYSCTL_INT(_security_mac_test, OID_AUTO, init_count_mount_fslabel, CTLFLAG_RD, &init_count_mount_fslabel, 0, "mount_fslabel init calls"); static int init_count_socket; SYSCTL_INT(_security_mac_test, OID_AUTO, init_count_socket, CTLFLAG_RD, &init_count_socket, 0, "socket init calls"); static int init_count_socket_peerlabel; SYSCTL_INT(_security_mac_test, OID_AUTO, init_count_socket_peerlabel, CTLFLAG_RD, &init_count_socket_peerlabel, 0, "socket_peerlabel init calls"); static int init_count_pipe; SYSCTL_INT(_security_mac_test, OID_AUTO, init_count_pipe, CTLFLAG_RD, &init_count_pipe, 0, "pipe init calls"); static int init_count_proc; SYSCTL_INT(_security_mac_test, OID_AUTO, init_count_proc, CTLFLAG_RD, &init_count_proc, 0, "proc init calls"); static int init_count_vnode; SYSCTL_INT(_security_mac_test, OID_AUTO, init_count_vnode, CTLFLAG_RD, &init_count_vnode, 0, "vnode init calls"); static int destroy_count_bpfdesc; SYSCTL_INT(_security_mac_test, OID_AUTO, destroy_count_bpfdesc, CTLFLAG_RD, &destroy_count_bpfdesc, 0, "bpfdesc destroy calls"); static int destroy_count_cred; SYSCTL_INT(_security_mac_test, OID_AUTO, destroy_count_cred, CTLFLAG_RD, &destroy_count_cred, 0, "cred destroy calls"); static int destroy_count_devfsdirent; SYSCTL_INT(_security_mac_test, OID_AUTO, destroy_count_devfsdirent, CTLFLAG_RD, &destroy_count_devfsdirent, 0, "devfsdirent destroy calls"); static int destroy_count_ifnet; SYSCTL_INT(_security_mac_test, OID_AUTO, destroy_count_ifnet, CTLFLAG_RD, &destroy_count_ifnet, 0, "ifnet destroy calls"); static int destroy_count_inpcb; SYSCTL_INT(_security_mac_test, OID_AUTO, destroy_count_inpcb, CTLFLAG_RD, &destroy_count_inpcb, 0, "inpcb destroy calls"); static int destroy_count_ipq; SYSCTL_INT(_security_mac_test, OID_AUTO, destroy_count_ipq, CTLFLAG_RD, &destroy_count_ipq, 0, "ipq destroy calls"); static int destroy_count_mbuf; SYSCTL_INT(_security_mac_test, OID_AUTO, destroy_count_mbuf, CTLFLAG_RD, &destroy_count_mbuf, 0, "mbuf destroy calls"); static int destroy_count_mount; SYSCTL_INT(_security_mac_test, OID_AUTO, destroy_count_mount, CTLFLAG_RD, &destroy_count_mount, 0, "mount destroy calls"); static int destroy_count_mount_fslabel; SYSCTL_INT(_security_mac_test, OID_AUTO, destroy_count_mount_fslabel, CTLFLAG_RD, &destroy_count_mount_fslabel, 0, "mount_fslabel destroy calls"); static int destroy_count_socket; SYSCTL_INT(_security_mac_test, OID_AUTO, destroy_count_socket, CTLFLAG_RD, &destroy_count_socket, 0, "socket destroy calls"); static int destroy_count_socket_peerlabel; SYSCTL_INT(_security_mac_test, OID_AUTO, destroy_count_socket_peerlabel, CTLFLAG_RD, &destroy_count_socket_peerlabel, 0, "socket_peerlabel destroy calls"); static int destroy_count_pipe; SYSCTL_INT(_security_mac_test, OID_AUTO, destroy_count_pipe, CTLFLAG_RD, &destroy_count_pipe, 0, "pipe destroy calls"); static int destroy_count_proc; SYSCTL_INT(_security_mac_test, OID_AUTO, destroy_count_proc, CTLFLAG_RD, &destroy_count_proc, 0, "proc destroy calls"); static int destroy_count_vnode; SYSCTL_INT(_security_mac_test, OID_AUTO, destroy_count_vnode, CTLFLAG_RD, &destroy_count_vnode, 0, "vnode destroy calls"); static int externalize_count; SYSCTL_INT(_security_mac_test, OID_AUTO, externalize_count, CTLFLAG_RD, &externalize_count, 0, "Subject/object externalize calls"); static int internalize_count; SYSCTL_INT(_security_mac_test, OID_AUTO, internalize_count, CTLFLAG_RD, &internalize_count, 0, "Subject/object internalize calls"); /* * Policy module operations. */ static void mac_test_destroy(struct mac_policy_conf *conf) { } static void mac_test_init(struct mac_policy_conf *conf) { } static int mac_test_syscall(struct thread *td, int call, void *arg) { return (0); } /* * Label operations. */ static void mac_test_init_bpfdesc_label(struct label *label) { SLOT(label) = BPFMAGIC; atomic_add_int(&init_count_bpfdesc, 1); } static void mac_test_init_cred_label(struct label *label) { SLOT(label) = CREDMAGIC; atomic_add_int(&init_count_cred, 1); } static void mac_test_init_devfsdirent_label(struct label *label) { SLOT(label) = DEVFSMAGIC; atomic_add_int(&init_count_devfsdirent, 1); } static void mac_test_init_ifnet_label(struct label *label) { SLOT(label) = IFNETMAGIC; atomic_add_int(&init_count_ifnet, 1); } static int mac_test_init_inpcb_label(struct label *label, int flag) { if (flag & M_WAITOK) WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, "mac_test_init_inpcb_label() at %s:%d", __FILE__, __LINE__); SLOT(label) = INPCBMAGIC; atomic_add_int(&init_count_inpcb, 1); return (0); } static int mac_test_init_ipq_label(struct label *label, int flag) { if (flag & M_WAITOK) WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, "mac_test_init_ipq_label() at %s:%d", __FILE__, __LINE__); SLOT(label) = IPQMAGIC; atomic_add_int(&init_count_ipq, 1); return (0); } static int mac_test_init_mbuf_label(struct label *label, int flag) { if (flag & M_WAITOK) WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, "mac_test_init_mbuf_label() at %s:%d", __FILE__, __LINE__); SLOT(label) = MBUFMAGIC; atomic_add_int(&init_count_mbuf, 1); return (0); } static void mac_test_init_mount_label(struct label *label) { SLOT(label) = MOUNTMAGIC; atomic_add_int(&init_count_mount, 1); } static void mac_test_init_mount_fs_label(struct label *label) { SLOT(label) = MOUNTMAGIC; atomic_add_int(&init_count_mount_fslabel, 1); } static int mac_test_init_socket_label(struct label *label, int flag) { if (flag & M_WAITOK) WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, "mac_test_init_socket_label() at %s:%d", __FILE__, __LINE__); SLOT(label) = SOCKETMAGIC; atomic_add_int(&init_count_socket, 1); return (0); } static int mac_test_init_socket_peer_label(struct label *label, int flag) { if (flag & M_WAITOK) WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, "mac_test_init_socket_peer_label() at %s:%d", __FILE__, __LINE__); SLOT(label) = SOCKETMAGIC; atomic_add_int(&init_count_socket_peerlabel, 1); return (0); } static void mac_test_init_pipe_label(struct label *label) { SLOT(label) = PIPEMAGIC; atomic_add_int(&init_count_pipe, 1); } static void mac_test_init_proc_label(struct label *label) { SLOT(label) = PROCMAGIC; atomic_add_int(&init_count_proc, 1); } static void mac_test_init_vnode_label(struct label *label) { SLOT(label) = VNODEMAGIC; atomic_add_int(&init_count_vnode, 1); } static void mac_test_destroy_bpfdesc_label(struct label *label) { if (SLOT(label) == BPFMAGIC || SLOT(label) == 0) { atomic_add_int(&destroy_count_bpfdesc, 1); SLOT(label) = EXMAGIC; } else if (SLOT(label) == EXMAGIC) { Debugger("mac_test_destroy_bpfdesc: dup destroy"); } else { Debugger("mac_test_destroy_bpfdesc: corrupted label"); } } static void mac_test_destroy_cred_label(struct label *label) { if (SLOT(label) == CREDMAGIC || SLOT(label) == 0) { atomic_add_int(&destroy_count_cred, 1); SLOT(label) = EXMAGIC; } else if (SLOT(label) == EXMAGIC) { Debugger("mac_test_destroy_cred: dup destroy"); } else { Debugger("mac_test_destroy_cred: corrupted label"); } } static void mac_test_destroy_devfsdirent_label(struct label *label) { if (SLOT(label) == DEVFSMAGIC || SLOT(label) == 0) { atomic_add_int(&destroy_count_devfsdirent, 1); SLOT(label) = EXMAGIC; } else if (SLOT(label) == EXMAGIC) { Debugger("mac_test_destroy_devfsdirent: dup destroy"); } else { Debugger("mac_test_destroy_devfsdirent: corrupted label"); } } static void mac_test_destroy_ifnet_label(struct label *label) { if (SLOT(label) == IFNETMAGIC || SLOT(label) == 0) { atomic_add_int(&destroy_count_ifnet, 1); SLOT(label) = EXMAGIC; } else if (SLOT(label) == EXMAGIC) { Debugger("mac_test_destroy_ifnet: dup destroy"); } else { Debugger("mac_test_destroy_ifnet: corrupted label"); } } static void mac_test_destroy_inpcb_label(struct label *label) { if (SLOT(label) == INPCBMAGIC || SLOT(label) == 0) { atomic_add_int(&destroy_count_inpcb, 1); SLOT(label) = EXMAGIC; } else if (SLOT(label) == EXMAGIC) { Debugger("mac_test_destroy_inpcb: dup destroy"); } else { Debugger("mac_test_destroy_inpcb: corrupted label"); } } static void mac_test_destroy_ipq_label(struct label *label) { if (SLOT(label) == IPQMAGIC || SLOT(label) == 0) { atomic_add_int(&destroy_count_ipq, 1); SLOT(label) = EXMAGIC; } else if (SLOT(label) == EXMAGIC) { Debugger("mac_test_destroy_ipq: dup destroy"); } else { Debugger("mac_test_destroy_ipq: corrupted label"); } } static void mac_test_destroy_mbuf_label(struct label *label) { /* * If we're loaded dynamically, there may be mbufs in flight that * didn't have label storage allocated for them. Handle this * gracefully. */ if (label == NULL) return; if (SLOT(label) == MBUFMAGIC || SLOT(label) == 0) { atomic_add_int(&destroy_count_mbuf, 1); SLOT(label) = EXMAGIC; } else if (SLOT(label) == EXMAGIC) { Debugger("mac_test_destroy_mbuf: dup destroy"); } else { Debugger("mac_test_destroy_mbuf: corrupted label"); } } static void mac_test_destroy_mount_label(struct label *label) { if ((SLOT(label) == MOUNTMAGIC || SLOT(label) == 0)) { atomic_add_int(&destroy_count_mount, 1); SLOT(label) = EXMAGIC; } else if (SLOT(label) == EXMAGIC) { Debugger("mac_test_destroy_mount: dup destroy"); } else { Debugger("mac_test_destroy_mount: corrupted label"); } } static void mac_test_destroy_mount_fs_label(struct label *label) { if ((SLOT(label) == MOUNTMAGIC || SLOT(label) == 0)) { atomic_add_int(&destroy_count_mount_fslabel, 1); SLOT(label) = EXMAGIC; } else if (SLOT(label) == EXMAGIC) { Debugger("mac_test_destroy_mount_fslabel: dup destroy"); } else { Debugger("mac_test_destroy_mount_fslabel: corrupted label"); } } static void mac_test_destroy_socket_label(struct label *label) { if ((SLOT(label) == SOCKETMAGIC || SLOT(label) == 0)) { atomic_add_int(&destroy_count_socket, 1); SLOT(label) = EXMAGIC; } else if (SLOT(label) == EXMAGIC) { Debugger("mac_test_destroy_socket: dup destroy"); } else { Debugger("mac_test_destroy_socket: corrupted label"); } } static void mac_test_destroy_socket_peer_label(struct label *label) { if ((SLOT(label) == SOCKETMAGIC || SLOT(label) == 0)) { atomic_add_int(&destroy_count_socket_peerlabel, 1); SLOT(label) = EXMAGIC; } else if (SLOT(label) == EXMAGIC) { Debugger("mac_test_destroy_socket_peerlabel: dup destroy"); } else { Debugger("mac_test_destroy_socket_peerlabel: corrupted label"); } } static void mac_test_destroy_pipe_label(struct label *label) { if ((SLOT(label) == PIPEMAGIC || SLOT(label) == 0)) { atomic_add_int(&destroy_count_pipe, 1); SLOT(label) = EXMAGIC; } else if (SLOT(label) == EXMAGIC) { Debugger("mac_test_destroy_pipe: dup destroy"); } else { Debugger("mac_test_destroy_pipe: corrupted label"); } } static void mac_test_destroy_proc_label(struct label *label) { if ((SLOT(label) == PROCMAGIC || SLOT(label) == 0)) { atomic_add_int(&destroy_count_proc, 1); SLOT(label) = EXMAGIC; } else if (SLOT(label) == EXMAGIC) { Debugger("mac_test_destroy_proc: dup destroy"); } else { Debugger("mac_test_destroy_proc: corrupted label"); } } static void mac_test_destroy_vnode_label(struct label *label) { if (SLOT(label) == VNODEMAGIC || SLOT(label) == 0) { atomic_add_int(&destroy_count_vnode, 1); SLOT(label) = EXMAGIC; } else if (SLOT(label) == EXMAGIC) { Debugger("mac_test_destroy_vnode: dup destroy"); } else { Debugger("mac_test_destroy_vnode: corrupted label"); } } static void mac_test_copy_cred_label(struct label *src, struct label *dest) { ASSERT_CRED_LABEL(src); ASSERT_CRED_LABEL(dest); } static void mac_test_copy_mbuf_label(struct label *src, struct label *dest) { ASSERT_MBUF_LABEL(src); ASSERT_MBUF_LABEL(dest); } static void mac_test_copy_pipe_label(struct label *src, struct label *dest) { ASSERT_PIPE_LABEL(src); ASSERT_PIPE_LABEL(dest); } static void mac_test_copy_socket_label(struct label *src, struct label *dest) { ASSERT_SOCKET_LABEL(src); ASSERT_SOCKET_LABEL(dest); } static void mac_test_copy_vnode_label(struct label *src, struct label *dest) { ASSERT_VNODE_LABEL(src); ASSERT_VNODE_LABEL(dest); } static int mac_test_externalize_label(struct label *label, char *element_name, struct sbuf *sb, int *claimed) { atomic_add_int(&externalize_count, 1); KASSERT(SLOT(label) != EXMAGIC, ("mac_test_externalize_label: destroyed label")); return (0); } static int mac_test_internalize_label(struct label *label, char *element_name, char *element_data, int *claimed) { atomic_add_int(&internalize_count, 1); KASSERT(SLOT(label) != EXMAGIC, ("mac_test_internalize_label: destroyed label")); return (0); } /* * Labeling event operations: file system objects, and things that look * a lot like file system objects. */ static void mac_test_associate_vnode_devfs(struct mount *mp, struct label *fslabel, struct devfs_dirent *de, struct label *delabel, struct vnode *vp, struct label *vlabel) { ASSERT_MOUNT_LABEL(fslabel); ASSERT_DEVFS_LABEL(delabel); ASSERT_VNODE_LABEL(vlabel); } static int mac_test_associate_vnode_extattr(struct mount *mp, struct label *fslabel, struct vnode *vp, struct label *vlabel) { ASSERT_MOUNT_LABEL(fslabel); ASSERT_VNODE_LABEL(vlabel); return (0); } static void mac_test_associate_vnode_singlelabel(struct mount *mp, struct label *fslabel, struct vnode *vp, struct label *vlabel) { ASSERT_MOUNT_LABEL(fslabel); ASSERT_VNODE_LABEL(vlabel); } static void mac_test_create_devfs_device(struct mount *mp, dev_t dev, struct devfs_dirent *devfs_dirent, struct label *label) { ASSERT_DEVFS_LABEL(label); } static void mac_test_create_devfs_directory(struct mount *mp, char *dirname, int dirnamelen, struct devfs_dirent *devfs_dirent, struct label *label) { ASSERT_DEVFS_LABEL(label); } static void mac_test_create_devfs_symlink(struct ucred *cred, struct mount *mp, struct devfs_dirent *dd, struct label *ddlabel, struct devfs_dirent *de, struct label *delabel) { ASSERT_CRED_LABEL(cred->cr_label); ASSERT_DEVFS_LABEL(ddlabel); ASSERT_DEVFS_LABEL(delabel); } static int mac_test_create_vnode_extattr(struct ucred *cred, struct mount *mp, struct label *fslabel, struct vnode *dvp, struct label *dlabel, struct vnode *vp, struct label *vlabel, struct componentname *cnp) { ASSERT_CRED_LABEL(cred->cr_label); ASSERT_MOUNT_LABEL(fslabel); ASSERT_VNODE_LABEL(dlabel); return (0); } static void mac_test_create_mount(struct ucred *cred, struct mount *mp, struct label *mntlabel, struct label *fslabel) { ASSERT_CRED_LABEL(cred->cr_label); ASSERT_MOUNT_LABEL(mntlabel); ASSERT_MOUNT_LABEL(fslabel); } static void mac_test_create_root_mount(struct ucred *cred, struct mount *mp, struct label *mntlabel, struct label *fslabel) { ASSERT_CRED_LABEL(cred->cr_label); ASSERT_MOUNT_LABEL(mntlabel); ASSERT_MOUNT_LABEL(fslabel); } static void mac_test_relabel_vnode(struct ucred *cred, struct vnode *vp, struct label *vnodelabel, struct label *label) { ASSERT_CRED_LABEL(cred->cr_label); ASSERT_VNODE_LABEL(vnodelabel); ASSERT_VNODE_LABEL(label); } static int mac_test_setlabel_vnode_extattr(struct ucred *cred, struct vnode *vp, struct label *vlabel, struct label *intlabel) { ASSERT_CRED_LABEL(cred->cr_label); ASSERT_VNODE_LABEL(vlabel); ASSERT_VNODE_LABEL(intlabel); return (0); } static void mac_test_update_devfsdirent(struct mount *mp, struct devfs_dirent *devfs_dirent, struct label *direntlabel, struct vnode *vp, struct label *vnodelabel) { ASSERT_DEVFS_LABEL(direntlabel); ASSERT_VNODE_LABEL(vnodelabel); } /* * Labeling event operations: IPC object. */ static void mac_test_create_mbuf_from_socket(struct socket *so, struct label *socketlabel, struct mbuf *m, struct label *mbuflabel) { ASSERT_SOCKET_LABEL(socketlabel); ASSERT_MBUF_LABEL(mbuflabel); } static void mac_test_create_socket(struct ucred *cred, struct socket *socket, struct label *socketlabel) { ASSERT_CRED_LABEL(cred->cr_label); ASSERT_SOCKET_LABEL(socketlabel); } static void -mac_test_create_pipe(struct ucred *cred, struct pipe *pipe, +mac_test_create_pipe(struct ucred *cred, struct pipepair *pp, struct label *pipelabel) { ASSERT_CRED_LABEL(cred->cr_label); ASSERT_PIPE_LABEL(pipelabel); } static void mac_test_create_socket_from_socket(struct socket *oldsocket, struct label *oldsocketlabel, struct socket *newsocket, struct label *newsocketlabel) { ASSERT_SOCKET_LABEL(oldsocketlabel); ASSERT_SOCKET_LABEL(newsocketlabel); } static void mac_test_relabel_socket(struct ucred *cred, struct socket *socket, struct label *socketlabel, struct label *newlabel) { ASSERT_CRED_LABEL(cred->cr_label); ASSERT_SOCKET_LABEL(newlabel); } static void -mac_test_relabel_pipe(struct ucred *cred, struct pipe *pipe, +mac_test_relabel_pipe(struct ucred *cred, struct pipepair *pp, struct label *pipelabel, struct label *newlabel) { ASSERT_CRED_LABEL(cred->cr_label); ASSERT_PIPE_LABEL(pipelabel); ASSERT_PIPE_LABEL(newlabel); } static void mac_test_set_socket_peer_from_mbuf(struct mbuf *mbuf, struct label *mbuflabel, struct socket *socket, struct label *socketpeerlabel) { ASSERT_MBUF_LABEL(mbuflabel); ASSERT_SOCKET_LABEL(socketpeerlabel); } /* * Labeling event operations: network objects. */ static void mac_test_set_socket_peer_from_socket(struct socket *oldsocket, struct label *oldsocketlabel, struct socket *newsocket, struct label *newsocketpeerlabel) { ASSERT_SOCKET_LABEL(oldsocketlabel); ASSERT_SOCKET_LABEL(newsocketpeerlabel); } static void mac_test_create_bpfdesc(struct ucred *cred, struct bpf_d *bpf_d, struct label *bpflabel) { ASSERT_CRED_LABEL(cred->cr_label); ASSERT_BPF_LABEL(bpflabel); } static void mac_test_create_datagram_from_ipq(struct ipq *ipq, struct label *ipqlabel, struct mbuf *datagram, struct label *datagramlabel) { ASSERT_IPQ_LABEL(ipqlabel); ASSERT_MBUF_LABEL(datagramlabel); } static void mac_test_create_fragment(struct mbuf *datagram, struct label *datagramlabel, struct mbuf *fragment, struct label *fragmentlabel) { ASSERT_MBUF_LABEL(datagramlabel); ASSERT_MBUF_LABEL(fragmentlabel); } static void mac_test_create_ifnet(struct ifnet *ifnet, struct label *ifnetlabel) { ASSERT_IFNET_LABEL(ifnetlabel); } static void mac_test_create_inpcb_from_socket(struct socket *so, struct label *solabel, struct inpcb *inp, struct label *inplabel) { ASSERT_SOCKET_LABEL(solabel); ASSERT_INPCB_LABEL(inplabel); } static void mac_test_create_ipq(struct mbuf *fragment, struct label *fragmentlabel, struct ipq *ipq, struct label *ipqlabel) { ASSERT_MBUF_LABEL(fragmentlabel); ASSERT_IPQ_LABEL(ipqlabel); } static void mac_test_create_mbuf_from_inpcb(struct inpcb *inp, struct label *inplabel, struct mbuf *m, struct label *mlabel) { ASSERT_INPCB_LABEL(inplabel); ASSERT_MBUF_LABEL(mlabel); } static void mac_test_create_mbuf_from_mbuf(struct mbuf *oldmbuf, struct label *oldmbuflabel, struct mbuf *newmbuf, struct label *newmbuflabel) { ASSERT_MBUF_LABEL(oldmbuflabel); ASSERT_MBUF_LABEL(newmbuflabel); } static void mac_test_create_mbuf_linklayer(struct ifnet *ifnet, struct label *ifnetlabel, struct mbuf *mbuf, struct label *mbuflabel) { ASSERT_IFNET_LABEL(ifnetlabel); ASSERT_MBUF_LABEL(mbuflabel); } static void mac_test_create_mbuf_from_bpfdesc(struct bpf_d *bpf_d, struct label *bpflabel, struct mbuf *mbuf, struct label *mbuflabel) { ASSERT_BPF_LABEL(bpflabel); ASSERT_MBUF_LABEL(mbuflabel); } static void mac_test_create_mbuf_from_ifnet(struct ifnet *ifnet, struct label *ifnetlabel, struct mbuf *m, struct label *mbuflabel) { ASSERT_IFNET_LABEL(ifnetlabel); ASSERT_MBUF_LABEL(mbuflabel); } static void mac_test_create_mbuf_multicast_encap(struct mbuf *oldmbuf, struct label *oldmbuflabel, struct ifnet *ifnet, struct label *ifnetlabel, struct mbuf *newmbuf, struct label *newmbuflabel) { ASSERT_MBUF_LABEL(oldmbuflabel); ASSERT_IFNET_LABEL(ifnetlabel); ASSERT_MBUF_LABEL(newmbuflabel); } static void mac_test_create_mbuf_netlayer(struct mbuf *oldmbuf, struct label *oldmbuflabel, struct mbuf *newmbuf, struct label *newmbuflabel) { ASSERT_MBUF_LABEL(oldmbuflabel); ASSERT_MBUF_LABEL(newmbuflabel); } static int mac_test_fragment_match(struct mbuf *fragment, struct label *fragmentlabel, struct ipq *ipq, struct label *ipqlabel) { ASSERT_MBUF_LABEL(fragmentlabel); ASSERT_IPQ_LABEL(ipqlabel); return (1); } static void mac_test_reflect_mbuf_icmp(struct mbuf *m, struct label *mlabel) { ASSERT_MBUF_LABEL(mlabel); } static void mac_test_reflect_mbuf_tcp(struct mbuf *m, struct label *mlabel) { ASSERT_MBUF_LABEL(mlabel); } static void mac_test_relabel_ifnet(struct ucred *cred, struct ifnet *ifnet, struct label *ifnetlabel, struct label *newlabel) { ASSERT_CRED_LABEL(cred->cr_label); ASSERT_IFNET_LABEL(ifnetlabel); ASSERT_IFNET_LABEL(newlabel); } static void mac_test_update_ipq(struct mbuf *fragment, struct label *fragmentlabel, struct ipq *ipq, struct label *ipqlabel) { ASSERT_MBUF_LABEL(fragmentlabel); ASSERT_IPQ_LABEL(ipqlabel); } static void mac_test_inpcb_sosetlabel(struct socket *so, struct label *solabel, struct inpcb *inp, struct label *inplabel) { ASSERT_SOCKET_LABEL(solabel); ASSERT_INPCB_LABEL(inplabel); } /* * Labeling event operations: processes. */ static void mac_test_execve_transition(struct ucred *old, struct ucred *new, struct vnode *vp, struct label *filelabel, struct label *interpvnodelabel, struct image_params *imgp, struct label *execlabel) { ASSERT_CRED_LABEL(old->cr_label); ASSERT_CRED_LABEL(new->cr_label); ASSERT_VNODE_LABEL(filelabel); if (interpvnodelabel != NULL) { ASSERT_VNODE_LABEL(interpvnodelabel); } if (execlabel != NULL) { ASSERT_CRED_LABEL(execlabel); } } static int mac_test_execve_will_transition(struct ucred *old, struct vnode *vp, struct label *filelabel, struct label *interpvnodelabel, struct image_params *imgp, struct label *execlabel) { ASSERT_CRED_LABEL(old->cr_label); ASSERT_VNODE_LABEL(filelabel); if (interpvnodelabel != NULL) { ASSERT_VNODE_LABEL(interpvnodelabel); } if (execlabel != NULL) { ASSERT_CRED_LABEL(execlabel); } return (0); } static void mac_test_create_proc0(struct ucred *cred) { ASSERT_CRED_LABEL(cred->cr_label); } static void mac_test_create_proc1(struct ucred *cred) { ASSERT_CRED_LABEL(cred->cr_label); } static void mac_test_relabel_cred(struct ucred *cred, struct label *newlabel) { ASSERT_CRED_LABEL(cred->cr_label); ASSERT_CRED_LABEL(newlabel); } static void mac_test_thread_userret(struct thread *td) { printf("mac_test_thread_userret(process = %d)\n", curthread->td_proc->p_pid); } /* * Access control checks. */ static int mac_test_check_bpfdesc_receive(struct bpf_d *bpf_d, struct label *bpflabel, struct ifnet *ifnet, struct label *ifnetlabel) { ASSERT_BPF_LABEL(bpflabel); ASSERT_IFNET_LABEL(ifnetlabel); return (0); } static int mac_test_check_cred_relabel(struct ucred *cred, struct label *newlabel) { ASSERT_CRED_LABEL(cred->cr_label); ASSERT_CRED_LABEL(newlabel); return (0); } static int mac_test_check_cred_visible(struct ucred *u1, struct ucred *u2) { ASSERT_CRED_LABEL(u1->cr_label); ASSERT_CRED_LABEL(u2->cr_label); return (0); } static int mac_test_check_ifnet_relabel(struct ucred *cred, struct ifnet *ifnet, struct label *ifnetlabel, struct label *newlabel) { ASSERT_CRED_LABEL(cred->cr_label); ASSERT_IFNET_LABEL(ifnetlabel); ASSERT_IFNET_LABEL(newlabel); return (0); } static int mac_test_check_ifnet_transmit(struct ifnet *ifnet, struct label *ifnetlabel, struct mbuf *m, struct label *mbuflabel) { ASSERT_IFNET_LABEL(ifnetlabel); ASSERT_MBUF_LABEL(mbuflabel); return (0); } static int mac_test_check_inpcb_deliver(struct inpcb *inp, struct label *inplabel, struct mbuf *m, struct label *mlabel) { ASSERT_INPCB_LABEL(inplabel); ASSERT_MBUF_LABEL(mlabel); return (0); } static int mac_test_check_kenv_dump(struct ucred *cred) { ASSERT_CRED_LABEL(cred->cr_label); return (0); } static int mac_test_check_kenv_get(struct ucred *cred, char *name) { ASSERT_CRED_LABEL(cred->cr_label); return (0); } static int mac_test_check_kenv_set(struct ucred *cred, char *name, char *value) { ASSERT_CRED_LABEL(cred->cr_label); return (0); } static int mac_test_check_kenv_unset(struct ucred *cred, char *name) { ASSERT_CRED_LABEL(cred->cr_label); return (0); } static int mac_test_check_kld_load(struct ucred *cred, struct vnode *vp, struct label *label) { ASSERT_CRED_LABEL(cred->cr_label); ASSERT_VNODE_LABEL(label); return (0); } static int mac_test_check_kld_stat(struct ucred *cred) { ASSERT_CRED_LABEL(cred->cr_label); return (0); } static int mac_test_check_kld_unload(struct ucred *cred) { ASSERT_CRED_LABEL(cred->cr_label); return (0); } static int mac_test_check_mount_stat(struct ucred *cred, struct mount *mp, struct label *mntlabel) { ASSERT_CRED_LABEL(cred->cr_label); ASSERT_MOUNT_LABEL(mntlabel); return (0); } static int -mac_test_check_pipe_ioctl(struct ucred *cred, struct pipe *pipe, +mac_test_check_pipe_ioctl(struct ucred *cred, struct pipepair *pp, struct label *pipelabel, unsigned long cmd, void /* caddr_t */ *data) { ASSERT_CRED_LABEL(cred->cr_label); ASSERT_PIPE_LABEL(pipelabel); return (0); } static int -mac_test_check_pipe_poll(struct ucred *cred, struct pipe *pipe, +mac_test_check_pipe_poll(struct ucred *cred, struct pipepair *pp, struct label *pipelabel) { ASSERT_CRED_LABEL(cred->cr_label); ASSERT_PIPE_LABEL(pipelabel); return (0); } static int -mac_test_check_pipe_read(struct ucred *cred, struct pipe *pipe, +mac_test_check_pipe_read(struct ucred *cred, struct pipepair *pp, struct label *pipelabel) { ASSERT_CRED_LABEL(cred->cr_label); ASSERT_PIPE_LABEL(pipelabel); return (0); } static int -mac_test_check_pipe_relabel(struct ucred *cred, struct pipe *pipe, +mac_test_check_pipe_relabel(struct ucred *cred, struct pipepair *pp, struct label *pipelabel, struct label *newlabel) { ASSERT_CRED_LABEL(cred->cr_label); ASSERT_PIPE_LABEL(pipelabel); ASSERT_PIPE_LABEL(newlabel); return (0); } static int -mac_test_check_pipe_stat(struct ucred *cred, struct pipe *pipe, +mac_test_check_pipe_stat(struct ucred *cred, struct pipepair *pp, struct label *pipelabel) { ASSERT_CRED_LABEL(cred->cr_label); ASSERT_PIPE_LABEL(pipelabel); return (0); } static int -mac_test_check_pipe_write(struct ucred *cred, struct pipe *pipe, +mac_test_check_pipe_write(struct ucred *cred, struct pipepair *pp, struct label *pipelabel) { ASSERT_CRED_LABEL(cred->cr_label); ASSERT_PIPE_LABEL(pipelabel); return (0); } static int mac_test_check_proc_debug(struct ucred *cred, struct proc *proc) { ASSERT_CRED_LABEL(cred->cr_label); ASSERT_CRED_LABEL(proc->p_ucred->cr_label); return (0); } static int mac_test_check_proc_sched(struct ucred *cred, struct proc *proc) { ASSERT_CRED_LABEL(cred->cr_label); ASSERT_CRED_LABEL(proc->p_ucred->cr_label); return (0); } static int mac_test_check_proc_signal(struct ucred *cred, struct proc *proc, int signum) { ASSERT_CRED_LABEL(cred->cr_label); ASSERT_CRED_LABEL(proc->p_ucred->cr_label); return (0); } static int mac_test_check_socket_bind(struct ucred *cred, struct socket *socket, struct label *socketlabel, struct sockaddr *sockaddr) { ASSERT_CRED_LABEL(cred->cr_label); ASSERT_SOCKET_LABEL(socketlabel); return (0); } static int mac_test_check_socket_connect(struct ucred *cred, struct socket *socket, struct label *socketlabel, struct sockaddr *sockaddr) { ASSERT_CRED_LABEL(cred->cr_label); ASSERT_SOCKET_LABEL(socketlabel); return (0); } static int mac_test_check_socket_deliver(struct socket *socket, struct label *socketlabel, struct mbuf *m, struct label *mbuflabel) { ASSERT_SOCKET_LABEL(socketlabel); ASSERT_MBUF_LABEL(mbuflabel); return (0); } static int mac_test_check_socket_listen(struct ucred *cred, struct socket *socket, struct label *socketlabel) { ASSERT_CRED_LABEL(cred->cr_label); ASSERT_SOCKET_LABEL(socketlabel); return (0); } static int mac_test_check_socket_visible(struct ucred *cred, struct socket *socket, struct label *socketlabel) { ASSERT_CRED_LABEL(cred->cr_label); ASSERT_SOCKET_LABEL(socketlabel); return (0); } static int mac_test_check_socket_relabel(struct ucred *cred, struct socket *socket, struct label *socketlabel, struct label *newlabel) { ASSERT_CRED_LABEL(cred->cr_label); ASSERT_SOCKET_LABEL(socketlabel); ASSERT_SOCKET_LABEL(newlabel); return (0); } static int mac_test_check_sysarch_ioperm(struct ucred *cred) { ASSERT_CRED_LABEL(cred->cr_label); return (0); } static int mac_test_check_system_acct(struct ucred *cred, struct vnode *vp, struct label *label) { ASSERT_CRED_LABEL(cred->cr_label); return (0); } static int mac_test_check_system_reboot(struct ucred *cred, int how) { ASSERT_CRED_LABEL(cred->cr_label); return (0); } static int mac_test_check_system_settime(struct ucred *cred) { ASSERT_CRED_LABEL(cred->cr_label); return (0); } static int mac_test_check_system_swapon(struct ucred *cred, struct vnode *vp, struct label *label) { ASSERT_CRED_LABEL(cred->cr_label); ASSERT_VNODE_LABEL(label); return (0); } static int mac_test_check_system_swapoff(struct ucred *cred, struct vnode *vp, struct label *label) { ASSERT_CRED_LABEL(cred->cr_label); ASSERT_VNODE_LABEL(label); return (0); } static int mac_test_check_system_sysctl(struct ucred *cred, int *name, u_int namelen, void *old, size_t *oldlenp, int inkernel, void *new, size_t newlen) { ASSERT_CRED_LABEL(cred->cr_label); return (0); } static int mac_test_check_vnode_access(struct ucred *cred, struct vnode *vp, struct label *label, int acc_mode) { ASSERT_CRED_LABEL(cred->cr_label); ASSERT_VNODE_LABEL(label); return (0); } static int mac_test_check_vnode_chdir(struct ucred *cred, struct vnode *dvp, struct label *dlabel) { ASSERT_CRED_LABEL(cred->cr_label); ASSERT_VNODE_LABEL(dlabel); return (0); } static int mac_test_check_vnode_chroot(struct ucred *cred, struct vnode *dvp, struct label *dlabel) { ASSERT_CRED_LABEL(cred->cr_label); ASSERT_VNODE_LABEL(dlabel); return (0); } static int mac_test_check_vnode_create(struct ucred *cred, struct vnode *dvp, struct label *dlabel, struct componentname *cnp, struct vattr *vap) { ASSERT_CRED_LABEL(cred->cr_label); ASSERT_VNODE_LABEL(dlabel); return (0); } static int mac_test_check_vnode_delete(struct ucred *cred, struct vnode *dvp, struct label *dlabel, struct vnode *vp, struct label *label, struct componentname *cnp) { ASSERT_CRED_LABEL(cred->cr_label); ASSERT_VNODE_LABEL(dlabel); ASSERT_VNODE_LABEL(label); return (0); } static int mac_test_check_vnode_deleteacl(struct ucred *cred, struct vnode *vp, struct label *label, acl_type_t type) { ASSERT_CRED_LABEL(cred->cr_label); ASSERT_VNODE_LABEL(label); return (0); } static int mac_test_check_vnode_deleteextattr(struct ucred *cred, struct vnode *vp, struct label *label, int attrnamespace, const char *name) { ASSERT_CRED_LABEL(cred->cr_label); ASSERT_VNODE_LABEL(label); return (0); } static int mac_test_check_vnode_exec(struct ucred *cred, struct vnode *vp, struct label *label, struct image_params *imgp, struct label *execlabel) { ASSERT_CRED_LABEL(cred->cr_label); ASSERT_VNODE_LABEL(label); if (execlabel != NULL) { ASSERT_CRED_LABEL(execlabel); } return (0); } static int mac_test_check_vnode_getacl(struct ucred *cred, struct vnode *vp, struct label *label, acl_type_t type) { ASSERT_CRED_LABEL(cred->cr_label); ASSERT_VNODE_LABEL(label); return (0); } static int mac_test_check_vnode_getextattr(struct ucred *cred, struct vnode *vp, struct label *label, int attrnamespace, const char *name, struct uio *uio) { ASSERT_CRED_LABEL(cred->cr_label); ASSERT_VNODE_LABEL(label); return (0); } static int mac_test_check_vnode_link(struct ucred *cred, struct vnode *dvp, struct label *dlabel, struct vnode *vp, struct label *label, struct componentname *cnp) { ASSERT_CRED_LABEL(cred->cr_label); ASSERT_VNODE_LABEL(dlabel); ASSERT_VNODE_LABEL(label); return (0); } static int mac_test_check_vnode_listextattr(struct ucred *cred, struct vnode *vp, struct label *label, int attrnamespace) { ASSERT_CRED_LABEL(cred->cr_label); ASSERT_VNODE_LABEL(label); return (0); } static int mac_test_check_vnode_lookup(struct ucred *cred, struct vnode *dvp, struct label *dlabel, struct componentname *cnp) { ASSERT_CRED_LABEL(cred->cr_label); ASSERT_VNODE_LABEL(dlabel); return (0); } static int mac_test_check_vnode_mmap(struct ucred *cred, struct vnode *vp, struct label *label, int prot) { ASSERT_CRED_LABEL(cred->cr_label); ASSERT_VNODE_LABEL(label); return (0); } static int mac_test_check_vnode_mprotect(struct ucred *cred, struct vnode *vp, struct label *label, int prot) { ASSERT_CRED_LABEL(cred->cr_label); ASSERT_VNODE_LABEL(label); return (0); } static int mac_test_check_vnode_open(struct ucred *cred, struct vnode *vp, struct label *filelabel, int acc_mode) { ASSERT_CRED_LABEL(cred->cr_label); ASSERT_VNODE_LABEL(filelabel); return (0); } static int mac_test_check_vnode_poll(struct ucred *active_cred, struct ucred *file_cred, struct vnode *vp, struct label *label) { ASSERT_CRED_LABEL(active_cred->cr_label); ASSERT_CRED_LABEL(file_cred->cr_label); ASSERT_VNODE_LABEL(label); return (0); } static int mac_test_check_vnode_read(struct ucred *active_cred, struct ucred *file_cred, struct vnode *vp, struct label *label) { ASSERT_CRED_LABEL(active_cred->cr_label); if (file_cred != NULL) { ASSERT_CRED_LABEL(file_cred->cr_label); } ASSERT_VNODE_LABEL(label); return (0); } static int mac_test_check_vnode_readdir(struct ucred *cred, struct vnode *dvp, struct label *dlabel) { ASSERT_CRED_LABEL(cred->cr_label); ASSERT_VNODE_LABEL(dlabel); return (0); } static int mac_test_check_vnode_readlink(struct ucred *cred, struct vnode *vp, struct label *vnodelabel) { ASSERT_CRED_LABEL(cred->cr_label); ASSERT_VNODE_LABEL(vnodelabel); return (0); } static int mac_test_check_vnode_relabel(struct ucred *cred, struct vnode *vp, struct label *vnodelabel, struct label *newlabel) { ASSERT_CRED_LABEL(cred->cr_label); ASSERT_VNODE_LABEL(vnodelabel); ASSERT_VNODE_LABEL(newlabel); return (0); } static int mac_test_check_vnode_rename_from(struct ucred *cred, struct vnode *dvp, struct label *dlabel, struct vnode *vp, struct label *label, struct componentname *cnp) { ASSERT_CRED_LABEL(cred->cr_label); ASSERT_VNODE_LABEL(dlabel); ASSERT_VNODE_LABEL(label); return (0); } static int mac_test_check_vnode_rename_to(struct ucred *cred, struct vnode *dvp, struct label *dlabel, struct vnode *vp, struct label *label, int samedir, struct componentname *cnp) { ASSERT_CRED_LABEL(cred->cr_label); ASSERT_VNODE_LABEL(dlabel); if (vp != NULL) { ASSERT_VNODE_LABEL(label); } return (0); } static int mac_test_check_vnode_revoke(struct ucred *cred, struct vnode *vp, struct label *label) { ASSERT_CRED_LABEL(cred->cr_label); ASSERT_VNODE_LABEL(label); return (0); } static int mac_test_check_vnode_setacl(struct ucred *cred, struct vnode *vp, struct label *label, acl_type_t type, struct acl *acl) { ASSERT_CRED_LABEL(cred->cr_label); ASSERT_VNODE_LABEL(label); return (0); } static int mac_test_check_vnode_setextattr(struct ucred *cred, struct vnode *vp, struct label *label, int attrnamespace, const char *name, struct uio *uio) { ASSERT_CRED_LABEL(cred->cr_label); ASSERT_VNODE_LABEL(label); return (0); } static int mac_test_check_vnode_setflags(struct ucred *cred, struct vnode *vp, struct label *label, u_long flags) { ASSERT_CRED_LABEL(cred->cr_label); ASSERT_VNODE_LABEL(label); return (0); } static int mac_test_check_vnode_setmode(struct ucred *cred, struct vnode *vp, struct label *label, mode_t mode) { ASSERT_CRED_LABEL(cred->cr_label); ASSERT_VNODE_LABEL(label); return (0); } static int mac_test_check_vnode_setowner(struct ucred *cred, struct vnode *vp, struct label *label, uid_t uid, gid_t gid) { ASSERT_CRED_LABEL(cred->cr_label); ASSERT_VNODE_LABEL(label); return (0); } static int mac_test_check_vnode_setutimes(struct ucred *cred, struct vnode *vp, struct label *label, struct timespec atime, struct timespec mtime) { ASSERT_CRED_LABEL(cred->cr_label); ASSERT_VNODE_LABEL(label); return (0); } static int mac_test_check_vnode_stat(struct ucred *active_cred, struct ucred *file_cred, struct vnode *vp, struct label *label) { ASSERT_CRED_LABEL(active_cred->cr_label); if (file_cred != NULL) { ASSERT_CRED_LABEL(file_cred->cr_label); } ASSERT_VNODE_LABEL(label); return (0); } static int mac_test_check_vnode_write(struct ucred *active_cred, struct ucred *file_cred, struct vnode *vp, struct label *label) { ASSERT_CRED_LABEL(active_cred->cr_label); if (file_cred != NULL) { ASSERT_CRED_LABEL(file_cred->cr_label); } ASSERT_VNODE_LABEL(label); return (0); } static struct mac_policy_ops mac_test_ops = { .mpo_destroy = mac_test_destroy, .mpo_init = mac_test_init, .mpo_syscall = mac_test_syscall, .mpo_init_bpfdesc_label = mac_test_init_bpfdesc_label, .mpo_init_cred_label = mac_test_init_cred_label, .mpo_init_devfsdirent_label = mac_test_init_devfsdirent_label, .mpo_init_ifnet_label = mac_test_init_ifnet_label, .mpo_init_inpcb_label = mac_test_init_inpcb_label, .mpo_init_ipq_label = mac_test_init_ipq_label, .mpo_init_mbuf_label = mac_test_init_mbuf_label, .mpo_init_mount_label = mac_test_init_mount_label, .mpo_init_mount_fs_label = mac_test_init_mount_fs_label, .mpo_init_pipe_label = mac_test_init_pipe_label, .mpo_init_proc_label = mac_test_init_proc_label, .mpo_init_socket_label = mac_test_init_socket_label, .mpo_init_socket_peer_label = mac_test_init_socket_peer_label, .mpo_init_vnode_label = mac_test_init_vnode_label, .mpo_destroy_bpfdesc_label = mac_test_destroy_bpfdesc_label, .mpo_destroy_cred_label = mac_test_destroy_cred_label, .mpo_destroy_devfsdirent_label = mac_test_destroy_devfsdirent_label, .mpo_destroy_ifnet_label = mac_test_destroy_ifnet_label, .mpo_destroy_inpcb_label = mac_test_destroy_inpcb_label, .mpo_destroy_ipq_label = mac_test_destroy_ipq_label, .mpo_destroy_mbuf_label = mac_test_destroy_mbuf_label, .mpo_destroy_mount_label = mac_test_destroy_mount_label, .mpo_destroy_mount_fs_label = mac_test_destroy_mount_fs_label, .mpo_destroy_pipe_label = mac_test_destroy_pipe_label, .mpo_destroy_proc_label = mac_test_destroy_proc_label, .mpo_destroy_socket_label = mac_test_destroy_socket_label, .mpo_destroy_socket_peer_label = mac_test_destroy_socket_peer_label, .mpo_destroy_vnode_label = mac_test_destroy_vnode_label, .mpo_copy_cred_label = mac_test_copy_cred_label, .mpo_copy_mbuf_label = mac_test_copy_mbuf_label, .mpo_copy_pipe_label = mac_test_copy_pipe_label, .mpo_copy_socket_label = mac_test_copy_socket_label, .mpo_copy_vnode_label = mac_test_copy_vnode_label, .mpo_externalize_cred_label = mac_test_externalize_label, .mpo_externalize_ifnet_label = mac_test_externalize_label, .mpo_externalize_pipe_label = mac_test_externalize_label, .mpo_externalize_socket_label = mac_test_externalize_label, .mpo_externalize_socket_peer_label = mac_test_externalize_label, .mpo_externalize_vnode_label = mac_test_externalize_label, .mpo_internalize_cred_label = mac_test_internalize_label, .mpo_internalize_ifnet_label = mac_test_internalize_label, .mpo_internalize_pipe_label = mac_test_internalize_label, .mpo_internalize_socket_label = mac_test_internalize_label, .mpo_internalize_vnode_label = mac_test_internalize_label, .mpo_associate_vnode_devfs = mac_test_associate_vnode_devfs, .mpo_associate_vnode_extattr = mac_test_associate_vnode_extattr, .mpo_associate_vnode_singlelabel = mac_test_associate_vnode_singlelabel, .mpo_create_devfs_device = mac_test_create_devfs_device, .mpo_create_devfs_directory = mac_test_create_devfs_directory, .mpo_create_devfs_symlink = mac_test_create_devfs_symlink, .mpo_create_vnode_extattr = mac_test_create_vnode_extattr, .mpo_create_mount = mac_test_create_mount, .mpo_create_root_mount = mac_test_create_root_mount, .mpo_relabel_vnode = mac_test_relabel_vnode, .mpo_setlabel_vnode_extattr = mac_test_setlabel_vnode_extattr, .mpo_update_devfsdirent = mac_test_update_devfsdirent, .mpo_create_mbuf_from_socket = mac_test_create_mbuf_from_socket, .mpo_create_pipe = mac_test_create_pipe, .mpo_create_socket = mac_test_create_socket, .mpo_create_socket_from_socket = mac_test_create_socket_from_socket, .mpo_relabel_pipe = mac_test_relabel_pipe, .mpo_relabel_socket = mac_test_relabel_socket, .mpo_set_socket_peer_from_mbuf = mac_test_set_socket_peer_from_mbuf, .mpo_set_socket_peer_from_socket = mac_test_set_socket_peer_from_socket, .mpo_create_bpfdesc = mac_test_create_bpfdesc, .mpo_create_ifnet = mac_test_create_ifnet, .mpo_create_inpcb_from_socket = mac_test_create_inpcb_from_socket, .mpo_create_datagram_from_ipq = mac_test_create_datagram_from_ipq, .mpo_create_fragment = mac_test_create_fragment, .mpo_create_ipq = mac_test_create_ipq, .mpo_create_mbuf_from_inpcb = mac_test_create_mbuf_from_inpcb, .mpo_create_mbuf_from_mbuf = mac_test_create_mbuf_from_mbuf, .mpo_create_mbuf_linklayer = mac_test_create_mbuf_linklayer, .mpo_create_mbuf_from_bpfdesc = mac_test_create_mbuf_from_bpfdesc, .mpo_create_mbuf_from_ifnet = mac_test_create_mbuf_from_ifnet, .mpo_create_mbuf_multicast_encap = mac_test_create_mbuf_multicast_encap, .mpo_create_mbuf_netlayer = mac_test_create_mbuf_netlayer, .mpo_fragment_match = mac_test_fragment_match, .mpo_reflect_mbuf_icmp = mac_test_reflect_mbuf_icmp, .mpo_reflect_mbuf_tcp = mac_test_reflect_mbuf_tcp, .mpo_relabel_ifnet = mac_test_relabel_ifnet, .mpo_update_ipq = mac_test_update_ipq, .mpo_inpcb_sosetlabel = mac_test_inpcb_sosetlabel, .mpo_execve_transition = mac_test_execve_transition, .mpo_execve_will_transition = mac_test_execve_will_transition, .mpo_create_proc0 = mac_test_create_proc0, .mpo_create_proc1 = mac_test_create_proc1, .mpo_relabel_cred = mac_test_relabel_cred, .mpo_thread_userret = mac_test_thread_userret, .mpo_check_bpfdesc_receive = mac_test_check_bpfdesc_receive, .mpo_check_cred_relabel = mac_test_check_cred_relabel, .mpo_check_cred_visible = mac_test_check_cred_visible, .mpo_check_ifnet_relabel = mac_test_check_ifnet_relabel, .mpo_check_ifnet_transmit = mac_test_check_ifnet_transmit, .mpo_check_inpcb_deliver = mac_test_check_inpcb_deliver, .mpo_check_kenv_dump = mac_test_check_kenv_dump, .mpo_check_kenv_get = mac_test_check_kenv_get, .mpo_check_kenv_set = mac_test_check_kenv_set, .mpo_check_kenv_unset = mac_test_check_kenv_unset, .mpo_check_kld_load = mac_test_check_kld_load, .mpo_check_kld_stat = mac_test_check_kld_stat, .mpo_check_kld_unload = mac_test_check_kld_unload, .mpo_check_mount_stat = mac_test_check_mount_stat, .mpo_check_pipe_ioctl = mac_test_check_pipe_ioctl, .mpo_check_pipe_poll = mac_test_check_pipe_poll, .mpo_check_pipe_read = mac_test_check_pipe_read, .mpo_check_pipe_relabel = mac_test_check_pipe_relabel, .mpo_check_pipe_stat = mac_test_check_pipe_stat, .mpo_check_pipe_write = mac_test_check_pipe_write, .mpo_check_proc_debug = mac_test_check_proc_debug, .mpo_check_proc_sched = mac_test_check_proc_sched, .mpo_check_proc_signal = mac_test_check_proc_signal, .mpo_check_socket_bind = mac_test_check_socket_bind, .mpo_check_socket_connect = mac_test_check_socket_connect, .mpo_check_socket_deliver = mac_test_check_socket_deliver, .mpo_check_socket_listen = mac_test_check_socket_listen, .mpo_check_socket_relabel = mac_test_check_socket_relabel, .mpo_check_socket_visible = mac_test_check_socket_visible, .mpo_check_sysarch_ioperm = mac_test_check_sysarch_ioperm, .mpo_check_system_acct = mac_test_check_system_acct, .mpo_check_system_reboot = mac_test_check_system_reboot, .mpo_check_system_settime = mac_test_check_system_settime, .mpo_check_system_swapon = mac_test_check_system_swapon, .mpo_check_system_swapoff = mac_test_check_system_swapoff, .mpo_check_system_sysctl = mac_test_check_system_sysctl, .mpo_check_vnode_access = mac_test_check_vnode_access, .mpo_check_vnode_chdir = mac_test_check_vnode_chdir, .mpo_check_vnode_chroot = mac_test_check_vnode_chroot, .mpo_check_vnode_create = mac_test_check_vnode_create, .mpo_check_vnode_delete = mac_test_check_vnode_delete, .mpo_check_vnode_deleteacl = mac_test_check_vnode_deleteacl, .mpo_check_vnode_deleteextattr = mac_test_check_vnode_deleteextattr, .mpo_check_vnode_exec = mac_test_check_vnode_exec, .mpo_check_vnode_getacl = mac_test_check_vnode_getacl, .mpo_check_vnode_getextattr = mac_test_check_vnode_getextattr, .mpo_check_vnode_link = mac_test_check_vnode_link, .mpo_check_vnode_listextattr = mac_test_check_vnode_listextattr, .mpo_check_vnode_lookup = mac_test_check_vnode_lookup, .mpo_check_vnode_mmap = mac_test_check_vnode_mmap, .mpo_check_vnode_mprotect = mac_test_check_vnode_mprotect, .mpo_check_vnode_open = mac_test_check_vnode_open, .mpo_check_vnode_poll = mac_test_check_vnode_poll, .mpo_check_vnode_read = mac_test_check_vnode_read, .mpo_check_vnode_readdir = mac_test_check_vnode_readdir, .mpo_check_vnode_readlink = mac_test_check_vnode_readlink, .mpo_check_vnode_relabel = mac_test_check_vnode_relabel, .mpo_check_vnode_rename_from = mac_test_check_vnode_rename_from, .mpo_check_vnode_rename_to = mac_test_check_vnode_rename_to, .mpo_check_vnode_revoke = mac_test_check_vnode_revoke, .mpo_check_vnode_setacl = mac_test_check_vnode_setacl, .mpo_check_vnode_setextattr = mac_test_check_vnode_setextattr, .mpo_check_vnode_setflags = mac_test_check_vnode_setflags, .mpo_check_vnode_setmode = mac_test_check_vnode_setmode, .mpo_check_vnode_setowner = mac_test_check_vnode_setowner, .mpo_check_vnode_setutimes = mac_test_check_vnode_setutimes, .mpo_check_vnode_stat = mac_test_check_vnode_stat, .mpo_check_vnode_write = mac_test_check_vnode_write, }; MAC_POLICY_SET(&mac_test_ops, mac_test, "TrustedBSD MAC/Test", MPC_LOADTIME_FLAG_UNLOADOK | MPC_LOADTIME_FLAG_LABELMBUFS, &test_slot); Index: head/sys/sys/mac.h =================================================================== --- head/sys/sys/mac.h (revision 125292) +++ head/sys/sys/mac.h (revision 125293) @@ -1,366 +1,366 @@ /*- * Copyright (c) 1999, 2000, 2001, 2002 Robert N. M. Watson * Copyright (c) 2001, 2002, 2003 Networks Associates Technology, Inc. * All rights reserved. * * This software was developed by Robert Watson for the TrustedBSD Project. * * This software was developed for the FreeBSD Project in part by Network * Associates Laboratories, the Security Research Division of Network * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), * as part of the DARPA CHATS research program. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ /* * Userland/kernel interface for Mandatory Access Control. * * The POSIX.1e implementation page may be reached at: * http://www.trustedbsd.org/ */ #ifndef _SYS_MAC_H #define _SYS_MAC_H #include #ifndef _POSIX_MAC #define _POSIX_MAC #endif /* * MAC framework-related constants and limits. */ #define MAC_MAX_POLICY_NAME 32 #define MAC_MAX_LABEL_ELEMENT_NAME 32 #define MAC_MAX_LABEL_ELEMENT_DATA 4096 #define MAC_MAX_LABEL_BUF_LEN 8192 struct mac { size_t m_buflen; char *m_string; }; typedef struct mac *mac_t; #ifndef _KERNEL /* * Location of the userland MAC framework configuration file. mac.conf * binds policy names to shared libraries that understand those policies, * as well as setting defaults for MAC-aware applications. */ #define MAC_CONFFILE "/etc/mac.conf" /* * Extended non-POSIX.1e interfaces that offer additional services * available from the userland and kernel MAC frameworks. */ __BEGIN_DECLS int mac_execve(char *fname, char **argv, char **envv, mac_t _label); int mac_free(mac_t _label); int mac_from_text(mac_t *_label, const char *_text); int mac_get_fd(int _fd, mac_t _label); int mac_get_file(const char *_path, mac_t _label); int mac_get_link(const char *_path, mac_t _label); int mac_get_peer(int _fd, mac_t _label); int mac_get_pid(pid_t _pid, mac_t _label); int mac_get_proc(mac_t _label); int mac_is_present(const char *_policyname); int mac_prepare(mac_t *_label, const char *_elements); int mac_prepare_file_label(mac_t *_label); int mac_prepare_ifnet_label(mac_t *_label); int mac_prepare_process_label(mac_t *_label); int mac_prepare_type(mac_t *_label, const char *_type); int mac_set_fd(int _fildes, const mac_t _label); int mac_set_file(const char *_path, mac_t _label); int mac_set_link(const char *_path, mac_t _label); int mac_set_proc(const mac_t _label); int mac_syscall(const char *_policyname, int _call, void *_arg); int mac_to_text(mac_t mac, char **_text); __END_DECLS #else /* _KERNEL */ /* * Kernel functions to manage and evaluate labels. */ struct bpf_d; struct componentname; struct devfs_dirent; struct ifnet; struct ifreq; struct inpcb; struct image_params; struct inpcb; struct ipq; struct m_tag; struct mbuf; struct mount; struct proc; struct sockaddr; struct socket; -struct pipe; +struct pipepair; struct thread; struct timespec; struct ucred; struct uio; struct vattr; struct vnode; #include /* XXX acl_type_t */ struct vop_setlabel_args; /* * Label operations. */ void mac_init_bpfdesc(struct bpf_d *); void mac_init_cred(struct ucred *); void mac_init_devfsdirent(struct devfs_dirent *); void mac_init_ifnet(struct ifnet *); int mac_init_inpcb(struct inpcb *, int flag); int mac_init_ipq(struct ipq *, int flag); int mac_init_socket(struct socket *, int flag); -void mac_init_pipe(struct pipe *); +void mac_init_pipe(struct pipepair *); int mac_init_mbuf(struct mbuf *mbuf, int flag); int mac_init_mbuf_tag(struct m_tag *, int flag); void mac_init_mount(struct mount *); void mac_init_proc(struct proc *); void mac_init_vnode(struct vnode *); void mac_copy_mbuf_tag(struct m_tag *, struct m_tag *); void mac_copy_vnode_label(struct label *, struct label *label); void mac_destroy_bpfdesc(struct bpf_d *); void mac_destroy_cred(struct ucred *); void mac_destroy_devfsdirent(struct devfs_dirent *); void mac_destroy_ifnet(struct ifnet *); void mac_destroy_inpcb(struct inpcb *); void mac_destroy_ipq(struct ipq *); void mac_destroy_socket(struct socket *); -void mac_destroy_pipe(struct pipe *); +void mac_destroy_pipe(struct pipepair *); void mac_destroy_proc(struct proc *); void mac_destroy_mbuf_tag(struct m_tag *); void mac_destroy_mount(struct mount *); void mac_destroy_vnode(struct vnode *); struct label *mac_cred_label_alloc(void); void mac_cred_label_free(struct label *label); struct label *mac_vnode_label_alloc(void); void mac_vnode_label_free(struct label *label); /* * Labeling event operations: file system objects, and things that * look a lot like file system objects. */ void mac_associate_vnode_devfs(struct mount *mp, struct devfs_dirent *de, struct vnode *vp); int mac_associate_vnode_extattr(struct mount *mp, struct vnode *vp); void mac_associate_vnode_singlelabel(struct mount *mp, struct vnode *vp); void mac_create_devfs_device(struct mount *mp, dev_t dev, struct devfs_dirent *de); void mac_create_devfs_directory(struct mount *mp, char *dirname, int dirnamelen, struct devfs_dirent *de); void mac_create_devfs_symlink(struct ucred *cred, struct mount *mp, struct devfs_dirent *dd, struct devfs_dirent *de); int mac_create_vnode_extattr(struct ucred *cred, struct mount *mp, struct vnode *dvp, struct vnode *vp, struct componentname *cnp); void mac_create_mount(struct ucred *cred, struct mount *mp); void mac_create_root_mount(struct ucred *cred, struct mount *mp); void mac_relabel_vnode(struct ucred *cred, struct vnode *vp, struct label *newlabel); void mac_update_devfsdirent(struct mount *mp, struct devfs_dirent *de, struct vnode *vp); /* * Labeling event operations: IPC objects. */ void mac_create_mbuf_from_socket(struct socket *so, struct mbuf *m); void mac_create_socket(struct ucred *cred, struct socket *socket); void mac_create_socket_from_socket(struct socket *oldsocket, struct socket *newsocket); void mac_set_socket_peer_from_mbuf(struct mbuf *mbuf, struct socket *socket); void mac_set_socket_peer_from_socket(struct socket *oldsocket, struct socket *newsocket); -void mac_create_pipe(struct ucred *cred, struct pipe *pipe); +void mac_create_pipe(struct ucred *cred, struct pipepair *pp); /* * Labeling event operations: network objects. */ void mac_create_bpfdesc(struct ucred *cred, struct bpf_d *bpf_d); void mac_create_ifnet(struct ifnet *ifp); void mac_create_inpcb_from_socket(struct socket *so, struct inpcb *inp); void mac_create_ipq(struct mbuf *fragment, struct ipq *ipq); void mac_create_datagram_from_ipq(struct ipq *ipq, struct mbuf *datagram); void mac_create_fragment(struct mbuf *datagram, struct mbuf *fragment); void mac_create_mbuf_from_inpcb(struct inpcb *inp, struct mbuf *m); void mac_create_mbuf_from_mbuf(struct mbuf *oldmbuf, struct mbuf *newmbuf); void mac_create_mbuf_linklayer(struct ifnet *ifnet, struct mbuf *m); void mac_create_mbuf_from_bpfdesc(struct bpf_d *bpf_d, struct mbuf *m); void mac_create_mbuf_from_ifnet(struct ifnet *ifnet, struct mbuf *m); void mac_create_mbuf_multicast_encap(struct mbuf *oldmbuf, struct ifnet *ifnet, struct mbuf *newmbuf); void mac_create_mbuf_netlayer(struct mbuf *oldmbuf, struct mbuf *newmbuf); int mac_fragment_match(struct mbuf *fragment, struct ipq *ipq); void mac_reflect_mbuf_icmp(struct mbuf *m); void mac_reflect_mbuf_tcp(struct mbuf *m); void mac_update_ipq(struct mbuf *fragment, struct ipq *ipq); void mac_inpcb_sosetlabel(struct socket *so, struct inpcb *inp); /* * Labeling event operations: processes. */ void mac_copy_cred(struct ucred *cr1, struct ucred *cr2); int mac_execve_enter(struct image_params *imgp, struct mac *mac_p); void mac_execve_exit(struct image_params *imgp); void mac_execve_transition(struct ucred *old, struct ucred *new, struct vnode *vp, struct label *interpvnodelabel, struct image_params *imgp); int mac_execve_will_transition(struct ucred *old, struct vnode *vp, struct label *interpvnodelabel, struct image_params *imgp); void mac_create_proc0(struct ucred *cred); void mac_create_proc1(struct ucred *cred); void mac_thread_userret(struct thread *td); /* Access control checks. */ int mac_check_bpfdesc_receive(struct bpf_d *bpf_d, struct ifnet *ifnet); int mac_check_cred_visible(struct ucred *u1, struct ucred *u2); int mac_check_ifnet_transmit(struct ifnet *ifnet, struct mbuf *m); int mac_check_inpcb_deliver(struct inpcb *inp, struct mbuf *m); int mac_check_kenv_dump(struct ucred *cred); int mac_check_kenv_get(struct ucred *cred, char *name); int mac_check_kenv_set(struct ucred *cred, char *name, char *value); int mac_check_kenv_unset(struct ucred *cred, char *name); int mac_check_kld_load(struct ucred *cred, struct vnode *vp); int mac_check_kld_stat(struct ucred *cred); int mac_check_kld_unload(struct ucred *cred); int mac_check_mount_stat(struct ucred *cred, struct mount *mp); -int mac_check_pipe_ioctl(struct ucred *cred, struct pipe *pipe, +int mac_check_pipe_ioctl(struct ucred *cred, struct pipepair *pp, unsigned long cmd, void *data); -int mac_check_pipe_poll(struct ucred *cred, struct pipe *pipe); -int mac_check_pipe_read(struct ucred *cred, struct pipe *pipe); -int mac_check_pipe_stat(struct ucred *cred, struct pipe *pipe); -int mac_check_pipe_write(struct ucred *cred, struct pipe *pipe); +int mac_check_pipe_poll(struct ucred *cred, struct pipepair *pp); +int mac_check_pipe_read(struct ucred *cred, struct pipepair *pp); +int mac_check_pipe_stat(struct ucred *cred, struct pipepair *pp); +int mac_check_pipe_write(struct ucred *cred, struct pipepair *pp); int mac_check_proc_debug(struct ucred *cred, struct proc *proc); int mac_check_proc_sched(struct ucred *cred, struct proc *proc); int mac_check_proc_signal(struct ucred *cred, struct proc *proc, int signum); int mac_check_socket_bind(struct ucred *cred, struct socket *so, struct sockaddr *sockaddr); int mac_check_socket_connect(struct ucred *cred, struct socket *so, struct sockaddr *sockaddr); int mac_check_socket_deliver(struct socket *so, struct mbuf *m); int mac_check_socket_listen(struct ucred *cred, struct socket *so); int mac_check_socket_receive(struct ucred *cred, struct socket *so); int mac_check_socket_send(struct ucred *cred, struct socket *so); int mac_check_socket_visible(struct ucred *cred, struct socket *so); int mac_check_sysarch_ioperm(struct ucred *cred); int mac_check_system_acct(struct ucred *cred, struct vnode *vp); int mac_check_system_nfsd(struct ucred *cred); int mac_check_system_reboot(struct ucred *cred, int howto); int mac_check_system_settime(struct ucred *cred); int mac_check_system_swapon(struct ucred *cred, struct vnode *vp); int mac_check_system_swapoff(struct ucred *cred, struct vnode *vp); int mac_check_system_sysctl(struct ucred *cred, int *name, u_int namelen, void *old, size_t *oldlenp, int inkernel, void *new, size_t newlen); int mac_check_vnode_access(struct ucred *cred, struct vnode *vp, int acc_mode); int mac_check_vnode_chdir(struct ucred *cred, struct vnode *dvp); int mac_check_vnode_chroot(struct ucred *cred, struct vnode *dvp); int mac_check_vnode_create(struct ucred *cred, struct vnode *dvp, struct componentname *cnp, struct vattr *vap); int mac_check_vnode_delete(struct ucred *cred, struct vnode *dvp, struct vnode *vp, struct componentname *cnp); int mac_check_vnode_deleteacl(struct ucred *cred, struct vnode *vp, acl_type_t type); int mac_check_vnode_deleteextattr(struct ucred *cred, struct vnode *vp, int attrnamespace, const char *name); int mac_check_vnode_exec(struct ucred *cred, struct vnode *vp, struct image_params *imgp); int mac_check_vnode_getacl(struct ucred *cred, struct vnode *vp, acl_type_t type); int mac_check_vnode_getextattr(struct ucred *cred, struct vnode *vp, int attrnamespace, const char *name, struct uio *uio); int mac_check_vnode_link(struct ucred *cred, struct vnode *dvp, struct vnode *vp, struct componentname *cnp); int mac_check_vnode_listextattr(struct ucred *cred, struct vnode *vp, int attrnamespace); int mac_check_vnode_lookup(struct ucred *cred, struct vnode *dvp, struct componentname *cnp); int mac_check_vnode_mmap(struct ucred *cred, struct vnode *vp, int prot); int mac_check_vnode_mprotect(struct ucred *cred, struct vnode *vp, int prot); int mac_check_vnode_open(struct ucred *cred, struct vnode *vp, int acc_mode); int mac_check_vnode_poll(struct ucred *active_cred, struct ucred *file_cred, struct vnode *vp); int mac_check_vnode_read(struct ucred *active_cred, struct ucred *file_cred, struct vnode *vp); int mac_check_vnode_readdir(struct ucred *cred, struct vnode *vp); int mac_check_vnode_readlink(struct ucred *cred, struct vnode *vp); int mac_check_vnode_rename_from(struct ucred *cred, struct vnode *dvp, struct vnode *vp, struct componentname *cnp); int mac_check_vnode_rename_to(struct ucred *cred, struct vnode *dvp, struct vnode *vp, int samedir, struct componentname *cnp); int mac_check_vnode_revoke(struct ucred *cred, struct vnode *vp); int mac_check_vnode_setacl(struct ucred *cred, struct vnode *vp, acl_type_t type, struct acl *acl); int mac_check_vnode_setextattr(struct ucred *cred, struct vnode *vp, int attrnamespace, const char *name, struct uio *uio); int mac_check_vnode_setflags(struct ucred *cred, struct vnode *vp, u_long flags); int mac_check_vnode_setmode(struct ucred *cred, struct vnode *vp, mode_t mode); int mac_check_vnode_setowner(struct ucred *cred, struct vnode *vp, uid_t uid, gid_t gid); int mac_check_vnode_setutimes(struct ucred *cred, struct vnode *vp, struct timespec atime, struct timespec mtime); int mac_check_vnode_stat(struct ucred *active_cred, struct ucred *file_cred, struct vnode *vp); int mac_check_vnode_write(struct ucred *active_cred, struct ucred *file_cred, struct vnode *vp); int mac_getsockopt_label(struct ucred *cred, struct socket *so, struct mac *extmac); int mac_getsockopt_peerlabel(struct ucred *cred, struct socket *so, struct mac *extmac); int mac_ioctl_ifnet_get(struct ucred *cred, struct ifreq *ifr, struct ifnet *ifnet); int mac_ioctl_ifnet_set(struct ucred *cred, struct ifreq *ifr, struct ifnet *ifnet); int mac_setsockopt_label(struct ucred *cred, struct socket *so, struct mac *extmac); -int mac_pipe_label_set(struct ucred *cred, struct pipe *pipe, +int mac_pipe_label_set(struct ucred *cred, struct pipepair *pp, struct label *label); void mac_cred_mmapped_drop_perms(struct thread *td, struct ucred *cred); /* * Calls to help various file systems implement labeling functionality * using their existing EA implementation. */ int vop_stdsetlabel_ea(struct vop_setlabel_args *ap); #endif /* !_KERNEL */ #endif /* !_SYS_MAC_H */ Index: head/sys/sys/mac_policy.h =================================================================== --- head/sys/sys/mac_policy.h (revision 125292) +++ head/sys/sys/mac_policy.h (revision 125293) @@ -1,495 +1,496 @@ /*- * Copyright (c) 1999, 2000, 2001, 2002 Robert N. M. Watson * Copyright (c) 2001, 2002, 2003 Networks Associates Technology, Inc. * All rights reserved. * * This software was developed by Robert Watson for the TrustedBSD Project. * * This software was developed for the FreeBSD Project in part by Network * Associates Laboratories, the Security Research Division of Network * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), * as part of the DARPA CHATS research program. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ /* * Kernel interface for MAC policy modules. */ #ifndef _SYS_MAC_POLICY_H #define _SYS_MAC_POLICY_H /*- * Pluggable access control policy definition structure. * * List of operations that are performed as part of the implementation * of a MAC policy. Policy implementors declare operations with a * mac_policy_ops structure, and using the MAC_POLICY_SET() macro. * If an entry point is not declared, then then the policy will be ignored * during evaluation of that event or check. * * Operations are sorted first by general class of operation, then * alphabetically. */ struct acl; struct componentname; struct devfs_dirent; struct inpcb; struct ipq; struct label; struct mac_policy_conf; struct mbuf; struct mount; -struct pipe; +struct pipepair; struct sbuf; struct socket; struct ucred; struct uio; struct vnode; struct mac_policy_ops { /* * Policy module operations. */ void (*mpo_destroy)(struct mac_policy_conf *mpc); void (*mpo_init)(struct mac_policy_conf *mpc); /* * General policy-directed security system call so that policies * may implement new services without reserving explicit * system call numbers. */ int (*mpo_syscall)(struct thread *td, int call, void *arg); /* * Label operations. */ void (*mpo_init_bpfdesc_label)(struct label *label); void (*mpo_init_cred_label)(struct label *label); void (*mpo_init_devfsdirent_label)(struct label *label); void (*mpo_init_ifnet_label)(struct label *label); int (*mpo_init_inpcb_label)(struct label *label, int flag); int (*mpo_init_ipq_label)(struct label *label, int flag); int (*mpo_init_mbuf_label)(struct label *label, int flag); void (*mpo_init_mount_label)(struct label *label); void (*mpo_init_mount_fs_label)(struct label *label); int (*mpo_init_socket_label)(struct label *label, int flag); int (*mpo_init_socket_peer_label)(struct label *label, int flag); void (*mpo_init_pipe_label)(struct label *label); void (*mpo_init_proc_label)(struct label *label); void (*mpo_init_vnode_label)(struct label *label); void (*mpo_destroy_bpfdesc_label)(struct label *label); void (*mpo_destroy_cred_label)(struct label *label); void (*mpo_destroy_devfsdirent_label)(struct label *label); void (*mpo_destroy_ifnet_label)(struct label *label); void (*mpo_destroy_inpcb_label)(struct label *label); void (*mpo_destroy_ipq_label)(struct label *label); void (*mpo_destroy_mbuf_label)(struct label *label); void (*mpo_destroy_mount_label)(struct label *label); void (*mpo_destroy_mount_fs_label)(struct label *label); void (*mpo_destroy_socket_label)(struct label *label); void (*mpo_destroy_socket_peer_label)(struct label *label); void (*mpo_destroy_pipe_label)(struct label *label); void (*mpo_destroy_proc_label)(struct label *label); void (*mpo_destroy_vnode_label)(struct label *label); void (*mpo_copy_cred_label)(struct label *src, struct label *dest); void (*mpo_copy_mbuf_label)(struct label *src, struct label *dest); void (*mpo_copy_pipe_label)(struct label *src, struct label *dest); void (*mpo_copy_socket_label)(struct label *src, struct label *dest); void (*mpo_copy_vnode_label)(struct label *src, struct label *dest); int (*mpo_externalize_cred_label)(struct label *label, char *element_name, struct sbuf *sb, int *claimed); int (*mpo_externalize_ifnet_label)(struct label *label, char *element_name, struct sbuf *sb, int *claimed); int (*mpo_externalize_pipe_label)(struct label *label, char *element_name, struct sbuf *sb, int *claimed); int (*mpo_externalize_socket_label)(struct label *label, char *element_name, struct sbuf *sb, int *claimed); int (*mpo_externalize_socket_peer_label)(struct label *label, char *element_name, struct sbuf *sb, int *claimed); int (*mpo_externalize_vnode_label)(struct label *label, char *element_name, struct sbuf *sb, int *claimed); int (*mpo_internalize_cred_label)(struct label *label, char *element_name, char *element_data, int *claimed); int (*mpo_internalize_ifnet_label)(struct label *label, char *element_name, char *element_data, int *claimed); int (*mpo_internalize_pipe_label)(struct label *label, char *element_name, char *element_data, int *claimed); int (*mpo_internalize_socket_label)(struct label *label, char *element_name, char *element_data, int *claimed); int (*mpo_internalize_vnode_label)(struct label *label, char *element_name, char *element_data, int *claimed); /* * Labeling event operations: file system objects, and things that * look a lot like file system objects. */ void (*mpo_associate_vnode_devfs)(struct mount *mp, struct label *fslabel, struct devfs_dirent *de, struct label *delabel, struct vnode *vp, struct label *vlabel); int (*mpo_associate_vnode_extattr)(struct mount *mp, struct label *fslabel, struct vnode *vp, struct label *vlabel); void (*mpo_associate_vnode_singlelabel)(struct mount *mp, struct label *fslabel, struct vnode *vp, struct label *vlabel); void (*mpo_create_devfs_device)(struct mount *mp, dev_t dev, struct devfs_dirent *de, struct label *label); void (*mpo_create_devfs_directory)(struct mount *mp, char *dirname, int dirnamelen, struct devfs_dirent *de, struct label *label); void (*mpo_create_devfs_symlink)(struct ucred *cred, struct mount *mp, struct devfs_dirent *dd, struct label *ddlabel, struct devfs_dirent *de, struct label *delabel); int (*mpo_create_vnode_extattr)(struct ucred *cred, struct mount *mp, struct label *fslabel, struct vnode *dvp, struct label *dlabel, struct vnode *vp, struct label *vlabel, struct componentname *cnp); void (*mpo_create_mount)(struct ucred *cred, struct mount *mp, struct label *mntlabel, struct label *fslabel); void (*mpo_create_root_mount)(struct ucred *cred, struct mount *mp, struct label *mountlabel, struct label *fslabel); void (*mpo_relabel_vnode)(struct ucred *cred, struct vnode *vp, struct label *vnodelabel, struct label *label); int (*mpo_setlabel_vnode_extattr)(struct ucred *cred, struct vnode *vp, struct label *vlabel, struct label *intlabel); void (*mpo_update_devfsdirent)(struct mount *mp, struct devfs_dirent *devfs_dirent, struct label *direntlabel, struct vnode *vp, struct label *vnodelabel); /* * Labeling event operations: IPC objects. */ void (*mpo_create_mbuf_from_socket)(struct socket *so, struct label *socketlabel, struct mbuf *m, struct label *mbuflabel); void (*mpo_create_socket)(struct ucred *cred, struct socket *so, struct label *socketlabel); void (*mpo_create_socket_from_socket)(struct socket *oldsocket, struct label *oldsocketlabel, struct socket *newsocket, struct label *newsocketlabel); void (*mpo_relabel_socket)(struct ucred *cred, struct socket *so, struct label *oldlabel, struct label *newlabel); - void (*mpo_relabel_pipe)(struct ucred *cred, struct pipe *pipe, + void (*mpo_relabel_pipe)(struct ucred *cred, struct pipepair *pp, struct label *oldlabel, struct label *newlabel); void (*mpo_set_socket_peer_from_mbuf)(struct mbuf *mbuf, struct label *mbuflabel, struct socket *so, struct label *socketpeerlabel); void (*mpo_set_socket_peer_from_socket)(struct socket *oldsocket, struct label *oldsocketlabel, struct socket *newsocket, struct label *newsocketpeerlabel); - void (*mpo_create_pipe)(struct ucred *cred, struct pipe *pipe, + void (*mpo_create_pipe)(struct ucred *cred, struct pipepair *pp, struct label *pipelabel); /* * Labeling event operations: network objects. */ void (*mpo_create_bpfdesc)(struct ucred *cred, struct bpf_d *bpf_d, struct label *bpflabel); void (*mpo_create_ifnet)(struct ifnet *ifnet, struct label *ifnetlabel); void (*mpo_create_inpcb_from_socket)(struct socket *so, struct label *solabel, struct inpcb *inp, struct label *inplabel); void (*mpo_create_ipq)(struct mbuf *fragment, struct label *fragmentlabel, struct ipq *ipq, struct label *ipqlabel); void (*mpo_create_datagram_from_ipq) (struct ipq *ipq, struct label *ipqlabel, struct mbuf *datagram, struct label *datagramlabel); void (*mpo_create_fragment)(struct mbuf *datagram, struct label *datagramlabel, struct mbuf *fragment, struct label *fragmentlabel); void (*mpo_create_mbuf_from_inpcb)(struct inpcb *inp, struct label *inplabel, struct mbuf *m, struct label *mlabel); void (*mpo_create_mbuf_from_mbuf)(struct mbuf *oldmbuf, struct label *oldlabel, struct mbuf *newmbuf, struct label *newlabel); void (*mpo_create_mbuf_linklayer)(struct ifnet *ifnet, struct label *ifnetlabel, struct mbuf *mbuf, struct label *mbuflabel); void (*mpo_create_mbuf_from_bpfdesc)(struct bpf_d *bpf_d, struct label *bpflabel, struct mbuf *mbuf, struct label *mbuflabel); void (*mpo_create_mbuf_from_ifnet)(struct ifnet *ifnet, struct label *ifnetlabel, struct mbuf *mbuf, struct label *mbuflabel); void (*mpo_create_mbuf_multicast_encap)(struct mbuf *oldmbuf, struct label *oldmbuflabel, struct ifnet *ifnet, struct label *ifnetlabel, struct mbuf *newmbuf, struct label *newmbuflabel); void (*mpo_create_mbuf_netlayer)(struct mbuf *oldmbuf, struct label *oldmbuflabel, struct mbuf *newmbuf, struct label *newmbuflabel); int (*mpo_fragment_match)(struct mbuf *fragment, struct label *fragmentlabel, struct ipq *ipq, struct label *ipqlabel); void (*mpo_reflect_mbuf_icmp)(struct mbuf *m, struct label *mlabel); void (*mpo_reflect_mbuf_tcp)(struct mbuf *m, struct label *mlabel); void (*mpo_relabel_ifnet)(struct ucred *cred, struct ifnet *ifnet, struct label *ifnetlabel, struct label *newlabel); void (*mpo_update_ipq)(struct mbuf *fragment, struct label *fragmentlabel, struct ipq *ipq, struct label *ipqlabel); void (*mpo_inpcb_sosetlabel)(struct socket *so, struct label *label, struct inpcb *inp, struct label *inplabel); /* * Labeling event operations: processes. */ void (*mpo_execve_transition)(struct ucred *old, struct ucred *new, struct vnode *vp, struct label *vnodelabel, struct label *interpvnodelabel, struct image_params *imgp, struct label *execlabel); int (*mpo_execve_will_transition)(struct ucred *old, struct vnode *vp, struct label *vnodelabel, struct label *interpvnodelabel, struct image_params *imgp, struct label *execlabel); void (*mpo_create_proc0)(struct ucred *cred); void (*mpo_create_proc1)(struct ucred *cred); void (*mpo_relabel_cred)(struct ucred *cred, struct label *newlabel); void (*mpo_thread_userret)(struct thread *thread); /* * Access control checks. */ int (*mpo_check_bpfdesc_receive)(struct bpf_d *bpf_d, struct label *bpflabel, struct ifnet *ifnet, struct label *ifnetlabel); int (*mpo_check_cred_relabel)(struct ucred *cred, struct label *newlabel); int (*mpo_check_cred_visible)(struct ucred *u1, struct ucred *u2); int (*mpo_check_ifnet_relabel)(struct ucred *cred, struct ifnet *ifnet, struct label *ifnetlabel, struct label *newlabel); int (*mpo_check_ifnet_transmit)(struct ifnet *ifnet, struct label *ifnetlabel, struct mbuf *m, struct label *mbuflabel); int (*mpo_check_inpcb_deliver)(struct inpcb *inp, struct label *inplabel, struct mbuf *m, struct label *mlabel); int (*mpo_check_kenv_dump)(struct ucred *cred); int (*mpo_check_kenv_get)(struct ucred *cred, char *name); int (*mpo_check_kenv_set)(struct ucred *cred, char *name, char *value); int (*mpo_check_kenv_unset)(struct ucred *cred, char *name); int (*mpo_check_kld_load)(struct ucred *cred, struct vnode *vp, struct label *vlabel); int (*mpo_check_kld_stat)(struct ucred *cred); int (*mpo_check_kld_unload)(struct ucred *cred); int (*mpo_check_mount_stat)(struct ucred *cred, struct mount *mp, struct label *mntlabel); - int (*mpo_check_pipe_ioctl)(struct ucred *cred, struct pipe *pipe, - struct label *pipelabel, unsigned long cmd, void *data); - int (*mpo_check_pipe_poll)(struct ucred *cred, struct pipe *pipe, - struct label *pipelabel); - int (*mpo_check_pipe_read)(struct ucred *cred, struct pipe *pipe, - struct label *pipelabel); + int (*mpo_check_pipe_ioctl)(struct ucred *cred, + struct pipepair *pp, struct label *pipelabel, + unsigned long cmd, void *data); + int (*mpo_check_pipe_poll)(struct ucred *cred, + struct pipepair *pp, struct label *pipelabel); + int (*mpo_check_pipe_read)(struct ucred *cred, + struct pipepair *pp, struct label *pipelabel); int (*mpo_check_pipe_relabel)(struct ucred *cred, - struct pipe *pipe, struct label *pipelabel, + struct pipepair *pp, struct label *pipelabel, struct label *newlabel); - int (*mpo_check_pipe_stat)(struct ucred *cred, struct pipe *pipe, - struct label *pipelabel); - int (*mpo_check_pipe_write)(struct ucred *cred, struct pipe *pipe, - struct label *pipelabel); + int (*mpo_check_pipe_stat)(struct ucred *cred, + struct pipepair *pp, struct label *pipelabel); + int (*mpo_check_pipe_write)(struct ucred *cred, + struct pipepair *pp, struct label *pipelabel); int (*mpo_check_proc_debug)(struct ucred *cred, struct proc *proc); int (*mpo_check_proc_sched)(struct ucred *cred, struct proc *proc); int (*mpo_check_proc_signal)(struct ucred *cred, struct proc *proc, int signum); int (*mpo_check_socket_bind)(struct ucred *cred, struct socket *so, struct label *socketlabel, struct sockaddr *sockaddr); int (*mpo_check_socket_connect)(struct ucred *cred, struct socket *so, struct label *socketlabel, struct sockaddr *sockaddr); int (*mpo_check_socket_deliver)(struct socket *so, struct label *socketlabel, struct mbuf *m, struct label *mbuflabel); int (*mpo_check_socket_listen)(struct ucred *cred, struct socket *so, struct label *socketlabel); int (*mpo_check_socket_receive)(struct ucred *cred, struct socket *so, struct label *socketlabel); int (*mpo_check_socket_relabel)(struct ucred *cred, struct socket *so, struct label *socketlabel, struct label *newlabel); int (*mpo_check_socket_send)(struct ucred *cred, struct socket *so, struct label *socketlabel); int (*mpo_check_socket_visible)(struct ucred *cred, struct socket *so, struct label *socketlabel); int (*mpo_check_sysarch_ioperm)(struct ucred *cred); int (*mpo_check_system_acct)(struct ucred *cred, struct vnode *vp, struct label *vlabel); int (*mpo_check_system_nfsd)(struct ucred *cred); int (*mpo_check_system_reboot)(struct ucred *cred, int howto); int (*mpo_check_system_settime)(struct ucred *cred); int (*mpo_check_system_swapon)(struct ucred *cred, struct vnode *vp, struct label *label); int (*mpo_check_system_swapoff)(struct ucred *cred, struct vnode *vp, struct label *label); int (*mpo_check_system_sysctl)(struct ucred *cred, int *name, u_int namelen, void *old, size_t *oldlenp, int inkernel, void *new, size_t newlen); int (*mpo_check_vnode_access)(struct ucred *cred, struct vnode *vp, struct label *label, int acc_mode); int (*mpo_check_vnode_chdir)(struct ucred *cred, struct vnode *dvp, struct label *dlabel); int (*mpo_check_vnode_chroot)(struct ucred *cred, struct vnode *dvp, struct label *dlabel); int (*mpo_check_vnode_create)(struct ucred *cred, struct vnode *dvp, struct label *dlabel, struct componentname *cnp, struct vattr *vap); int (*mpo_check_vnode_delete)(struct ucred *cred, struct vnode *dvp, struct label *dlabel, struct vnode *vp, struct label *label, struct componentname *cnp); int (*mpo_check_vnode_deleteacl)(struct ucred *cred, struct vnode *vp, struct label *label, acl_type_t type); int (*mpo_check_vnode_deleteextattr)(struct ucred *cred, struct vnode *vp, struct label *label, int attrnamespace, const char *name); int (*mpo_check_vnode_exec)(struct ucred *cred, struct vnode *vp, struct label *label, struct image_params *imgp, struct label *execlabel); int (*mpo_check_vnode_getacl)(struct ucred *cred, struct vnode *vp, struct label *label, acl_type_t type); int (*mpo_check_vnode_getextattr)(struct ucred *cred, struct vnode *vp, struct label *label, int attrnamespace, const char *name, struct uio *uio); int (*mpo_check_vnode_link)(struct ucred *cred, struct vnode *dvp, struct label *dlabel, struct vnode *vp, struct label *label, struct componentname *cnp); int (*mpo_check_vnode_listextattr)(struct ucred *cred, struct vnode *vp, struct label *label, int attrnamespace); int (*mpo_check_vnode_lookup)(struct ucred *cred, struct vnode *dvp, struct label *dlabel, struct componentname *cnp); int (*mpo_check_vnode_mmap)(struct ucred *cred, struct vnode *vp, struct label *label, int prot); void (*mpo_check_vnode_mmap_downgrade)(struct ucred *cred, struct vnode *vp, struct label *label, int *prot); int (*mpo_check_vnode_mprotect)(struct ucred *cred, struct vnode *vp, struct label *label, int prot); int (*mpo_check_vnode_open)(struct ucred *cred, struct vnode *vp, struct label *label, int acc_mode); int (*mpo_check_vnode_poll)(struct ucred *active_cred, struct ucred *file_cred, struct vnode *vp, struct label *label); int (*mpo_check_vnode_read)(struct ucred *active_cred, struct ucred *file_cred, struct vnode *vp, struct label *label); int (*mpo_check_vnode_readdir)(struct ucred *cred, struct vnode *dvp, struct label *dlabel); int (*mpo_check_vnode_readlink)(struct ucred *cred, struct vnode *vp, struct label *label); int (*mpo_check_vnode_relabel)(struct ucred *cred, struct vnode *vp, struct label *vnodelabel, struct label *newlabel); int (*mpo_check_vnode_rename_from)(struct ucred *cred, struct vnode *dvp, struct label *dlabel, struct vnode *vp, struct label *label, struct componentname *cnp); int (*mpo_check_vnode_rename_to)(struct ucred *cred, struct vnode *dvp, struct label *dlabel, struct vnode *vp, struct label *label, int samedir, struct componentname *cnp); int (*mpo_check_vnode_revoke)(struct ucred *cred, struct vnode *vp, struct label *label); int (*mpo_check_vnode_setacl)(struct ucred *cred, struct vnode *vp, struct label *label, acl_type_t type, struct acl *acl); int (*mpo_check_vnode_setextattr)(struct ucred *cred, struct vnode *vp, struct label *label, int attrnamespace, const char *name, struct uio *uio); int (*mpo_check_vnode_setflags)(struct ucred *cred, struct vnode *vp, struct label *label, u_long flags); int (*mpo_check_vnode_setmode)(struct ucred *cred, struct vnode *vp, struct label *label, mode_t mode); int (*mpo_check_vnode_setowner)(struct ucred *cred, struct vnode *vp, struct label *label, uid_t uid, gid_t gid); int (*mpo_check_vnode_setutimes)(struct ucred *cred, struct vnode *vp, struct label *label, struct timespec atime, struct timespec mtime); int (*mpo_check_vnode_stat)(struct ucred *active_cred, struct ucred *file_cred, struct vnode *vp, struct label *label); int (*mpo_check_vnode_write)(struct ucred *active_cred, struct ucred *file_cred, struct vnode *vp, struct label *label); }; struct mac_policy_conf { char *mpc_name; /* policy name */ char *mpc_fullname; /* policy full name */ struct mac_policy_ops *mpc_ops; /* policy operations */ int mpc_loadtime_flags; /* flags */ int *mpc_field_off; /* security field */ int mpc_runtime_flags; /* flags */ LIST_ENTRY(mac_policy_conf) mpc_list; /* global list */ }; /* Flags for the mpc_loadtime_flags field. */ #define MPC_LOADTIME_FLAG_NOTLATE 0x00000001 #define MPC_LOADTIME_FLAG_UNLOADOK 0x00000002 #define MPC_LOADTIME_FLAG_LABELMBUFS 0x00000004 /* Flags for the mpc_runtime_flags field. */ #define MPC_RUNTIME_FLAG_REGISTERED 0x00000001 #define MAC_POLICY_SET(mpops, mpname, mpfullname, mpflags, privdata_wanted) \ static struct mac_policy_conf mpname##_mac_policy_conf = { \ #mpname, \ mpfullname, \ mpops, \ mpflags, \ privdata_wanted, \ 0, \ }; \ static moduledata_t mpname##_mod = { \ #mpname, \ mac_policy_modevent, \ &mpname##_mac_policy_conf \ }; \ MODULE_DEPEND(mpname, kernel_mac_support, 1, 1, 1); \ DECLARE_MODULE(mpname, mpname##_mod, SI_SUB_MAC_POLICY, \ SI_ORDER_MIDDLE) int mac_policy_modevent(module_t mod, int type, void *data); #define LABEL_TO_SLOT(l, s) (l)->l_perpolicy[s] #endif /* !_SYS_MAC_POLICY_H */ Index: head/sys/sys/pipe.h =================================================================== --- head/sys/sys/pipe.h (revision 125292) +++ head/sys/sys/pipe.h (revision 125293) @@ -1,128 +1,139 @@ /* * Copyright (c) 1996 John S. Dyson * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice immediately at the beginning of the file, without modification, * this list of conditions, and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Absolutely no warranty of function or purpose is made by the author * John S. Dyson. * 4. This work was done expressly for inclusion into FreeBSD. Other use * is allowed if this notation is included. * 5. Modifications may be freely made to this file if the above conditions * are met. * * $FreeBSD$ */ #ifndef _SYS_PIPE_H_ #define _SYS_PIPE_H_ #ifndef _KERNEL #include /* for struct timespec */ #include /* for struct selinfo */ #include /* for vm_page_t */ #include /* for PAGE_SIZE */ #endif /* * Pipe buffer size, keep moderate in value, pipes take kva space. */ #ifndef PIPE_SIZE #define PIPE_SIZE 16384 #endif #ifndef BIG_PIPE_SIZE #define BIG_PIPE_SIZE (64*1024) #endif #ifndef SMALL_PIPE_SIZE #define SMALL_PIPE_SIZE PAGE_SIZE #endif /* * PIPE_MINDIRECT MUST be smaller than PIPE_SIZE and MUST be bigger * than PIPE_BUF. */ #ifndef PIPE_MINDIRECT #define PIPE_MINDIRECT 8192 #endif #define PIPENPAGES (BIG_PIPE_SIZE / PAGE_SIZE + 1) /* * See sys_pipe.c for info on what these limits mean. */ extern int maxpipekva; extern int maxpipekvawired; /* * Pipe buffer information. * Separate in, out, cnt are used to simplify calculations. * Buffered write is active when the buffer.cnt field is set. */ struct pipebuf { u_int cnt; /* number of chars currently in buffer */ u_int in; /* in pointer */ u_int out; /* out pointer */ u_int size; /* size of buffer */ caddr_t buffer; /* kva of buffer */ }; /* * Information to support direct transfers between processes for pipes. */ struct pipemapping { vm_offset_t kva; /* kernel virtual address */ vm_size_t cnt; /* number of chars in buffer */ vm_size_t pos; /* current position of transfer */ int npages; /* number of pages */ vm_page_t ms[PIPENPAGES]; /* pages in source process */ }; /* * Bits in pipe_state. */ #define PIPE_ASYNC 0x004 /* Async? I/O. */ #define PIPE_WANTR 0x008 /* Reader wants some characters. */ #define PIPE_WANTW 0x010 /* Writer wants space to put characters. */ #define PIPE_WANT 0x020 /* Pipe is wanted to be run-down. */ #define PIPE_SEL 0x040 /* Pipe has a select active. */ #define PIPE_EOF 0x080 /* Pipe is in EOF condition. */ #define PIPE_LOCKFL 0x100 /* Process has exclusive access to pointers/data. */ #define PIPE_LWANT 0x200 /* Process wants exclusive access to pointers/data. */ #define PIPE_DIRECTW 0x400 /* Pipe direct write active. */ #define PIPE_DIRECTOK 0x800 /* Direct mode ok. */ /* * Per-pipe data structure. * Two of these are linked together to produce bi-directional pipes. */ struct pipe { struct pipebuf pipe_buffer; /* data storage */ struct pipemapping pipe_map; /* pipe mapping for direct I/O */ struct selinfo pipe_sel; /* for compat with select */ struct timespec pipe_atime; /* time of last access */ struct timespec pipe_mtime; /* time of last modify */ struct timespec pipe_ctime; /* time of status change */ struct sigio *pipe_sigio; /* information for async I/O */ struct pipe *pipe_peer; /* link with other direction */ + struct pipepair *pipe_pair; /* container structure pointer */ u_int pipe_state; /* pipe status info */ int pipe_busy; /* busy flag, mostly to handle rundown sanely */ - struct label *pipe_label; /* pipe MAC label - shared */ - struct mtx *pipe_mtxp; /* shared mutex between both pipes */ + int pipe_present; /* still present? */ }; -#define PIPE_MTX(pipe) (pipe)->pipe_mtxp +/* + * Container structure to hold the two pipe endpoints, mutex, and label + * pointer. + */ +struct pipepair { + struct pipe pp_rpipe; + struct pipe pp_wpipe; + struct mtx pp_mtx; + struct label *pp_label; +}; + +#define PIPE_MTX(pipe) (&(pipe)->pipe_pair->pp_mtx) #define PIPE_LOCK(pipe) mtx_lock(PIPE_MTX(pipe)) #define PIPE_UNLOCK(pipe) mtx_unlock(PIPE_MTX(pipe)) #define PIPE_LOCK_ASSERT(pipe, type) mtx_assert(PIPE_MTX(pipe), (type)) #endif /* !_SYS_PIPE_H_ */