Index: head/sys/kern/kern_prot.c =================================================================== --- head/sys/kern/kern_prot.c (revision 123172) +++ head/sys/kern/kern_prot.c (revision 123173) @@ -1,2036 +1,2036 @@ /* * Copyright (c) 1982, 1986, 1989, 1990, 1991, 1993 * The Regents of the University of California. All rights reserved. * (c) UNIX System Laboratories, Inc. * All or some portions of this file are derived from material licensed * to the University of California by American Telephone and Telegraph * Co. or Unix System Laboratories, Inc. and are reproduced herein with * the permission of UNIX System Laboratories, Inc. * Copyright (c) 2000-2001 Robert N. M. Watson. 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, 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. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. * * @(#)kern_prot.c 8.6 (Berkeley) 1/21/94 */ /* * System calls related to processes and protection */ #include __FBSDID("$FreeBSD$"); #include "opt_compat.h" #include "opt_mac.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static MALLOC_DEFINE(M_CRED, "cred", "credentials"); SYSCTL_DECL(_security); SYSCTL_NODE(_security, OID_AUTO, bsd, CTLFLAG_RW, 0, "BSD security policy"); #ifndef _SYS_SYSPROTO_H_ struct getpid_args { int dummy; }; #endif /* * MPSAFE */ /* ARGSUSED */ int getpid(struct thread *td, struct getpid_args *uap) { struct proc *p = td->td_proc; td->td_retval[0] = p->p_pid; #if defined(COMPAT_43) || defined(COMPAT_SUNOS) PROC_LOCK(p); td->td_retval[1] = p->p_pptr->p_pid; PROC_UNLOCK(p); #endif return (0); } #ifndef _SYS_SYSPROTO_H_ struct getppid_args { int dummy; }; #endif /* * MPSAFE */ /* ARGSUSED */ int getppid(struct thread *td, struct getppid_args *uap) { struct proc *p = td->td_proc; PROC_LOCK(p); td->td_retval[0] = p->p_pptr->p_pid; PROC_UNLOCK(p); return (0); } /* * Get process group ID; note that POSIX getpgrp takes no parameter. */ #ifndef _SYS_SYSPROTO_H_ struct getpgrp_args { int dummy; }; #endif /* * MPSAFE */ int getpgrp(struct thread *td, struct getpgrp_args *uap) { struct proc *p = td->td_proc; PROC_LOCK(p); td->td_retval[0] = p->p_pgrp->pg_id; PROC_UNLOCK(p); return (0); } /* Get an arbitary pid's process group id */ #ifndef _SYS_SYSPROTO_H_ struct getpgid_args { pid_t pid; }; #endif /* * MPSAFE */ int getpgid(struct thread *td, struct getpgid_args *uap) { struct proc *p; int error; if (uap->pid == 0) { p = td->td_proc; PROC_LOCK(p); } else { p = pfind(uap->pid); if (p == NULL) return (ESRCH); error = p_cansee(td, p); if (error) { PROC_UNLOCK(p); return (error); } } td->td_retval[0] = p->p_pgrp->pg_id; PROC_UNLOCK(p); return (0); } /* * Get an arbitary pid's session id. */ #ifndef _SYS_SYSPROTO_H_ struct getsid_args { pid_t pid; }; #endif /* * MPSAFE */ int getsid(struct thread *td, struct getsid_args *uap) { struct proc *p; int error; if (uap->pid == 0) { p = td->td_proc; PROC_LOCK(p); } else { p = pfind(uap->pid); if (p == NULL) return (ESRCH); error = p_cansee(td, p); if (error) { PROC_UNLOCK(p); return (error); } } td->td_retval[0] = p->p_session->s_sid; PROC_UNLOCK(p); return (0); } #ifndef _SYS_SYSPROTO_H_ struct getuid_args { int dummy; }; #endif /* * MPSAFE */ /* ARGSUSED */ int getuid(struct thread *td, struct getuid_args *uap) { td->td_retval[0] = td->td_ucred->cr_ruid; #if defined(COMPAT_43) || defined(COMPAT_SUNOS) td->td_retval[1] = td->td_ucred->cr_uid; #endif return (0); } #ifndef _SYS_SYSPROTO_H_ struct geteuid_args { int dummy; }; #endif /* * MPSAFE */ /* ARGSUSED */ int geteuid(struct thread *td, struct geteuid_args *uap) { td->td_retval[0] = td->td_ucred->cr_uid; return (0); } #ifndef _SYS_SYSPROTO_H_ struct getgid_args { int dummy; }; #endif /* * MPSAFE */ /* ARGSUSED */ int getgid(struct thread *td, struct getgid_args *uap) { td->td_retval[0] = td->td_ucred->cr_rgid; #if defined(COMPAT_43) || defined(COMPAT_SUNOS) td->td_retval[1] = td->td_ucred->cr_groups[0]; #endif return (0); } /* * Get effective group ID. The "egid" is groups[0], and could be obtained * via getgroups. This syscall exists because it is somewhat painful to do * correctly in a library function. */ #ifndef _SYS_SYSPROTO_H_ struct getegid_args { int dummy; }; #endif /* * MPSAFE */ /* ARGSUSED */ int getegid(struct thread *td, struct getegid_args *uap) { td->td_retval[0] = td->td_ucred->cr_groups[0]; return (0); } #ifndef _SYS_SYSPROTO_H_ struct getgroups_args { u_int gidsetsize; gid_t *gidset; }; #endif /* * MPSAFE */ int getgroups(struct thread *td, register struct getgroups_args *uap) { struct ucred *cred; u_int ngrp; int error; cred = td->td_ucred; if ((ngrp = uap->gidsetsize) == 0) { td->td_retval[0] = cred->cr_ngroups; return (0); } if (ngrp < cred->cr_ngroups) return (EINVAL); ngrp = cred->cr_ngroups; error = copyout(cred->cr_groups, uap->gidset, ngrp * sizeof(gid_t)); if (error == 0) td->td_retval[0] = ngrp; return (error); } #ifndef _SYS_SYSPROTO_H_ struct setsid_args { int dummy; }; #endif /* * MPSAFE */ /* ARGSUSED */ int setsid(register struct thread *td, struct setsid_args *uap) { struct pgrp *pgrp; int error; struct proc *p = td->td_proc; struct pgrp *newpgrp; struct session *newsess; error = 0; pgrp = NULL; MALLOC(newpgrp, struct pgrp *, sizeof(struct pgrp), M_PGRP, M_WAITOK | M_ZERO); MALLOC(newsess, struct session *, sizeof(struct session), M_SESSION, M_WAITOK | M_ZERO); sx_xlock(&proctree_lock); if (p->p_pgid == p->p_pid || (pgrp = pgfind(p->p_pid)) != NULL) { if (pgrp != NULL) PGRP_UNLOCK(pgrp); error = EPERM; } else { (void)enterpgrp(p, p->p_pid, newpgrp, newsess); td->td_retval[0] = p->p_pid; newpgrp = NULL; newsess = NULL; } sx_xunlock(&proctree_lock); if (newpgrp != NULL) FREE(newpgrp, M_PGRP); if (newsess != NULL) FREE(newsess, M_SESSION); return (error); } /* * set process group (setpgid/old setpgrp) * * caller does setpgid(targpid, targpgid) * * pid must be caller or child of caller (ESRCH) * if a child * pid must be in same session (EPERM) * pid can't have done an exec (EACCES) * if pgid != pid * there must exist some pid in same session having pgid (EPERM) * pid must not be session leader (EPERM) */ #ifndef _SYS_SYSPROTO_H_ struct setpgid_args { int pid; /* target process id */ int pgid; /* target pgrp id */ }; #endif /* * MPSAFE */ /* ARGSUSED */ int setpgid(struct thread *td, register struct setpgid_args *uap) { struct proc *curp = td->td_proc; register struct proc *targp; /* target process */ register struct pgrp *pgrp; /* target pgrp */ int error; struct pgrp *newpgrp; if (uap->pgid < 0) return (EINVAL); error = 0; MALLOC(newpgrp, struct pgrp *, sizeof(struct pgrp), M_PGRP, M_WAITOK | M_ZERO); sx_xlock(&proctree_lock); if (uap->pid != 0 && uap->pid != curp->p_pid) { if ((targp = pfind(uap->pid)) == NULL) { error = ESRCH; goto done; } if (!inferior(targp)) { PROC_UNLOCK(targp); error = ESRCH; goto done; } if ((error = p_cansee(curthread, targp))) { PROC_UNLOCK(targp); goto done; } if (targp->p_pgrp == NULL || targp->p_session != curp->p_session) { PROC_UNLOCK(targp); error = EPERM; goto done; } if (targp->p_flag & P_EXEC) { PROC_UNLOCK(targp); error = EACCES; goto done; } PROC_UNLOCK(targp); } else targp = curp; if (SESS_LEADER(targp)) { error = EPERM; goto done; } if (uap->pgid == 0) uap->pgid = targp->p_pid; if ((pgrp = pgfind(uap->pgid)) == NULL) { if (uap->pgid == targp->p_pid) { error = enterpgrp(targp, uap->pgid, newpgrp, NULL); if (error == 0) newpgrp = NULL; } else error = EPERM; } else { if (pgrp == targp->p_pgrp) { PGRP_UNLOCK(pgrp); goto done; } if (pgrp->pg_id != targp->p_pid && pgrp->pg_session != curp->p_session) { PGRP_UNLOCK(pgrp); error = EPERM; goto done; } PGRP_UNLOCK(pgrp); error = enterthispgrp(targp, pgrp); } done: sx_xunlock(&proctree_lock); KASSERT((error == 0) || (newpgrp != NULL), ("setpgid failed and newpgrp is NULL")); if (newpgrp != NULL) FREE(newpgrp, M_PGRP); return (error); } /* * Use the clause in B.4.2.2 that allows setuid/setgid to be 4.2/4.3BSD * compatible. It says that setting the uid/gid to euid/egid is a special * case of "appropriate privilege". Once the rules are expanded out, this * basically means that setuid(nnn) sets all three id's, in all permitted * cases unless _POSIX_SAVED_IDS is enabled. In that case, setuid(getuid()) * does not set the saved id - this is dangerous for traditional BSD * programs. For this reason, we *really* do not want to set * _POSIX_SAVED_IDS and do not want to clear POSIX_APPENDIX_B_4_2_2. */ #define POSIX_APPENDIX_B_4_2_2 #ifndef _SYS_SYSPROTO_H_ struct setuid_args { uid_t uid; }; #endif /* * MPSAFE */ /* ARGSUSED */ int setuid(struct thread *td, struct setuid_args *uap) { struct proc *p = td->td_proc; struct ucred *newcred, *oldcred; uid_t uid; struct uidinfo *uip; int error; uid = uap->uid; newcred = crget(); uip = uifind(uid); PROC_LOCK(p); oldcred = p->p_ucred; /* * See if we have "permission" by POSIX 1003.1 rules. * * Note that setuid(geteuid()) is a special case of * "appropriate privileges" in appendix B.4.2.2. We need * to use this clause to be compatible with traditional BSD * semantics. Basically, it means that "setuid(xx)" sets all * three id's (assuming you have privs). * * Notes on the logic. We do things in three steps. * 1: We determine if the euid is going to change, and do EPERM * right away. We unconditionally change the euid later if this * test is satisfied, simplifying that part of the logic. * 2: We determine if the real and/or saved uids are going to * change. Determined by compile options. * 3: Change euid last. (after tests in #2 for "appropriate privs") */ if (uid != oldcred->cr_ruid && /* allow setuid(getuid()) */ #ifdef _POSIX_SAVED_IDS uid != oldcred->cr_svuid && /* allow setuid(saved gid) */ #endif #ifdef POSIX_APPENDIX_B_4_2_2 /* Use BSD-compat clause from B.4.2.2 */ uid != oldcred->cr_uid && /* allow setuid(geteuid()) */ #endif (error = suser_cred(oldcred, PRISON_ROOT)) != 0) { PROC_UNLOCK(p); uifree(uip); crfree(newcred); return (error); } /* * Copy credentials so other references do not see our changes. */ crcopy(newcred, oldcred); #ifdef _POSIX_SAVED_IDS /* * Do we have "appropriate privileges" (are we root or uid == euid) * If so, we are changing the real uid and/or saved uid. */ if ( #ifdef POSIX_APPENDIX_B_4_2_2 /* Use the clause from B.4.2.2 */ uid == oldcred->cr_uid || #endif suser_cred(oldcred, PRISON_ROOT) == 0) /* we are using privs */ #endif { /* * Set the real uid and transfer proc count to new user. */ if (uid != oldcred->cr_ruid) { change_ruid(newcred, uip); setsugid(p); } /* * Set saved uid * * XXX always set saved uid even if not _POSIX_SAVED_IDS, as * the security of seteuid() depends on it. B.4.2.2 says it * is important that we should do this. */ if (uid != oldcred->cr_svuid) { change_svuid(newcred, uid); setsugid(p); } } /* * In all permitted cases, we are changing the euid. */ if (uid != oldcred->cr_uid) { change_euid(newcred, uip); setsugid(p); } p->p_ucred = newcred; PROC_UNLOCK(p); uifree(uip); crfree(oldcred); return (0); } #ifndef _SYS_SYSPROTO_H_ struct seteuid_args { uid_t euid; }; #endif /* * MPSAFE */ /* ARGSUSED */ int seteuid(struct thread *td, struct seteuid_args *uap) { struct proc *p = td->td_proc; struct ucred *newcred, *oldcred; uid_t euid; struct uidinfo *euip; int error; euid = uap->euid; newcred = crget(); euip = uifind(euid); PROC_LOCK(p); oldcred = p->p_ucred; if (euid != oldcred->cr_ruid && /* allow seteuid(getuid()) */ euid != oldcred->cr_svuid && /* allow seteuid(saved uid) */ (error = suser_cred(oldcred, PRISON_ROOT)) != 0) { PROC_UNLOCK(p); uifree(euip); crfree(newcred); return (error); } /* * Everything's okay, do it. Copy credentials so other references do * not see our changes. */ crcopy(newcred, oldcred); if (oldcred->cr_uid != euid) { change_euid(newcred, euip); setsugid(p); } p->p_ucred = newcred; PROC_UNLOCK(p); uifree(euip); crfree(oldcred); return (0); } #ifndef _SYS_SYSPROTO_H_ struct setgid_args { gid_t gid; }; #endif /* * MPSAFE */ /* ARGSUSED */ int setgid(struct thread *td, struct setgid_args *uap) { struct proc *p = td->td_proc; struct ucred *newcred, *oldcred; gid_t gid; int error; gid = uap->gid; newcred = crget(); PROC_LOCK(p); oldcred = p->p_ucred; /* * See if we have "permission" by POSIX 1003.1 rules. * * Note that setgid(getegid()) is a special case of * "appropriate privileges" in appendix B.4.2.2. We need * to use this clause to be compatible with traditional BSD * semantics. Basically, it means that "setgid(xx)" sets all * three id's (assuming you have privs). * * For notes on the logic here, see setuid() above. */ if (gid != oldcred->cr_rgid && /* allow setgid(getgid()) */ #ifdef _POSIX_SAVED_IDS gid != oldcred->cr_svgid && /* allow setgid(saved gid) */ #endif #ifdef POSIX_APPENDIX_B_4_2_2 /* Use BSD-compat clause from B.4.2.2 */ gid != oldcred->cr_groups[0] && /* allow setgid(getegid()) */ #endif (error = suser_cred(oldcred, PRISON_ROOT)) != 0) { PROC_UNLOCK(p); crfree(newcred); return (error); } crcopy(newcred, oldcred); #ifdef _POSIX_SAVED_IDS /* * Do we have "appropriate privileges" (are we root or gid == egid) * If so, we are changing the real uid and saved gid. */ if ( #ifdef POSIX_APPENDIX_B_4_2_2 /* use the clause from B.4.2.2 */ gid == oldcred->cr_groups[0] || #endif suser_cred(oldcred, PRISON_ROOT) == 0) /* we are using privs */ #endif { /* * Set real gid */ if (oldcred->cr_rgid != gid) { change_rgid(newcred, gid); setsugid(p); } /* * Set saved gid * * XXX always set saved gid even if not _POSIX_SAVED_IDS, as * the security of setegid() depends on it. B.4.2.2 says it * is important that we should do this. */ if (oldcred->cr_svgid != gid) { change_svgid(newcred, gid); setsugid(p); } } /* * In all cases permitted cases, we are changing the egid. * Copy credentials so other references do not see our changes. */ if (oldcred->cr_groups[0] != gid) { change_egid(newcred, gid); setsugid(p); } p->p_ucred = newcred; PROC_UNLOCK(p); crfree(oldcred); return (0); } #ifndef _SYS_SYSPROTO_H_ struct setegid_args { gid_t egid; }; #endif /* * MPSAFE */ /* ARGSUSED */ int setegid(struct thread *td, struct setegid_args *uap) { struct proc *p = td->td_proc; struct ucred *newcred, *oldcred; gid_t egid; int error; egid = uap->egid; newcred = crget(); PROC_LOCK(p); oldcred = p->p_ucred; if (egid != oldcred->cr_rgid && /* allow setegid(getgid()) */ egid != oldcred->cr_svgid && /* allow setegid(saved gid) */ (error = suser_cred(oldcred, PRISON_ROOT)) != 0) { PROC_UNLOCK(p); crfree(newcred); return (error); } crcopy(newcred, oldcred); if (oldcred->cr_groups[0] != egid) { change_egid(newcred, egid); setsugid(p); } p->p_ucred = newcred; PROC_UNLOCK(p); crfree(oldcred); return (0); } #ifndef _SYS_SYSPROTO_H_ struct setgroups_args { u_int gidsetsize; gid_t *gidset; }; #endif /* * MPSAFE */ /* ARGSUSED */ int setgroups(struct thread *td, struct setgroups_args *uap) { struct proc *p = td->td_proc; struct ucred *newcred, *tempcred, *oldcred; u_int ngrp; int error; ngrp = uap->gidsetsize; if (ngrp > NGROUPS) return (EINVAL); tempcred = crget(); error = copyin(uap->gidset, tempcred->cr_groups, ngrp * sizeof(gid_t)); if (error != 0) { crfree(tempcred); return (error); } newcred = crget(); PROC_LOCK(p); oldcred = p->p_ucred; error = suser_cred(oldcred, PRISON_ROOT); if (error) { PROC_UNLOCK(p); crfree(newcred); crfree(tempcred); return (error); } /* * XXX A little bit lazy here. We could test if anything has * changed before crcopy() and setting P_SUGID. */ crcopy(newcred, oldcred); if (ngrp < 1) { /* * setgroups(0, NULL) is a legitimate way of clearing the * groups vector on non-BSD systems (which generally do not * have the egid in the groups[0]). We risk security holes * when running non-BSD software if we do not do the same. */ newcred->cr_ngroups = 1; } else { bcopy(tempcred->cr_groups, newcred->cr_groups, ngrp * sizeof(gid_t)); newcred->cr_ngroups = ngrp; } setsugid(p); p->p_ucred = newcred; PROC_UNLOCK(p); crfree(tempcred); crfree(oldcred); return (0); } #ifndef _SYS_SYSPROTO_H_ struct setreuid_args { uid_t ruid; uid_t euid; }; #endif /* * MPSAFE */ /* ARGSUSED */ int setreuid(register struct thread *td, struct setreuid_args *uap) { struct proc *p = td->td_proc; struct ucred *newcred, *oldcred; uid_t euid, ruid; struct uidinfo *euip, *ruip; int error; euid = uap->euid; ruid = uap->ruid; newcred = crget(); euip = uifind(euid); ruip = uifind(ruid); PROC_LOCK(p); oldcred = p->p_ucred; if (((ruid != (uid_t)-1 && ruid != oldcred->cr_ruid && ruid != oldcred->cr_svuid) || (euid != (uid_t)-1 && euid != oldcred->cr_uid && euid != oldcred->cr_ruid && euid != oldcred->cr_svuid)) && (error = suser_cred(oldcred, PRISON_ROOT)) != 0) { PROC_UNLOCK(p); uifree(ruip); uifree(euip); crfree(newcred); return (error); } crcopy(newcred, oldcred); if (euid != (uid_t)-1 && oldcred->cr_uid != euid) { change_euid(newcred, euip); setsugid(p); } if (ruid != (uid_t)-1 && oldcred->cr_ruid != ruid) { change_ruid(newcred, ruip); setsugid(p); } if ((ruid != (uid_t)-1 || newcred->cr_uid != newcred->cr_ruid) && newcred->cr_svuid != newcred->cr_uid) { change_svuid(newcred, newcred->cr_uid); setsugid(p); } p->p_ucred = newcred; PROC_UNLOCK(p); uifree(ruip); uifree(euip); crfree(oldcred); return (0); } #ifndef _SYS_SYSPROTO_H_ struct setregid_args { gid_t rgid; gid_t egid; }; #endif /* * MPSAFE */ /* ARGSUSED */ int setregid(register struct thread *td, struct setregid_args *uap) { struct proc *p = td->td_proc; struct ucred *newcred, *oldcred; gid_t egid, rgid; int error; egid = uap->egid; rgid = uap->rgid; newcred = crget(); PROC_LOCK(p); oldcred = p->p_ucred; if (((rgid != (gid_t)-1 && rgid != oldcred->cr_rgid && rgid != oldcred->cr_svgid) || (egid != (gid_t)-1 && egid != oldcred->cr_groups[0] && egid != oldcred->cr_rgid && egid != oldcred->cr_svgid)) && (error = suser_cred(oldcred, PRISON_ROOT)) != 0) { PROC_UNLOCK(p); crfree(newcred); return (error); } crcopy(newcred, oldcred); if (egid != (gid_t)-1 && oldcred->cr_groups[0] != egid) { change_egid(newcred, egid); setsugid(p); } if (rgid != (gid_t)-1 && oldcred->cr_rgid != rgid) { change_rgid(newcred, rgid); setsugid(p); } if ((rgid != (gid_t)-1 || newcred->cr_groups[0] != newcred->cr_rgid) && newcred->cr_svgid != newcred->cr_groups[0]) { change_svgid(newcred, newcred->cr_groups[0]); setsugid(p); } p->p_ucred = newcred; PROC_UNLOCK(p); crfree(oldcred); return (0); } /* * setresuid(ruid, euid, suid) is like setreuid except control over the * saved uid is explicit. */ #ifndef _SYS_SYSPROTO_H_ struct setresuid_args { uid_t ruid; uid_t euid; uid_t suid; }; #endif /* * MPSAFE */ /* ARGSUSED */ int setresuid(register struct thread *td, struct setresuid_args *uap) { struct proc *p = td->td_proc; struct ucred *newcred, *oldcred; uid_t euid, ruid, suid; struct uidinfo *euip, *ruip; int error; euid = uap->euid; ruid = uap->ruid; suid = uap->suid; newcred = crget(); euip = uifind(euid); ruip = uifind(ruid); PROC_LOCK(p); oldcred = p->p_ucred; if (((ruid != (uid_t)-1 && ruid != oldcred->cr_ruid && ruid != oldcred->cr_svuid && ruid != oldcred->cr_uid) || (euid != (uid_t)-1 && euid != oldcred->cr_ruid && euid != oldcred->cr_svuid && euid != oldcred->cr_uid) || (suid != (uid_t)-1 && suid != oldcred->cr_ruid && suid != oldcred->cr_svuid && suid != oldcred->cr_uid)) && (error = suser_cred(oldcred, PRISON_ROOT)) != 0) { PROC_UNLOCK(p); uifree(ruip); uifree(euip); crfree(newcred); return (error); } crcopy(newcred, oldcred); if (euid != (uid_t)-1 && oldcred->cr_uid != euid) { change_euid(newcred, euip); setsugid(p); } if (ruid != (uid_t)-1 && oldcred->cr_ruid != ruid) { change_ruid(newcred, ruip); setsugid(p); } if (suid != (uid_t)-1 && oldcred->cr_svuid != suid) { change_svuid(newcred, suid); setsugid(p); } p->p_ucred = newcred; PROC_UNLOCK(p); uifree(ruip); uifree(euip); crfree(oldcred); return (0); } /* * setresgid(rgid, egid, sgid) is like setregid except control over the * saved gid is explicit. */ #ifndef _SYS_SYSPROTO_H_ struct setresgid_args { gid_t rgid; gid_t egid; gid_t sgid; }; #endif /* * MPSAFE */ /* ARGSUSED */ int setresgid(register struct thread *td, struct setresgid_args *uap) { struct proc *p = td->td_proc; struct ucred *newcred, *oldcred; gid_t egid, rgid, sgid; int error; egid = uap->egid; rgid = uap->rgid; sgid = uap->sgid; newcred = crget(); PROC_LOCK(p); oldcred = p->p_ucred; if (((rgid != (gid_t)-1 && rgid != oldcred->cr_rgid && rgid != oldcred->cr_svgid && rgid != oldcred->cr_groups[0]) || (egid != (gid_t)-1 && egid != oldcred->cr_rgid && egid != oldcred->cr_svgid && egid != oldcred->cr_groups[0]) || (sgid != (gid_t)-1 && sgid != oldcred->cr_rgid && sgid != oldcred->cr_svgid && sgid != oldcred->cr_groups[0])) && (error = suser_cred(oldcred, PRISON_ROOT)) != 0) { PROC_UNLOCK(p); crfree(newcred); return (error); } crcopy(newcred, oldcred); if (egid != (gid_t)-1 && oldcred->cr_groups[0] != egid) { change_egid(newcred, egid); setsugid(p); } if (rgid != (gid_t)-1 && oldcred->cr_rgid != rgid) { change_rgid(newcred, rgid); setsugid(p); } if (sgid != (gid_t)-1 && oldcred->cr_svgid != sgid) { change_svgid(newcred, sgid); setsugid(p); } p->p_ucred = newcred; PROC_UNLOCK(p); crfree(oldcred); return (0); } #ifndef _SYS_SYSPROTO_H_ struct getresuid_args { uid_t *ruid; uid_t *euid; uid_t *suid; }; #endif /* * MPSAFE */ /* ARGSUSED */ int getresuid(register struct thread *td, struct getresuid_args *uap) { struct ucred *cred; int error1 = 0, error2 = 0, error3 = 0; cred = td->td_ucred; if (uap->ruid) error1 = copyout(&cred->cr_ruid, uap->ruid, sizeof(cred->cr_ruid)); if (uap->euid) error2 = copyout(&cred->cr_uid, uap->euid, sizeof(cred->cr_uid)); if (uap->suid) error3 = copyout(&cred->cr_svuid, uap->suid, sizeof(cred->cr_svuid)); return (error1 ? error1 : error2 ? error2 : error3); } #ifndef _SYS_SYSPROTO_H_ struct getresgid_args { gid_t *rgid; gid_t *egid; gid_t *sgid; }; #endif /* * MPSAFE */ /* ARGSUSED */ int getresgid(register struct thread *td, struct getresgid_args *uap) { struct ucred *cred; int error1 = 0, error2 = 0, error3 = 0; cred = td->td_ucred; if (uap->rgid) error1 = copyout(&cred->cr_rgid, uap->rgid, sizeof(cred->cr_rgid)); if (uap->egid) error2 = copyout(&cred->cr_groups[0], uap->egid, sizeof(cred->cr_groups[0])); if (uap->sgid) error3 = copyout(&cred->cr_svgid, uap->sgid, sizeof(cred->cr_svgid)); return (error1 ? error1 : error2 ? error2 : error3); } #ifndef _SYS_SYSPROTO_H_ struct issetugid_args { int dummy; }; #endif /* * MPSAFE */ /* ARGSUSED */ int issetugid(register struct thread *td, struct issetugid_args *uap) { struct proc *p = td->td_proc; /* * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time, * we use P_SUGID because we consider changing the owners as * "tainting" as well. * This is significant for procs that start as root and "become" * a user without an exec - programs cannot know *everything* * that libc *might* have put in their data segment. */ PROC_LOCK(p); td->td_retval[0] = (p->p_flag & P_SUGID) ? 1 : 0; PROC_UNLOCK(p); return (0); } /* * MPSAFE */ int __setugid(struct thread *td, struct __setugid_args *uap) { #ifdef REGRESSION struct proc *p; p = td->td_proc; switch (uap->flag) { case 0: PROC_LOCK(p); p->p_flag &= ~P_SUGID; PROC_UNLOCK(p); return (0); case 1: PROC_LOCK(p); p->p_flag |= P_SUGID; PROC_UNLOCK(p); return (0); default: return (EINVAL); } #else /* !REGRESSION */ return (ENOSYS); #endif /* REGRESSION */ } /* * Check if gid is a member of the group set. * * MPSAFE (cred must be held) */ int groupmember(gid_t gid, struct ucred *cred) { register gid_t *gp; gid_t *egp; egp = &(cred->cr_groups[cred->cr_ngroups]); for (gp = cred->cr_groups; gp < egp; gp++) if (*gp == gid) return (1); return (0); } /* * `suser_enabled' (which can be set by the security.suser_enabled * sysctl) determines whether the system 'super-user' policy is in effect. * If it is nonzero, an effective uid of 0 connotes special privilege, * overriding many mandatory and discretionary protections. If it is zero, * uid 0 is offered no special privilege in the kernel security policy. * Setting it to zero may seriously impact the functionality of many * existing userland programs, and should not be done without careful * consideration of the consequences. */ int suser_enabled = 1; SYSCTL_INT(_security_bsd, OID_AUTO, suser_enabled, CTLFLAG_RW, &suser_enabled, 0, "processes with uid 0 have privilege"); TUNABLE_INT("security.bsd.suser_enabled", &suser_enabled); /* * Test whether the specified credentials imply "super-user" privilege. * Return 0 or EPERM. The flag argument is currently used only to * specify jail interaction. */ int suser_cred(struct ucred *cred, int flag) { if (!suser_enabled) return (EPERM); if (cred->cr_uid != 0) return (EPERM); if (jailed(cred) && !(flag & PRISON_ROOT)) return (EPERM); return (0); } /* * Shortcut to hide contents of struct td and struct proc from the * caller, promoting binary compatibility. */ int suser(struct thread *td) { return (suser_cred(td->td_ucred, 0)); } /* * Test the active securelevel against a given level. securelevel_gt() * implements (securelevel > level). securelevel_ge() implements * (securelevel >= level). Note that the logic is inverted -- these * functions return EPERM on "success" and 0 on "failure". * * MPSAFE */ int securelevel_gt(struct ucred *cr, int level) { int active_securelevel; active_securelevel = securelevel; KASSERT(cr != NULL, ("securelevel_gt: null cr")); if (cr->cr_prison != NULL) { mtx_lock(&cr->cr_prison->pr_mtx); active_securelevel = imax(cr->cr_prison->pr_securelevel, active_securelevel); mtx_unlock(&cr->cr_prison->pr_mtx); } return (active_securelevel > level ? EPERM : 0); } int securelevel_ge(struct ucred *cr, int level) { int active_securelevel; active_securelevel = securelevel; KASSERT(cr != NULL, ("securelevel_ge: null cr")); if (cr->cr_prison != NULL) { mtx_lock(&cr->cr_prison->pr_mtx); active_securelevel = imax(cr->cr_prison->pr_securelevel, active_securelevel); mtx_unlock(&cr->cr_prison->pr_mtx); } return (active_securelevel >= level ? EPERM : 0); } /* * 'see_other_uids' determines whether or not visibility of processes * and sockets with credentials holding different real uids is possible * using a variety of system MIBs. * XXX: data declarations should be together near the beginning of the file. */ static int see_other_uids = 1; SYSCTL_INT(_security_bsd, OID_AUTO, see_other_uids, CTLFLAG_RW, &see_other_uids, 0, "Unprivileged processes may see subjects/objects with different real uid"); /*- * Determine if u1 "can see" the subject specified by u2, according to the * 'see_other_uids' policy. * Returns: 0 for permitted, ESRCH otherwise * Locks: none * References: *u1 and *u2 must not change during the call * u1 may equal u2, in which case only one reference is required */ static int cr_seeotheruids(struct ucred *u1, struct ucred *u2) { if (!see_other_uids && u1->cr_ruid != u2->cr_ruid) { if (suser_cred(u1, PRISON_ROOT) != 0) return (ESRCH); } return (0); } /* * 'see_other_gids' determines whether or not visibility of processes * and sockets with credentials holding different real gids is possible * using a variety of system MIBs. * XXX: data declarations should be together near the beginning of the file. */ static int see_other_gids = 1; SYSCTL_INT(_security_bsd, OID_AUTO, see_other_gids, CTLFLAG_RW, &see_other_gids, 0, "Unprivileged processes may see subjects/objects with different real gid"); /* * Determine if u1 can "see" the subject specified by u2, according to the * 'see_other_gids' policy. * Returns: 0 for permitted, ESRCH otherwise * Locks: none * References: *u1 and *u2 must not change during the call * u1 may equal u2, in which case only one reference is required */ static int cr_seeothergids(struct ucred *u1, struct ucred *u2) { int i, match; if (!see_other_gids) { match = 0; for (i = 0; i < u1->cr_ngroups; i++) { if (groupmember(u1->cr_groups[i], u2)) match = 1; if (match) break; } if (!match) { if (suser_cred(u1, PRISON_ROOT) != 0) return (ESRCH); } } return (0); } /*- * Determine if u1 "can see" the subject specified by u2. * Returns: 0 for permitted, an errno value otherwise * Locks: none * References: *u1 and *u2 must not change during the call * u1 may equal u2, in which case only one reference is required */ int cr_cansee(struct ucred *u1, struct ucred *u2) { int error; if ((error = prison_check(u1, u2))) return (error); #ifdef MAC if ((error = mac_check_cred_visible(u1, u2))) return (error); #endif if ((error = cr_seeotheruids(u1, u2))) return (error); if ((error = cr_seeothergids(u1, u2))) return (error); return (0); } /*- * Determine if td "can see" the subject specified by p. * Returns: 0 for permitted, an errno value otherwise * Locks: Sufficient locks to protect p->p_ucred must be held. td really * should be curthread. * References: td and p must be valid for the lifetime of the call */ int p_cansee(struct thread *td, struct proc *p) { /* Wrap cr_cansee() for all functionality. */ KASSERT(td == curthread, ("%s: td not curthread", __func__)); PROC_LOCK_ASSERT(p, MA_OWNED); return (cr_cansee(td->td_ucred, p->p_ucred)); } /* * 'conservative_signals' prevents the delivery of a broad class of * signals by unprivileged processes to processes that have changed their * credentials since the last invocation of execve(). This can prevent * the leakage of cached information or retained privileges as a result * of a common class of signal-related vulnerabilities. However, this * may interfere with some applications that expect to be able to * deliver these signals to peer processes after having given up * privilege. */ static int conservative_signals = 1; SYSCTL_INT(_security_bsd, OID_AUTO, conservative_signals, CTLFLAG_RW, &conservative_signals, 0, "Unprivileged processes prevented from " "sending certain signals to processes whose credentials have changed"); /*- * Determine whether cred may deliver the specified signal to proc. * Returns: 0 for permitted, an errno value otherwise. * Locks: A lock must be held for proc. * References: cred and proc must be valid for the lifetime of the call. */ int cr_cansignal(struct ucred *cred, struct proc *proc, int signum) { int error; PROC_LOCK_ASSERT(proc, MA_OWNED); /* * Jail semantics limit the scope of signalling to proc in the * same jail as cred, if cred is in jail. */ error = prison_check(cred, proc->p_ucred); if (error) return (error); #ifdef MAC if ((error = mac_check_proc_signal(cred, proc, signum))) return (error); #endif if ((error = cr_seeotheruids(cred, proc->p_ucred))) return (error); if ((error = cr_seeothergids(cred, proc->p_ucred))) return (error); /* * UNIX signal semantics depend on the status of the P_SUGID * bit on the target process. If the bit is set, then additional * restrictions are placed on the set of available signals. */ if (conservative_signals && (proc->p_flag & P_SUGID)) { switch (signum) { case 0: case SIGKILL: case SIGINT: case SIGTERM: case SIGALRM: case SIGSTOP: case SIGTTIN: case SIGTTOU: case SIGTSTP: case SIGHUP: case SIGUSR1: case SIGUSR2: /* * Generally, permit job and terminal control * signals. */ break; default: /* Not permitted without privilege. */ error = suser_cred(cred, PRISON_ROOT); if (error) return (error); } } /* * Generally, the target credential's ruid or svuid must match the * subject credential's ruid or euid. */ if (cred->cr_ruid != proc->p_ucred->cr_ruid && cred->cr_ruid != proc->p_ucred->cr_svuid && cred->cr_uid != proc->p_ucred->cr_ruid && cred->cr_uid != proc->p_ucred->cr_svuid) { /* Not permitted without privilege. */ error = suser_cred(cred, PRISON_ROOT); if (error) return (error); } return (0); } /*- * Determine whether td may deliver the specified signal to p. * Returns: 0 for permitted, an errno value otherwise * Locks: Sufficient locks to protect various components of td and p * must be held. td must be curthread, and a lock must be * held for p. * References: td and p must be valid for the lifetime of the call */ int p_cansignal(struct thread *td, struct proc *p, int signum) { KASSERT(td == curthread, ("%s: td not curthread", __func__)); PROC_LOCK_ASSERT(p, MA_OWNED); if (td->td_proc == p) return (0); /* * UNIX signalling semantics require that processes in the same * session always be able to deliver SIGCONT to one another, * overriding the remaining protections. */ /* XXX: This will require an additional lock of some sort. */ if (signum == SIGCONT && td->td_proc->p_session == p->p_session) return (0); return (cr_cansignal(td->td_ucred, p, signum)); } /*- * Determine whether td may reschedule p. * Returns: 0 for permitted, an errno value otherwise * Locks: Sufficient locks to protect various components of td and p * must be held. td must be curthread, and a lock must * be held for p. * References: td and p must be valid for the lifetime of the call */ int p_cansched(struct thread *td, struct proc *p) { int error; KASSERT(td == curthread, ("%s: td not curthread", __func__)); PROC_LOCK_ASSERT(p, MA_OWNED); if (td->td_proc == p) return (0); if ((error = prison_check(td->td_ucred, p->p_ucred))) return (error); #ifdef MAC if ((error = mac_check_proc_sched(td->td_ucred, p))) return (error); #endif if ((error = cr_seeotheruids(td->td_ucred, p->p_ucred))) return (error); if ((error = cr_seeothergids(td->td_ucred, p->p_ucred))) return (error); if (td->td_ucred->cr_ruid == p->p_ucred->cr_ruid) return (0); if (td->td_ucred->cr_uid == p->p_ucred->cr_ruid) return (0); if (suser_cred(td->td_ucred, PRISON_ROOT) == 0) return (0); #ifdef CAPABILITIES if (!cap_check(NULL, td, CAP_SYS_NICE, PRISON_ROOT)) return (0); #endif return (EPERM); } /* * The 'unprivileged_proc_debug' flag may be used to disable a variety of * unprivileged inter-process debugging services, including some procfs * functionality, ptrace(), and ktrace(). In the past, inter-process * debugging has been involved in a variety of security problems, and sites * not requiring the service might choose to disable it when hardening * systems. * * XXX: Should modifying and reading this variable require locking? * XXX: data declarations should be together near the beginning of the file. */ static int unprivileged_proc_debug = 1; SYSCTL_INT(_security_bsd, OID_AUTO, unprivileged_proc_debug, CTLFLAG_RW, &unprivileged_proc_debug, 0, "Unprivileged processes may use process debugging facilities"); /*- * Determine whether td may debug p. * Returns: 0 for permitted, an errno value otherwise * Locks: Sufficient locks to protect various components of td and p * must be held. td must be curthread, and a lock must * be held for p. * References: td and p must be valid for the lifetime of the call */ int p_candebug(struct thread *td, struct proc *p) { int credentialchanged, error, grpsubset, i, uidsubset; KASSERT(td == curthread, ("%s: td not curthread", __func__)); PROC_LOCK_ASSERT(p, MA_OWNED); if (!unprivileged_proc_debug) { error = suser_cred(td->td_ucred, PRISON_ROOT); if (error) return (error); } if (td->td_proc == p) return (0); if ((error = prison_check(td->td_ucred, p->p_ucred))) return (error); #ifdef MAC if ((error = mac_check_proc_debug(td->td_ucred, p))) return (error); #endif if ((error = cr_seeotheruids(td->td_ucred, p->p_ucred))) return (error); if ((error = cr_seeothergids(td->td_ucred, p->p_ucred))) return (error); /* * Is p's group set a subset of td's effective group set? This * includes p's egid, group access list, rgid, and svgid. */ grpsubset = 1; for (i = 0; i < p->p_ucred->cr_ngroups; i++) { if (!groupmember(p->p_ucred->cr_groups[i], td->td_ucred)) { grpsubset = 0; break; } } grpsubset = grpsubset && groupmember(p->p_ucred->cr_rgid, td->td_ucred) && groupmember(p->p_ucred->cr_svgid, td->td_ucred); /* * Are the uids present in p's credential equal to td's * effective uid? This includes p's euid, svuid, and ruid. */ uidsubset = (td->td_ucred->cr_uid == p->p_ucred->cr_uid && td->td_ucred->cr_uid == p->p_ucred->cr_svuid && td->td_ucred->cr_uid == p->p_ucred->cr_ruid); /* * Has the credential of the process changed since the last exec()? */ credentialchanged = (p->p_flag & P_SUGID); /* * If p's gids aren't a subset, or the uids aren't a subset, * or the credential has changed, require appropriate privilege * for td to debug p. For POSIX.1e capabilities, this will * require CAP_SYS_PTRACE. */ if (!grpsubset || !uidsubset || credentialchanged) { error = suser_cred(td->td_ucred, PRISON_ROOT); if (error) return (error); } /* Can't trace init when securelevel > 0. */ if (p == initproc) { error = securelevel_gt(td->td_ucred, 0); if (error) return (error); } /* * Can't trace a process that's currently exec'ing. * XXX: Note, this is not a security policy decision, it's a * basic correctness/functionality decision. Therefore, this check * should be moved to the caller's of p_candebug(). */ if ((p->p_flag & P_INEXEC) != 0) return (EAGAIN); return (0); } /*- * Determine whether the subject represented by cred can "see" a socket. * Returns: 0 for permitted, ENOENT otherwise. */ int cr_canseesocket(struct ucred *cred, struct socket *so) { int error; error = prison_check(cred, so->so_cred); if (error) return (ENOENT); #ifdef MAC error = mac_check_socket_visible(cred, so); if (error) return (error); #endif if (cr_seeotheruids(cred, so->so_cred)) return (ENOENT); if (cr_seeothergids(cred, so->so_cred)) return (ENOENT); return (0); } /* * Allocate a zeroed cred structure. * MPSAFE */ struct ucred * crget(void) { register struct ucred *cr; MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK | M_ZERO); cr->cr_ref = 1; cr->cr_mtxp = mtx_pool_find(mtxpool_sleep, cr); #ifdef MAC mac_init_cred(cr); #endif return (cr); } /* * Claim another reference to a ucred structure. * MPSAFE */ struct ucred * crhold(struct ucred *cr) { mtx_lock(cr->cr_mtxp); cr->cr_ref++; mtx_unlock(cr->cr_mtxp); return (cr); } /* * Free a cred structure. * Throws away space when ref count gets to 0. * MPSAFE */ void crfree(struct ucred *cr) { struct mtx *mtxp = cr->cr_mtxp; mtx_lock(mtxp); KASSERT(cr->cr_ref > 0, ("bad ucred refcount: %d", cr->cr_ref)); if (--cr->cr_ref == 0) { /* * Some callers of crget(), such as nfs_statfs(), * allocate a temporary credential, but don't * allocate a uidinfo structure. */ mtx_unlock(mtxp); mtx_lock(&Giant); if (cr->cr_uidinfo != NULL) uifree(cr->cr_uidinfo); if (cr->cr_ruidinfo != NULL) uifree(cr->cr_ruidinfo); /* * Free a prison, if any. */ if (jailed(cr)) prison_free(cr->cr_prison); #ifdef MAC mac_destroy_cred(cr); #endif FREE(cr, M_CRED); mtx_unlock(&Giant); } else { mtx_unlock(mtxp); } } /* * Check to see if this ucred is shared. * MPSAFE */ int crshared(struct ucred *cr) { int shared; mtx_lock(cr->cr_mtxp); shared = (cr->cr_ref > 1); mtx_unlock(cr->cr_mtxp); return (shared); } /* * Copy a ucred's contents from a template. Does not block. * MPSAFE */ void crcopy(struct ucred *dest, struct ucred *src) { KASSERT(crshared(dest) == 0, ("crcopy of shared ucred")); bcopy(&src->cr_startcopy, &dest->cr_startcopy, (unsigned)((caddr_t)&src->cr_endcopy - (caddr_t)&src->cr_startcopy)); uihold(dest->cr_uidinfo); uihold(dest->cr_ruidinfo); if (jailed(dest)) prison_hold(dest->cr_prison); #ifdef MAC - mac_create_cred(src, dest); + mac_copy_cred(src, dest); #endif } /* * Dup cred struct to a new held one. * MPSAFE */ struct ucred * crdup(struct ucred *cr) { struct ucred *newcr; newcr = crget(); crcopy(newcr, cr); return (newcr); } #ifdef DIAGNOSTIC void cred_free_thread(struct thread *td) { struct ucred *cred; cred = td->td_ucred; td->td_ucred = NULL; if (cred != NULL) crfree(cred); } #endif /* * Fill in a struct xucred based on a struct ucred. * MPSAFE */ void cru2x(struct ucred *cr, struct xucred *xcr) { bzero(xcr, sizeof(*xcr)); xcr->cr_version = XUCRED_VERSION; xcr->cr_uid = cr->cr_uid; xcr->cr_ngroups = cr->cr_ngroups; bcopy(cr->cr_groups, xcr->cr_groups, sizeof(cr->cr_groups)); } /* * small routine to swap a thread's current ucred for the correct one * taken from the process. * MPSAFE */ void cred_update_thread(struct thread *td) { struct proc *p; struct ucred *cred; p = td->td_proc; cred = td->td_ucred; PROC_LOCK(p); td->td_ucred = crhold(p->p_ucred); PROC_UNLOCK(p); if (cred != NULL) crfree(cred); } /* * Get login name, if available. */ #ifndef _SYS_SYSPROTO_H_ struct getlogin_args { char *namebuf; u_int namelen; }; #endif /* * MPSAFE */ /* ARGSUSED */ int getlogin(struct thread *td, struct getlogin_args *uap) { int error; char login[MAXLOGNAME]; struct proc *p = td->td_proc; if (uap->namelen > MAXLOGNAME) uap->namelen = MAXLOGNAME; PROC_LOCK(p); SESS_LOCK(p->p_session); bcopy(p->p_session->s_login, login, uap->namelen); SESS_UNLOCK(p->p_session); PROC_UNLOCK(p); error = copyout(login, uap->namebuf, uap->namelen); return(error); } /* * Set login name. */ #ifndef _SYS_SYSPROTO_H_ struct setlogin_args { char *namebuf; }; #endif /* * MPSAFE */ /* ARGSUSED */ int setlogin(struct thread *td, struct setlogin_args *uap) { struct proc *p = td->td_proc; int error; char logintmp[MAXLOGNAME]; error = suser_cred(td->td_ucred, PRISON_ROOT); if (error) return (error); error = copyinstr(uap->namebuf, logintmp, sizeof(logintmp), NULL); if (error == ENAMETOOLONG) error = EINVAL; else if (!error) { PROC_LOCK(p); SESS_LOCK(p->p_session); (void) memcpy(p->p_session->s_login, logintmp, sizeof(logintmp)); SESS_UNLOCK(p->p_session); PROC_UNLOCK(p); } return (error); } void setsugid(struct proc *p) { PROC_LOCK_ASSERT(p, MA_OWNED); p->p_flag |= P_SUGID; if (!(p->p_pfsflags & PF_ISUGID)) p->p_stops = 0; } /*- * Change a process's effective uid. * Side effects: newcred->cr_uid and newcred->cr_uidinfo will be modified. * References: newcred must be an exclusive credential reference for the * duration of the call. */ void change_euid(struct ucred *newcred, struct uidinfo *euip) { newcred->cr_uid = euip->ui_uid; uihold(euip); uifree(newcred->cr_uidinfo); newcred->cr_uidinfo = euip; } /*- * Change a process's effective gid. * Side effects: newcred->cr_gid will be modified. * References: newcred must be an exclusive credential reference for the * duration of the call. */ void change_egid(struct ucred *newcred, gid_t egid) { newcred->cr_groups[0] = egid; } /*- * Change a process's real uid. * Side effects: newcred->cr_ruid will be updated, newcred->cr_ruidinfo * will be updated, and the old and new cr_ruidinfo proc * counts will be updated. * References: newcred must be an exclusive credential reference for the * duration of the call. */ void change_ruid(struct ucred *newcred, struct uidinfo *ruip) { (void)chgproccnt(newcred->cr_ruidinfo, -1, 0); newcred->cr_ruid = ruip->ui_uid; uihold(ruip); uifree(newcred->cr_ruidinfo); newcred->cr_ruidinfo = ruip; (void)chgproccnt(newcred->cr_ruidinfo, 1, 0); } /*- * Change a process's real gid. * Side effects: newcred->cr_rgid will be updated. * References: newcred must be an exclusive credential reference for the * duration of the call. */ void change_rgid(struct ucred *newcred, gid_t rgid) { newcred->cr_rgid = rgid; } /*- * Change a process's saved uid. * Side effects: newcred->cr_svuid will be updated. * References: newcred must be an exclusive credential reference for the * duration of the call. */ void change_svuid(struct ucred *newcred, uid_t svuid) { newcred->cr_svuid = svuid; } /*- * Change a process's saved gid. * Side effects: newcred->cr_svgid will be updated. * References: newcred must be an exclusive credential reference for the * duration of the call. */ void change_svgid(struct ucred *newcred, gid_t svgid) { newcred->cr_svgid = svgid; } Index: head/sys/security/mac/mac_framework.h =================================================================== --- head/sys/security/mac/mac_framework.h (revision 123172) +++ head/sys/security/mac/mac_framework.h (revision 123173) @@ -1,365 +1,365 @@ /*- * 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 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 *); 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_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); /* * 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_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_create_cred(struct ucred *cred_parent, struct ucred *cred_child); +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, 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_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, 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_policy.h =================================================================== --- head/sys/security/mac/mac_policy.h (revision 123172) +++ head/sys/security/mac/mac_policy.h (revision 123173) @@ -1,492 +1,492 @@ /*- * 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 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, 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, 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_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_create_cred)(struct ucred *parent_cred, - struct ucred *child_cred); 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_relabel)(struct ucred *cred, struct pipe *pipe, 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_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_process.c =================================================================== --- head/sys/security/mac/mac_process.c (revision 123172) +++ head/sys/security/mac/mac_process.c (revision 123173) @@ -1,515 +1,515 @@ /*- * 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. */ #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 int mac_enforce_process = 1; SYSCTL_INT(_security_mac, OID_AUTO, enforce_process, CTLFLAG_RW, &mac_enforce_process, 0, "Enforce MAC policy on inter-process operations"); TUNABLE_INT("security.mac.enforce_process", &mac_enforce_process); int mac_enforce_vm = 1; SYSCTL_INT(_security_mac, OID_AUTO, enforce_vm, CTLFLAG_RW, &mac_enforce_vm, 0, "Enforce MAC policy on vm operations"); TUNABLE_INT("security.mac.enforce_vm", &mac_enforce_vm); static int mac_mmap_revocation = 1; SYSCTL_INT(_security_mac, OID_AUTO, mmap_revocation, CTLFLAG_RW, &mac_mmap_revocation, 0, "Revoke mmap access to files on subject " "relabel"); static int mac_mmap_revocation_via_cow = 0; SYSCTL_INT(_security_mac, OID_AUTO, mmap_revocation_via_cow, CTLFLAG_RW, &mac_mmap_revocation_via_cow, 0, "Revoke mmap access to files via " "copy-on-write semantics, or by removing all write access"); #ifdef MAC_DEBUG static unsigned int nmaccreds, nmacprocs; SYSCTL_UINT(_security_mac_debug_counters, OID_AUTO, creds, CTLFLAG_RD, &nmaccreds, 0, "number of ucreds in use"); SYSCTL_UINT(_security_mac_debug_counters, OID_AUTO, procs, CTLFLAG_RD, &nmacprocs, 0, "number of procs in use"); #endif static void mac_cred_mmapped_drop_perms_recurse(struct thread *td, struct ucred *cred, struct vm_map *map); struct label * mac_cred_label_alloc(void) { struct label *label; label = mac_labelzone_alloc(M_WAITOK); MAC_PERFORM(init_cred_label, label); MAC_DEBUG_COUNTER_INC(&nmaccreds); return (label); } void mac_init_cred(struct ucred *cred) { cred->cr_label = mac_cred_label_alloc(); } static struct label * mac_proc_label_alloc(void) { struct label *label; label = mac_labelzone_alloc(M_WAITOK); MAC_PERFORM(init_proc_label, label); MAC_DEBUG_COUNTER_INC(&nmacprocs); return (label); } void mac_init_proc(struct proc *p) { p->p_label = mac_proc_label_alloc(); } void mac_cred_label_free(struct label *label) { MAC_PERFORM(destroy_cred_label, label); mac_labelzone_free(label); MAC_DEBUG_COUNTER_DEC(&nmaccreds); } void mac_destroy_cred(struct ucred *cred) { mac_cred_label_free(cred->cr_label); cred->cr_label = NULL; } static void mac_proc_label_free(struct label *label) { MAC_PERFORM(destroy_proc_label, label); mac_labelzone_free(label); MAC_DEBUG_COUNTER_DEC(&nmacprocs); } void mac_destroy_proc(struct proc *p) { mac_proc_label_free(p->p_label); p->p_label = NULL; } int mac_externalize_cred_label(struct label *label, char *elements, char *outbuf, size_t outbuflen) { int error; MAC_EXTERNALIZE(cred, label, elements, outbuf, outbuflen); return (error); } int mac_internalize_cred_label(struct label *label, char *string) { int error; MAC_INTERNALIZE(cred, label, string); return (error); } /* * Initialize MAC label for the first kernel process, from which other * kernel processes and threads are spawned. */ void mac_create_proc0(struct ucred *cred) { MAC_PERFORM(create_proc0, cred); } /* * Initialize MAC label for the first userland process, from which other * userland processes and threads are spawned. */ void mac_create_proc1(struct ucred *cred) { MAC_PERFORM(create_proc1, cred); } void mac_thread_userret(struct thread *td) { MAC_PERFORM(thread_userret, td); } /* * When a new process is created, its label must be initialized. Generally, * this involves inheritence from the parent process, modulo possible * deltas. This function allows that processing to take place. */ void -mac_create_cred(struct ucred *parent_cred, struct ucred *child_cred) +mac_copy_cred(struct ucred *src, struct ucred *dest) { - MAC_PERFORM(create_cred, parent_cred, child_cred); + MAC_PERFORM(copy_cred_label, src->cr_label, dest->cr_label); } int mac_execve_enter(struct image_params *imgp, struct mac *mac_p) { struct label *label; struct mac mac; char *buffer; int error; if (mac_p == NULL) return (0); error = copyin(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); } label = mac_cred_label_alloc(); error = mac_internalize_cred_label(label, buffer); free(buffer, M_MACTEMP); if (error) { mac_cred_label_free(label); return (error); } imgp->execlabel = label; return (0); } void mac_execve_exit(struct image_params *imgp) { if (imgp->execlabel != NULL) { mac_cred_label_free(imgp->execlabel); imgp->execlabel = NULL; } } /* * When relabeling a process, call out to the policies for the maximum * permission allowed for each object type we know about in its * memory space, and revoke access (in the least surprising ways we * know) when necessary. The process lock is not held here. */ void mac_cred_mmapped_drop_perms(struct thread *td, struct ucred *cred) { /* XXX freeze all other threads */ mac_cred_mmapped_drop_perms_recurse(td, cred, &td->td_proc->p_vmspace->vm_map); /* XXX allow other threads to continue */ } static __inline const char * prot2str(vm_prot_t prot) { switch (prot & VM_PROT_ALL) { case VM_PROT_READ: return ("r--"); case VM_PROT_READ | VM_PROT_WRITE: return ("rw-"); case VM_PROT_READ | VM_PROT_EXECUTE: return ("r-x"); case VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE: return ("rwx"); case VM_PROT_WRITE: return ("-w-"); case VM_PROT_EXECUTE: return ("--x"); case VM_PROT_WRITE | VM_PROT_EXECUTE: return ("-wx"); default: return ("---"); } } static void mac_cred_mmapped_drop_perms_recurse(struct thread *td, struct ucred *cred, struct vm_map *map) { struct vm_map_entry *vme; int result; vm_prot_t revokeperms; vm_object_t object; vm_ooffset_t offset; struct vnode *vp; if (!mac_mmap_revocation) return; vm_map_lock_read(map); for (vme = map->header.next; vme != &map->header; vme = vme->next) { if (vme->eflags & MAP_ENTRY_IS_SUB_MAP) { mac_cred_mmapped_drop_perms_recurse(td, cred, vme->object.sub_map); continue; } /* * Skip over entries that obviously are not shared. */ if (vme->eflags & (MAP_ENTRY_COW | MAP_ENTRY_NOSYNC) || !vme->max_protection) continue; /* * Drill down to the deepest backing object. */ offset = vme->offset; object = vme->object.vm_object; if (object == NULL) continue; while (object->backing_object != NULL) { object = object->backing_object; offset += object->backing_object_offset; } /* * At the moment, vm_maps and objects aren't considered * by the MAC system, so only things with backing by a * normal object (read: vnodes) are checked. */ if (object->type != OBJT_VNODE) continue; vp = (struct vnode *)object->handle; vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); result = vme->max_protection; mac_check_vnode_mmap_downgrade(cred, vp, &result); VOP_UNLOCK(vp, 0, td); /* * Find out what maximum protection we may be allowing * now but a policy needs to get removed. */ revokeperms = vme->max_protection & ~result; if (!revokeperms) continue; printf("pid %ld: revoking %s perms from %#lx:%ld " "(max %s/cur %s)\n", (long)td->td_proc->p_pid, prot2str(revokeperms), (u_long)vme->start, (long)(vme->end - vme->start), prot2str(vme->max_protection), prot2str(vme->protection)); vm_map_lock_upgrade(map); /* * This is the really simple case: if a map has more * max_protection than is allowed, but it's not being * actually used (that is, the current protection is * still allowed), we can just wipe it out and do * nothing more. */ if ((vme->protection & revokeperms) == 0) { vme->max_protection -= revokeperms; } else { if (revokeperms & VM_PROT_WRITE) { /* * In the more complicated case, flush out all * pending changes to the object then turn it * copy-on-write. */ vm_object_reference(object); vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); VM_OBJECT_LOCK(object); vm_object_page_clean(object, OFF_TO_IDX(offset), OFF_TO_IDX(offset + vme->end - vme->start + PAGE_MASK), OBJPC_SYNC); VM_OBJECT_UNLOCK(object); VOP_UNLOCK(vp, 0, td); vm_object_deallocate(object); /* * Why bother if there's no read permissions * anymore? For the rest, we need to leave * the write permissions on for COW, or * remove them entirely if configured to. */ if (!mac_mmap_revocation_via_cow) { vme->max_protection &= ~VM_PROT_WRITE; vme->protection &= ~VM_PROT_WRITE; } if ((revokeperms & VM_PROT_READ) == 0) vme->eflags |= MAP_ENTRY_COW | MAP_ENTRY_NEEDS_COPY; } if (revokeperms & VM_PROT_EXECUTE) { vme->max_protection &= ~VM_PROT_EXECUTE; vme->protection &= ~VM_PROT_EXECUTE; } if (revokeperms & VM_PROT_READ) { vme->max_protection = 0; vme->protection = 0; } pmap_protect(map->pmap, vme->start, vme->end, vme->protection & ~revokeperms); vm_map_simplify_entry(map, vme); } vm_map_lock_downgrade(map); } vm_map_unlock_read(map); } /* * When the subject's label changes, it may require revocation of privilege * to mapped objects. This can't be done on-the-fly later with a unified * buffer cache. */ void mac_relabel_cred(struct ucred *cred, struct label *newlabel) { MAC_PERFORM(relabel_cred, cred, newlabel); } int mac_check_cred_relabel(struct ucred *cred, struct label *newlabel) { int error; MAC_CHECK(check_cred_relabel, cred, newlabel); return (error); } int mac_check_cred_visible(struct ucred *u1, struct ucred *u2) { int error; if (!mac_enforce_process) return (0); MAC_CHECK(check_cred_visible, u1, u2); return (error); } int mac_check_proc_debug(struct ucred *cred, struct proc *proc) { int error; PROC_LOCK_ASSERT(proc, MA_OWNED); if (!mac_enforce_process) return (0); MAC_CHECK(check_proc_debug, cred, proc); return (error); } int mac_check_proc_sched(struct ucred *cred, struct proc *proc) { int error; PROC_LOCK_ASSERT(proc, MA_OWNED); if (!mac_enforce_process) return (0); MAC_CHECK(check_proc_sched, cred, proc); return (error); } int mac_check_proc_signal(struct ucred *cred, struct proc *proc, int signum) { int error; PROC_LOCK_ASSERT(proc, MA_OWNED); if (!mac_enforce_process) return (0); MAC_CHECK(check_proc_signal, cred, proc, signum); return (error); } Index: head/sys/security/mac_biba/mac_biba.c =================================================================== --- head/sys/security/mac_biba/mac_biba.c (revision 123172) +++ head/sys/security/mac_biba/mac_biba.c (revision 123173) @@ -1,2788 +1,2776 @@ /*- * 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, 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, 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_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_cred(struct ucred *cred_parent, struct ucred *cred_child) -{ - struct mac_biba *source, *dest; - - source = SLOT(cred_parent->cr_label); - dest = SLOT(cred_child->cr_label); - - mac_biba_copy_single(source, dest); - mac_biba_copy_range(source, dest); -} - -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, 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, 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, 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, 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, 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, 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_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_cred = mac_biba_create_cred, .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 123172) +++ head/sys/security/mac_lomac/mac_lomac.c (revision 123173) @@ -1,2757 +1,2745 @@ /*- * 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, 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, 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_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_create_cred(struct ucred *cred_parent, struct ucred *cred_child) -{ - struct mac_lomac *source, *dest; - - source = SLOT(cred_parent->cr_label); - dest = SLOT(cred_child->cr_label); - - mac_lomac_copy_single(source, dest); - mac_lomac_copy_range(source, dest); -} - -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, 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, 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, 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, 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_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_create_cred = mac_lomac_create_cred, .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 123172) +++ head/sys/security/mac_mls/mac_mls.c (revision 123173) @@ -1,2553 +1,2541 @@ /*- * 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, 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, 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_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_cred(struct ucred *cred_parent, struct ucred *cred_child) -{ - struct mac_mls *source, *dest; - - source = SLOT(cred_parent->cr_label); - dest = SLOT(cred_child->cr_label); - - mac_mls_copy_single(source, dest); - mac_mls_copy_range(source, dest); -} - -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, 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, 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, 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, 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, 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, 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_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_cred = mac_mls_create_cred, .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_partition/mac_partition.c =================================================================== --- head/sys/security/mac_partition/mac_partition.c (revision 123172) +++ head/sys/security/mac_partition/mac_partition.c (revision 123173) @@ -1,290 +1,290 @@ /*- * Copyright (c) 1999, 2000, 2001, 2002 Robert N. M. Watson * Copyright (c) 2001, 2002 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. * Experiment with a partition-like model. */ #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, partition, CTLFLAG_RW, 0, "TrustedBSD mac_partition policy controls"); static int mac_partition_enabled = 1; SYSCTL_INT(_security_mac_partition, OID_AUTO, enabled, CTLFLAG_RW, &mac_partition_enabled, 0, "Enforce partition policy"); static int partition_slot; #define SLOT(l) (LABEL_TO_SLOT((l), partition_slot).l_long) static void mac_partition_init(struct mac_policy_conf *conf) { } static void mac_partition_init_label(struct label *label) { SLOT(label) = 0; } static void mac_partition_destroy_label(struct label *label) { SLOT(label) = 0; } +static void +mac_partition_copy_label(struct label *src, struct label *dest) +{ + + SLOT(dest) = SLOT(src); +} + static int mac_partition_externalize_label(struct label *label, char *element_name, struct sbuf *sb, int *claimed) { if (strcmp(MAC_PARTITION_LABEL_NAME, element_name) != 0) return (0); (*claimed)++; if (sbuf_printf(sb, "%ld", SLOT(label)) == -1) return (EINVAL); else return (0); } static int mac_partition_internalize_label(struct label *label, char *element_name, char *element_data, int *claimed) { if (strcmp(MAC_PARTITION_LABEL_NAME, element_name) != 0) return (0); (*claimed)++; SLOT(label) = strtol(element_data, NULL, 10); return (0); } static void -mac_partition_create_cred(struct ucred *cred_parent, struct ucred *cred_child) -{ - - SLOT(cred_child->cr_label) = SLOT(cred_parent->cr_label); -} - -static void mac_partition_create_proc0(struct ucred *cred) { SLOT(cred->cr_label) = 0; } static void mac_partition_create_proc1(struct ucred *cred) { SLOT(cred->cr_label) = 0; } static void mac_partition_relabel_cred(struct ucred *cred, struct label *newlabel) { if (SLOT(newlabel) != 0) SLOT(cred->cr_label) = SLOT(newlabel); } static int label_on_label(struct label *subject, struct label *object) { if (mac_partition_enabled == 0) return (0); if (SLOT(subject) == 0) return (0); if (SLOT(subject) == SLOT(object)) return (0); return (EPERM); } static int mac_partition_check_cred_relabel(struct ucred *cred, struct label *newlabel) { int error; error = 0; /* Treat "0" as a no-op request. */ if (SLOT(newlabel) != 0) { /* * Require BSD privilege in order to change the partition. * Originally we also required that the process not be * in a partition in the first place, but this didn't * interact well with sendmail. */ error = suser_cred(cred, 0); } return (error); } static int mac_partition_check_cred_visible(struct ucred *u1, struct ucred *u2) { int error; error = label_on_label(u1->cr_label, u2->cr_label); return (error == 0 ? 0 : ESRCH); } static int mac_partition_check_proc_debug(struct ucred *cred, struct proc *proc) { int error; error = label_on_label(cred->cr_label, proc->p_ucred->cr_label); return (error ? ESRCH : 0); } static int mac_partition_check_proc_sched(struct ucred *cred, struct proc *proc) { int error; error = label_on_label(cred->cr_label, proc->p_ucred->cr_label); return (error ? ESRCH : 0); } static int mac_partition_check_proc_signal(struct ucred *cred, struct proc *proc, int signum) { int error; error = label_on_label(cred->cr_label, proc->p_ucred->cr_label); return (error ? ESRCH : 0); } static int mac_partition_check_socket_visible(struct ucred *cred, struct socket *socket, struct label *socketlabel) { int error; error = label_on_label(cred->cr_label, socketlabel); return (error ? ENOENT : 0); } static int mac_partition_check_vnode_exec(struct ucred *cred, struct vnode *vp, struct label *label, struct image_params *imgp, struct label *execlabel) { if (execlabel != NULL) { /* * We currently don't permit labels to be changed at * exec-time as part of the partition model, so disallow * non-NULL partition label changes in execlabel. */ if (SLOT(execlabel) != 0) return (EINVAL); } return (0); } static struct mac_policy_ops mac_partition_ops = { .mpo_init = mac_partition_init, .mpo_init_cred_label = mac_partition_init_label, .mpo_destroy_cred_label = mac_partition_destroy_label, + .mpo_copy_cred_label = mac_partition_copy_label, .mpo_externalize_cred_label = mac_partition_externalize_label, .mpo_internalize_cred_label = mac_partition_internalize_label, - .mpo_create_cred = mac_partition_create_cred, .mpo_create_proc0 = mac_partition_create_proc0, .mpo_create_proc1 = mac_partition_create_proc1, .mpo_relabel_cred = mac_partition_relabel_cred, .mpo_check_cred_relabel = mac_partition_check_cred_relabel, .mpo_check_cred_visible = mac_partition_check_cred_visible, .mpo_check_proc_debug = mac_partition_check_proc_debug, .mpo_check_proc_sched = mac_partition_check_proc_sched, .mpo_check_proc_signal = mac_partition_check_proc_signal, .mpo_check_socket_visible = mac_partition_check_socket_visible, .mpo_check_vnode_exec = mac_partition_check_vnode_exec, }; MAC_POLICY_SET(&mac_partition_ops, mac_partition, "TrustedBSD MAC/Partition", MPC_LOADTIME_FLAG_UNLOADOK, &partition_slot); Index: head/sys/security/mac_stub/mac_stub.c =================================================================== --- head/sys/security/mac_stub/mac_stub.c (revision 123172) +++ head/sys/security/mac_stub/mac_stub.c (revision 123173) @@ -1,1190 +1,1184 @@ /*- * 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. * * Stub module that implements a NOOP for most (if not all) MAC Framework * policy entry points. */ #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, stub, CTLFLAG_RW, 0, "TrustedBSD mac_stub policy controls"); static int stub_enabled = 1; SYSCTL_INT(_security_mac_stub, OID_AUTO, enabled, CTLFLAG_RW, &stub_enabled, 0, "Enforce mac_stub policy"); /* * Policy module operations. */ static void stub_destroy(struct mac_policy_conf *conf) { } static void stub_init(struct mac_policy_conf *conf) { } static int stub_syscall(struct thread *td, int call, void *arg) { return (0); } /* * Label operations. */ static void stub_init_label(struct label *label) { } static int stub_init_label_waitcheck(struct label *label, int flag) { return (0); } static void stub_destroy_label(struct label *label) { } static void stub_copy_label(struct label *src, struct label *dest) { } static int stub_externalize_label(struct label *label, char *element_name, struct sbuf *sb, int *claimed) { return (0); } static int stub_internalize_label(struct label *label, char *element_name, char *element_data, int *claimed) { return (0); } /* * Labeling event operations: file system objects, and things that look * a lot like file system objects. */ static void stub_associate_vnode_devfs(struct mount *mp, struct label *fslabel, struct devfs_dirent *de, struct label *delabel, struct vnode *vp, struct label *vlabel) { } static int stub_associate_vnode_extattr(struct mount *mp, struct label *fslabel, struct vnode *vp, struct label *vlabel) { return (0); } static void stub_associate_vnode_singlelabel(struct mount *mp, struct label *fslabel, struct vnode *vp, struct label *vlabel) { } static void stub_create_devfs_device(struct mount *mp, dev_t dev, struct devfs_dirent *devfs_dirent, struct label *label) { } static void stub_create_devfs_directory(struct mount *mp, char *dirname, int dirnamelen, struct devfs_dirent *devfs_dirent, struct label *label) { } static void stub_create_devfs_symlink(struct ucred *cred, struct mount *mp, struct devfs_dirent *dd, struct label *ddlabel, struct devfs_dirent *de, struct label *delabel) { } static int stub_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) { return (0); } static void stub_create_mount(struct ucred *cred, struct mount *mp, struct label *mntlabel, struct label *fslabel) { } static void stub_create_root_mount(struct ucred *cred, struct mount *mp, struct label *mntlabel, struct label *fslabel) { } static void stub_relabel_vnode(struct ucred *cred, struct vnode *vp, struct label *vnodelabel, struct label *label) { } static int stub_setlabel_vnode_extattr(struct ucred *cred, struct vnode *vp, struct label *vlabel, struct label *intlabel) { return (0); } static void stub_update_devfsdirent(struct mount *mp, struct devfs_dirent *devfs_dirent, struct label *direntlabel, struct vnode *vp, struct label *vnodelabel) { } /* * Labeling event operations: IPC object. */ static void stub_create_mbuf_from_socket(struct socket *so, struct label *socketlabel, struct mbuf *m, struct label *mbuflabel) { } static void stub_create_socket(struct ucred *cred, struct socket *socket, struct label *socketlabel) { } static void stub_create_pipe(struct ucred *cred, struct pipe *pipe, struct label *pipelabel) { } static void stub_create_socket_from_socket(struct socket *oldsocket, struct label *oldsocketlabel, struct socket *newsocket, struct label *newsocketlabel) { } static void stub_relabel_socket(struct ucred *cred, struct socket *socket, struct label *socketlabel, struct label *newlabel) { } static void stub_relabel_pipe(struct ucred *cred, struct pipe *pipe, struct label *pipelabel, struct label *newlabel) { } static void stub_set_socket_peer_from_mbuf(struct mbuf *mbuf, struct label *mbuflabel, struct socket *socket, struct label *socketpeerlabel) { } static void stub_set_socket_peer_from_socket(struct socket *oldsocket, struct label *oldsocketlabel, struct socket *newsocket, struct label *newsocketpeerlabel) { } /* * Labeling event operations: network objects. */ static void stub_create_bpfdesc(struct ucred *cred, struct bpf_d *bpf_d, struct label *bpflabel) { } static void stub_create_datagram_from_ipq(struct ipq *ipq, struct label *ipqlabel, struct mbuf *datagram, struct label *datagramlabel) { } static void stub_create_fragment(struct mbuf *datagram, struct label *datagramlabel, struct mbuf *fragment, struct label *fragmentlabel) { } static void stub_create_ifnet(struct ifnet *ifnet, struct label *ifnetlabel) { } static void stub_create_inpcb_from_socket(struct socket *so, struct label *solabel, struct inpcb *inp, struct label *inplabel) { } static void stub_create_ipq(struct mbuf *fragment, struct label *fragmentlabel, struct ipq *ipq, struct label *ipqlabel) { } static void stub_create_mbuf_from_mbuf(struct mbuf *oldmbuf, struct label *oldmbuflabel, struct mbuf *newmbuf, struct label *newmbuflabel) { } static void stub_create_mbuf_linklayer(struct ifnet *ifnet, struct label *ifnetlabel, struct mbuf *mbuf, struct label *mbuflabel) { } static void stub_create_mbuf_from_bpfdesc(struct bpf_d *bpf_d, struct label *bpflabel, struct mbuf *mbuf, struct label *mbuflabel) { } static void stub_create_mbuf_from_ifnet(struct ifnet *ifnet, struct label *ifnetlabel, struct mbuf *m, struct label *mbuflabel) { } static void stub_create_mbuf_multicast_encap(struct mbuf *oldmbuf, struct label *oldmbuflabel, struct ifnet *ifnet, struct label *ifnetlabel, struct mbuf *newmbuf, struct label *newmbuflabel) { } static void stub_create_mbuf_netlayer(struct mbuf *oldmbuf, struct label *oldmbuflabel, struct mbuf *newmbuf, struct label *newmbuflabel) { } static int stub_fragment_match(struct mbuf *fragment, struct label *fragmentlabel, struct ipq *ipq, struct label *ipqlabel) { return (1); } static void stub_reflect_mbuf_icmp(struct mbuf *m, struct label *mlabel) { } static void stub_reflect_mbuf_tcp(struct mbuf *m, struct label *mlabel) { } static void stub_relabel_ifnet(struct ucred *cred, struct ifnet *ifnet, struct label *ifnetlabel, struct label *newlabel) { } static void stub_update_ipq(struct mbuf *fragment, struct label *fragmentlabel, struct ipq *ipq, struct label *ipqlabel) { } static void stub_inpcb_sosetlabel(struct socket *so, struct label *solabel, struct inpcb *inp, struct label *inplabel) { } /* * Labeling event operations: processes. */ static void -stub_create_cred(struct ucred *cred_parent, struct ucred *cred_child) -{ - -} - -static void stub_execve_transition(struct ucred *old, struct ucred *new, struct vnode *vp, struct label *vnodelabel, struct label *interpvnodelabel, struct image_params *imgp, struct label *execlabel) { } static int stub_execve_will_transition(struct ucred *old, struct vnode *vp, struct label *vnodelabel, struct label *interpvnodelabel, struct image_params *imgp, struct label *execlabel) { return (0); } static void stub_create_proc0(struct ucred *cred) { } static void stub_create_proc1(struct ucred *cred) { } static void stub_relabel_cred(struct ucred *cred, struct label *newlabel) { } static void stub_thread_userret(struct thread *td) { } /* * Access control checks. */ static int stub_check_bpfdesc_receive(struct bpf_d *bpf_d, struct label *bpflabel, struct ifnet *ifnet, struct label *ifnet_label) { return (0); } static int stub_check_cred_relabel(struct ucred *cred, struct label *newlabel) { return (0); } static int stub_check_cred_visible(struct ucred *u1, struct ucred *u2) { return (0); } static int stub_check_ifnet_relabel(struct ucred *cred, struct ifnet *ifnet, struct label *ifnetlabel, struct label *newlabel) { return (0); } static int stub_check_ifnet_transmit(struct ifnet *ifnet, struct label *ifnetlabel, struct mbuf *m, struct label *mbuflabel) { return (0); } static int stub_check_inpcb_deliver(struct inpcb *inp, struct label *inplabel, struct mbuf *m, struct label *mlabel) { return (0); } static int stub_check_kenv_dump(struct ucred *cred) { return (0); } static int stub_check_kenv_get(struct ucred *cred, char *name) { return (0); } static int stub_check_kenv_set(struct ucred *cred, char *name, char *value) { return (0); } static int stub_check_kenv_unset(struct ucred *cred, char *name) { return (0); } static int stub_check_kld_load(struct ucred *cred, struct vnode *vp, struct label *vlabel) { return (0); } static int stub_check_kld_stat(struct ucred *cred) { return (0); } static int stub_check_kld_unload(struct ucred *cred) { return (0); } static int stub_check_mount_stat(struct ucred *cred, struct mount *mp, struct label *mntlabel) { return (0); } static int stub_check_pipe_ioctl(struct ucred *cred, struct pipe *pipe, struct label *pipelabel, unsigned long cmd, void /* caddr_t */ *data) { return (0); } static int stub_check_pipe_poll(struct ucred *cred, struct pipe *pipe, struct label *pipelabel) { return (0); } static int stub_check_pipe_read(struct ucred *cred, struct pipe *pipe, struct label *pipelabel) { return (0); } static int stub_check_pipe_relabel(struct ucred *cred, struct pipe *pipe, struct label *pipelabel, struct label *newlabel) { return (0); } static int stub_check_pipe_stat(struct ucred *cred, struct pipe *pipe, struct label *pipelabel) { return (0); } static int stub_check_pipe_write(struct ucred *cred, struct pipe *pipe, struct label *pipelabel) { return (0); } static int stub_check_proc_debug(struct ucred *cred, struct proc *proc) { return (0); } static int stub_check_proc_sched(struct ucred *cred, struct proc *proc) { return (0); } static int stub_check_proc_signal(struct ucred *cred, struct proc *proc, int signum) { return (0); } static int stub_check_socket_bind(struct ucred *cred, struct socket *socket, struct label *socketlabel, struct sockaddr *sockaddr) { return (0); } static int stub_check_socket_connect(struct ucred *cred, struct socket *socket, struct label *socketlabel, struct sockaddr *sockaddr) { return (0); } static int stub_check_socket_deliver(struct socket *so, struct label *socketlabel, struct mbuf *m, struct label *mbuflabel) { return (0); } static int stub_check_socket_listen(struct ucred *cred, struct socket *so, struct label *socketlabel) { return (0); } static int stub_check_socket_relabel(struct ucred *cred, struct socket *socket, struct label *socketlabel, struct label *newlabel) { return (0); } static int stub_check_socket_visible(struct ucred *cred, struct socket *socket, struct label *socketlabel) { return (0); } static int stub_check_sysarch_ioperm(struct ucred *cred) { return (0); } static int stub_check_system_acct(struct ucred *cred, struct vnode *vp, struct label *vlabel) { return (0); } static int stub_check_system_reboot(struct ucred *cred, int how) { return (0); } static int stub_check_system_settime(struct ucred *cred) { return (0); } static int stub_check_system_swapon(struct ucred *cred, struct vnode *vp, struct label *label) { return (0); } static int stub_check_system_swapoff(struct ucred *cred, struct vnode *vp, struct label *label) { return (0); } static int stub_check_system_sysctl(struct ucred *cred, int *name, u_int namelen, void *old, size_t *oldlenp, int inkernel, void *new, size_t newlen) { return (0); } static int stub_check_vnode_access(struct ucred *cred, struct vnode *vp, struct label *label, int acc_mode) { return (0); } static int stub_check_vnode_chdir(struct ucred *cred, struct vnode *dvp, struct label *dlabel) { return (0); } static int stub_check_vnode_chroot(struct ucred *cred, struct vnode *dvp, struct label *dlabel) { return (0); } static int stub_check_vnode_create(struct ucred *cred, struct vnode *dvp, struct label *dlabel, struct componentname *cnp, struct vattr *vap) { return (0); } static int stub_check_vnode_delete(struct ucred *cred, struct vnode *dvp, struct label *dlabel, struct vnode *vp, struct label *label, struct componentname *cnp) { return (0); } static int stub_check_vnode_deleteacl(struct ucred *cred, struct vnode *vp, struct label *label, acl_type_t type) { return (0); } static int stub_check_vnode_deleteextattr(struct ucred *cred, struct vnode *vp, struct label *label, int attrnamespace, const char *name) { return (0); } static int stub_check_vnode_exec(struct ucred *cred, struct vnode *vp, struct label *label, struct image_params *imgp, struct label *execlabel) { return (0); } static int stub_check_vnode_getacl(struct ucred *cred, struct vnode *vp, struct label *label, acl_type_t type) { return (0); } static int stub_check_vnode_getextattr(struct ucred *cred, struct vnode *vp, struct label *label, int attrnamespace, const char *name, struct uio *uio) { return (0); } static int stub_check_vnode_link(struct ucred *cred, struct vnode *dvp, struct label *dlabel, struct vnode *vp, struct label *label, struct componentname *cnp) { return (0); } static int stub_check_vnode_listextattr(struct ucred *cred, struct vnode *vp, struct label *label, int attrnamespace) { return (0); } static int stub_check_vnode_lookup(struct ucred *cred, struct vnode *dvp, struct label *dlabel, struct componentname *cnp) { return (0); } static int stub_check_vnode_mmap(struct ucred *cred, struct vnode *vp, struct label *label, int prot) { return (0); } static int stub_check_vnode_mprotect(struct ucred *cred, struct vnode *vp, struct label *label, int prot) { return (0); } static int stub_check_vnode_open(struct ucred *cred, struct vnode *vp, struct label *filelabel, int acc_mode) { return (0); } static int stub_check_vnode_poll(struct ucred *active_cred, struct ucred *file_cred, struct vnode *vp, struct label *label) { return (0); } static int stub_check_vnode_read(struct ucred *active_cred, struct ucred *file_cred, struct vnode *vp, struct label *label) { return (0); } static int stub_check_vnode_readdir(struct ucred *cred, struct vnode *vp, struct label *dlabel) { return (0); } static int stub_check_vnode_readlink(struct ucred *cred, struct vnode *vp, struct label *vnodelabel) { return (0); } static int stub_check_vnode_relabel(struct ucred *cred, struct vnode *vp, struct label *vnodelabel, struct label *newlabel) { return (0); } static int stub_check_vnode_rename_from(struct ucred *cred, struct vnode *dvp, struct label *dlabel, struct vnode *vp, struct label *label, struct componentname *cnp) { return (0); } static int stub_check_vnode_rename_to(struct ucred *cred, struct vnode *dvp, struct label *dlabel, struct vnode *vp, struct label *label, int samedir, struct componentname *cnp) { return (0); } static int stub_check_vnode_revoke(struct ucred *cred, struct vnode *vp, struct label *label) { return (0); } static int stub_check_vnode_setacl(struct ucred *cred, struct vnode *vp, struct label *label, acl_type_t type, struct acl *acl) { return (0); } static int stub_check_vnode_setextattr(struct ucred *cred, struct vnode *vp, struct label *label, int attrnamespace, const char *name, struct uio *uio) { return (0); } static int stub_check_vnode_setflags(struct ucred *cred, struct vnode *vp, struct label *label, u_long flags) { return (0); } static int stub_check_vnode_setmode(struct ucred *cred, struct vnode *vp, struct label *label, mode_t mode) { return (0); } static int stub_check_vnode_setowner(struct ucred *cred, struct vnode *vp, struct label *label, uid_t uid, gid_t gid) { return (0); } static int stub_check_vnode_setutimes(struct ucred *cred, struct vnode *vp, struct label *label, struct timespec atime, struct timespec mtime) { return (0); } static int stub_check_vnode_stat(struct ucred *active_cred, struct ucred *file_cred, struct vnode *vp, struct label *label) { return (0); } static int stub_check_vnode_write(struct ucred *active_cred, struct ucred *file_cred, struct vnode *vp, struct label *label) { return (0); } static struct mac_policy_ops mac_stub_ops = { .mpo_destroy = stub_destroy, .mpo_init = stub_init, .mpo_syscall = stub_syscall, .mpo_init_bpfdesc_label = stub_init_label, .mpo_init_cred_label = stub_init_label, .mpo_init_devfsdirent_label = stub_init_label, .mpo_init_ifnet_label = stub_init_label, .mpo_init_inpcb_label = stub_init_label_waitcheck, .mpo_init_ipq_label = stub_init_label_waitcheck, .mpo_init_mbuf_label = stub_init_label_waitcheck, .mpo_init_mount_label = stub_init_label, .mpo_init_mount_fs_label = stub_init_label, .mpo_init_pipe_label = stub_init_label, .mpo_init_socket_label = stub_init_label_waitcheck, .mpo_init_socket_peer_label = stub_init_label_waitcheck, .mpo_init_vnode_label = stub_init_label, .mpo_destroy_bpfdesc_label = stub_destroy_label, .mpo_destroy_cred_label = stub_destroy_label, .mpo_destroy_devfsdirent_label = stub_destroy_label, .mpo_destroy_ifnet_label = stub_destroy_label, .mpo_destroy_inpcb_label = stub_destroy_label, .mpo_destroy_ipq_label = stub_destroy_label, .mpo_destroy_mbuf_label = stub_destroy_label, .mpo_destroy_mount_label = stub_destroy_label, .mpo_destroy_mount_fs_label = stub_destroy_label, .mpo_destroy_pipe_label = stub_destroy_label, .mpo_destroy_socket_label = stub_destroy_label, .mpo_destroy_socket_peer_label = stub_destroy_label, .mpo_destroy_vnode_label = stub_destroy_label, + .mpo_copy_cred_label = stub_copy_label, .mpo_copy_mbuf_label = stub_copy_label, .mpo_copy_pipe_label = stub_copy_label, .mpo_copy_socket_label = stub_copy_label, .mpo_copy_vnode_label = stub_copy_label, .mpo_externalize_cred_label = stub_externalize_label, .mpo_externalize_ifnet_label = stub_externalize_label, .mpo_externalize_pipe_label = stub_externalize_label, .mpo_externalize_socket_label = stub_externalize_label, .mpo_externalize_socket_peer_label = stub_externalize_label, .mpo_externalize_vnode_label = stub_externalize_label, .mpo_internalize_cred_label = stub_internalize_label, .mpo_internalize_ifnet_label = stub_internalize_label, .mpo_internalize_pipe_label = stub_internalize_label, .mpo_internalize_socket_label = stub_internalize_label, .mpo_internalize_vnode_label = stub_internalize_label, .mpo_associate_vnode_devfs = stub_associate_vnode_devfs, .mpo_associate_vnode_extattr = stub_associate_vnode_extattr, .mpo_associate_vnode_singlelabel = stub_associate_vnode_singlelabel, .mpo_create_devfs_device = stub_create_devfs_device, .mpo_create_devfs_directory = stub_create_devfs_directory, .mpo_create_devfs_symlink = stub_create_devfs_symlink, .mpo_create_vnode_extattr = stub_create_vnode_extattr, .mpo_create_mount = stub_create_mount, .mpo_create_root_mount = stub_create_root_mount, .mpo_relabel_vnode = stub_relabel_vnode, .mpo_setlabel_vnode_extattr = stub_setlabel_vnode_extattr, .mpo_update_devfsdirent = stub_update_devfsdirent, .mpo_create_mbuf_from_socket = stub_create_mbuf_from_socket, .mpo_create_pipe = stub_create_pipe, .mpo_create_socket = stub_create_socket, .mpo_create_socket_from_socket = stub_create_socket_from_socket, .mpo_relabel_pipe = stub_relabel_pipe, .mpo_relabel_socket = stub_relabel_socket, .mpo_set_socket_peer_from_mbuf = stub_set_socket_peer_from_mbuf, .mpo_set_socket_peer_from_socket = stub_set_socket_peer_from_socket, .mpo_create_bpfdesc = stub_create_bpfdesc, .mpo_create_ifnet = stub_create_ifnet, .mpo_create_inpcb_from_socket = stub_create_inpcb_from_socket, .mpo_create_ipq = stub_create_ipq, .mpo_create_datagram_from_ipq = stub_create_datagram_from_ipq, .mpo_create_fragment = stub_create_fragment, .mpo_create_ipq = stub_create_ipq, .mpo_create_mbuf_from_mbuf = stub_create_mbuf_from_mbuf, .mpo_create_mbuf_linklayer = stub_create_mbuf_linklayer, .mpo_create_mbuf_from_bpfdesc = stub_create_mbuf_from_bpfdesc, .mpo_create_mbuf_from_ifnet = stub_create_mbuf_from_ifnet, .mpo_create_mbuf_multicast_encap = stub_create_mbuf_multicast_encap, .mpo_create_mbuf_netlayer = stub_create_mbuf_netlayer, .mpo_fragment_match = stub_fragment_match, .mpo_reflect_mbuf_icmp = stub_reflect_mbuf_icmp, .mpo_reflect_mbuf_tcp = stub_reflect_mbuf_tcp, .mpo_relabel_ifnet = stub_relabel_ifnet, .mpo_update_ipq = stub_update_ipq, .mpo_inpcb_sosetlabel = stub_inpcb_sosetlabel, - .mpo_create_cred = stub_create_cred, .mpo_execve_transition = stub_execve_transition, .mpo_execve_will_transition = stub_execve_will_transition, .mpo_create_proc0 = stub_create_proc0, .mpo_create_proc1 = stub_create_proc1, .mpo_relabel_cred = stub_relabel_cred, .mpo_thread_userret = stub_thread_userret, .mpo_check_bpfdesc_receive = stub_check_bpfdesc_receive, .mpo_check_cred_relabel = stub_check_cred_relabel, .mpo_check_cred_visible = stub_check_cred_visible, .mpo_check_ifnet_relabel = stub_check_ifnet_relabel, .mpo_check_ifnet_transmit = stub_check_ifnet_transmit, .mpo_check_inpcb_deliver = stub_check_inpcb_deliver, .mpo_check_kenv_dump = stub_check_kenv_dump, .mpo_check_kenv_get = stub_check_kenv_get, .mpo_check_kenv_set = stub_check_kenv_set, .mpo_check_kenv_unset = stub_check_kenv_unset, .mpo_check_kld_load = stub_check_kld_load, .mpo_check_kld_stat = stub_check_kld_stat, .mpo_check_kld_unload = stub_check_kld_unload, .mpo_check_mount_stat = stub_check_mount_stat, .mpo_check_pipe_ioctl = stub_check_pipe_ioctl, .mpo_check_pipe_poll = stub_check_pipe_poll, .mpo_check_pipe_read = stub_check_pipe_read, .mpo_check_pipe_relabel = stub_check_pipe_relabel, .mpo_check_pipe_stat = stub_check_pipe_stat, .mpo_check_pipe_write = stub_check_pipe_write, .mpo_check_proc_debug = stub_check_proc_debug, .mpo_check_proc_sched = stub_check_proc_sched, .mpo_check_proc_signal = stub_check_proc_signal, .mpo_check_socket_bind = stub_check_socket_bind, .mpo_check_socket_connect = stub_check_socket_connect, .mpo_check_socket_deliver = stub_check_socket_deliver, .mpo_check_socket_listen = stub_check_socket_listen, .mpo_check_socket_relabel = stub_check_socket_relabel, .mpo_check_socket_visible = stub_check_socket_visible, .mpo_check_sysarch_ioperm = stub_check_sysarch_ioperm, .mpo_check_system_acct = stub_check_system_acct, .mpo_check_system_reboot = stub_check_system_reboot, .mpo_check_system_settime = stub_check_system_settime, .mpo_check_system_swapon = stub_check_system_swapon, .mpo_check_system_swapoff = stub_check_system_swapoff, .mpo_check_system_sysctl = stub_check_system_sysctl, .mpo_check_vnode_access = stub_check_vnode_access, .mpo_check_vnode_chdir = stub_check_vnode_chdir, .mpo_check_vnode_chroot = stub_check_vnode_chroot, .mpo_check_vnode_create = stub_check_vnode_create, .mpo_check_vnode_delete = stub_check_vnode_delete, .mpo_check_vnode_deleteacl = stub_check_vnode_deleteacl, .mpo_check_vnode_deleteextattr = stub_check_vnode_deleteextattr, .mpo_check_vnode_exec = stub_check_vnode_exec, .mpo_check_vnode_getacl = stub_check_vnode_getacl, .mpo_check_vnode_getextattr = stub_check_vnode_getextattr, .mpo_check_vnode_link = stub_check_vnode_link, .mpo_check_vnode_listextattr = stub_check_vnode_listextattr, .mpo_check_vnode_lookup = stub_check_vnode_lookup, .mpo_check_vnode_mmap = stub_check_vnode_mmap, .mpo_check_vnode_mprotect = stub_check_vnode_mprotect, .mpo_check_vnode_open = stub_check_vnode_open, .mpo_check_vnode_poll = stub_check_vnode_poll, .mpo_check_vnode_read = stub_check_vnode_read, .mpo_check_vnode_readdir = stub_check_vnode_readdir, .mpo_check_vnode_readlink = stub_check_vnode_readlink, .mpo_check_vnode_relabel = stub_check_vnode_relabel, .mpo_check_vnode_rename_from = stub_check_vnode_rename_from, .mpo_check_vnode_rename_to = stub_check_vnode_rename_to, .mpo_check_vnode_revoke = stub_check_vnode_revoke, .mpo_check_vnode_setacl = stub_check_vnode_setacl, .mpo_check_vnode_setextattr = stub_check_vnode_setextattr, .mpo_check_vnode_setflags = stub_check_vnode_setflags, .mpo_check_vnode_setmode = stub_check_vnode_setmode, .mpo_check_vnode_setowner = stub_check_vnode_setowner, .mpo_check_vnode_setutimes = stub_check_vnode_setutimes, .mpo_check_vnode_stat = stub_check_vnode_stat, .mpo_check_vnode_write = stub_check_vnode_write, }; MAC_POLICY_SET(&mac_stub_ops, mac_stub, "TrustedBSD MAC/Stub", MPC_LOADTIME_FLAG_UNLOADOK, NULL); Index: head/sys/security/mac_test/mac_test.c =================================================================== --- head/sys/security/mac_test/mac_test.c (revision 123172) +++ head/sys/security/mac_test/mac_test.c (revision 123173) @@ -1,2013 +1,2013 @@ /*- * 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, 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, 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_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_create_cred(struct ucred *cred_parent, struct ucred *cred_child) -{ - - ASSERT_CRED_LABEL(cred_parent->cr_label); - ASSERT_CRED_LABEL(cred_child->cr_label); -} - -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); 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, 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, 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, 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, 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, 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, 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_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_create_cred = mac_test_create_cred, .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 123172) +++ head/sys/sys/mac.h (revision 123173) @@ -1,365 +1,365 @@ /*- * 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 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 *); 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_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); /* * 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_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_create_cred(struct ucred *cred_parent, struct ucred *cred_child); +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, 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_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, 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 123172) +++ head/sys/sys/mac_policy.h (revision 123173) @@ -1,492 +1,492 @@ /*- * 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 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, 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, 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_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_create_cred)(struct ucred *parent_cred, - struct ucred *child_cred); 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_relabel)(struct ucred *cred, struct pipe *pipe, 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_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 */