diff --git a/sys/fs/procfs/procfs_mem.c b/sys/fs/procfs/procfs_mem.c index 6ef725ee0ee7..159b40785172 100644 --- a/sys/fs/procfs/procfs_mem.c +++ b/sys/fs/procfs/procfs_mem.c @@ -1,69 +1,72 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 1993 Jan-Simon Pendry * Copyright (c) 1993 Sean Eric Fagan * Copyright (c) 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Jan-Simon Pendry and Sean Eric Fagan. * * 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. 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. */ #include #include #include #include #include #include #include +#include #include #include /* * Copy data in and out of the target process. * We do this by mapping the process's page into * the kernel and then doing a uiomove direct * from the kernel address space. */ int procfs_doprocmem(PFS_FILL_ARGS) { int error; if (uio->uio_resid == 0) return (0); PROC_LOCK(p); error = p_candebug(td, p); + if (error == 0 && uio->uio_rw == UIO_WRITE) + error = priv_check(td, PRIV_PROC_MEM_WRITE); PROC_UNLOCK(p); if (error == 0) error = proc_rwmem(p, uio); return (error); } diff --git a/sys/kern/kern_priv.c b/sys/kern/kern_priv.c index c146f9e6f8d5..83fd246eef9b 100644 --- a/sys/kern/kern_priv.c +++ b/sys/kern/kern_priv.c @@ -1,364 +1,366 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2006 nCircle Network Security, Inc. * Copyright (c) 2009 Robert N. M. Watson * Copyright (c) 2020 Mariusz Zaborski * All rights reserved. * * This software was developed by Robert N. M. Watson for the TrustedBSD * Project under contract to nCircle Network Security, Inc. * * 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, NCIRCLE NETWORK SECURITY, * INC., 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 #include #include #include #include #include #include #include #include #include #include #include /* * `suser_enabled' (which can be set by the security.bsd.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. */ static bool suser_enabled(struct ucred *cred) { return (prison_allow(cred, PR_ALLOW_SUSER)); } static int sysctl_kern_suser_enabled(SYSCTL_HANDLER_ARGS) { struct ucred *cred; int error, enabled; cred = req->td->td_ucred; enabled = suser_enabled(cred); error = sysctl_handle_int(oidp, &enabled, 0, req); if (error || !req->newptr) return (error); prison_set_allow(cred, PR_ALLOW_SUSER, enabled); return (0); } SYSCTL_PROC(_security_bsd, OID_AUTO, suser_enabled, CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_PRISON | CTLFLAG_MPSAFE, 0, 0, &sysctl_kern_suser_enabled, "I", "Processes with uid 0 have privilege"); static int unprivileged_mlock = 1; SYSCTL_INT(_security_bsd, OID_AUTO, unprivileged_mlock, CTLFLAG_RWTUN, &unprivileged_mlock, 0, "Allow non-root users to call mlock(2)"); static int unprivileged_read_msgbuf = 1; SYSCTL_INT(_security_bsd, OID_AUTO, unprivileged_read_msgbuf, CTLFLAG_RW, &unprivileged_read_msgbuf, 0, "Unprivileged processes may read the kernel message buffer"); SDT_PROVIDER_DEFINE(priv); SDT_PROBE_DEFINE1(priv, kernel, priv_check, priv__ok, "int"); SDT_PROBE_DEFINE1(priv, kernel, priv_check, priv__err, "int"); static __always_inline int priv_check_cred_pre(struct ucred *cred, int priv) { int error; #ifdef MAC error = mac_priv_check(cred, priv); #else error = 0; #endif return (error); } static __always_inline int priv_check_cred_post(struct ucred *cred, int priv, int error, bool handled) { if (__predict_true(handled)) goto out; /* * Now check with MAC, if enabled, to see if a policy module grants * privilege. */ #ifdef MAC if (mac_priv_grant(cred, priv) == 0) { error = 0; goto out; } #endif /* * The default is deny, so if no policies have granted it, reject * with a privilege error here. */ error = EPERM; out: if (SDT_PROBES_ENABLED()) { if (error) SDT_PROBE1(priv, kernel, priv_check, priv__err, priv); else SDT_PROBE1(priv, kernel, priv_check, priv__ok, priv); } return (error); } /* * Check a credential for privilege. Lots of good reasons to deny privilege; * only a few to grant it. */ int priv_check_cred(struct ucred *cred, int priv) { int error; KASSERT(PRIV_VALID(priv), ("priv_check_cred: invalid privilege %d", priv)); switch (priv) { case PRIV_VFS_LOOKUP: return (priv_check_cred_vfs_lookup(cred)); case PRIV_VFS_GENERATION: return (priv_check_cred_vfs_generation(cred)); } /* * We first evaluate policies that may deny the granting of * privilege unilaterally. */ error = priv_check_cred_pre(cred, priv); if (error) goto out; /* * Jail policy will restrict certain privileges that may otherwise be * be granted. */ error = prison_priv_check(cred, priv); if (error) goto out; if (unprivileged_mlock) { /* * Allow unprivileged users to call mlock(2)/munlock(2) and * mlockall(2)/munlockall(2). */ switch (priv) { case PRIV_VM_MLOCK: case PRIV_VM_MUNLOCK: error = 0; goto out; } } if (unprivileged_read_msgbuf) { /* * Allow an unprivileged user to read the kernel message * buffer. */ if (priv == PRIV_MSGBUF) { error = 0; goto out; } } /* * Having determined if privilege is restricted by various policies, * now determine if privilege is granted. At this point, any policy * may grant privilege. For now, we allow short-circuit boolean * evaluation, so may not call all policies. Perhaps we should. * * Superuser policy grants privilege based on the effective (or in * the case of specific privileges, real) uid being 0. We allow the * superuser policy to be globally disabled, although this is * currenty of limited utility. */ if (suser_enabled(cred)) { switch (priv) { case PRIV_MAXFILES: case PRIV_MAXPROC: case PRIV_PROC_LIMIT: if (cred->cr_ruid == 0) { error = 0; goto out; } break; case PRIV_VFS_READ_DIR: /* * Allow PRIV_VFS_READ_DIR for root if we're not in a * jail, otherwise deny unless a MAC policy grants it. */ if (jailed(cred)) break; /* FALLTHROUGH */ default: if (cred->cr_uid == 0) { error = 0; goto out; } break; } } /* * Writes to kernel/physical memory are a typical root-only operation, * but non-root users are expected to be able to read it (provided they * have permission to access /dev/[k]mem). */ - if (priv == PRIV_KMEM_READ) { + switch (priv) { + case PRIV_KMEM_READ: + case PRIV_PROC_MEM_WRITE: /* we already checked candebug */ error = 0; goto out; } /* * Allow unprivileged process debugging on a per-jail basis. * Do this here instead of prison_priv_check(), so it can also * apply to prison0. */ if (priv == PRIV_DEBUG_UNPRIV) { if (prison_allow(cred, PR_ALLOW_UNPRIV_DEBUG)) { error = 0; goto out; } } return (priv_check_cred_post(cred, priv, error, false)); out: return (priv_check_cred_post(cred, priv, error, true)); } int priv_check(struct thread *td, int priv) { KASSERT(td == curthread, ("priv_check: td != curthread")); return (priv_check_cred(td->td_ucred, priv)); } static int __noinline priv_check_cred_vfs_lookup_slow(struct ucred *cred) { int error; error = priv_check_cred_pre(cred, PRIV_VFS_LOOKUP); if (error) goto out; if (cred->cr_uid == 0 && suser_enabled(cred)) { error = 0; goto out; } return (priv_check_cred_post(cred, PRIV_VFS_LOOKUP, error, false)); out: return (priv_check_cred_post(cred, PRIV_VFS_LOOKUP, error, true)); } int priv_check_cred_vfs_lookup(struct ucred *cred) { int error; if (__predict_false(mac_priv_check_fp_flag || mac_priv_grant_fp_flag || SDT_PROBES_ENABLED())) return (priv_check_cred_vfs_lookup_slow(cred)); error = EPERM; if (cred->cr_uid == 0 && suser_enabled(cred)) error = 0; return (error); } int priv_check_cred_vfs_lookup_nomac(struct ucred *cred) { int error; if (__predict_false(mac_priv_check_fp_flag || mac_priv_grant_fp_flag || SDT_PROBES_ENABLED())) return (EAGAIN); error = EPERM; if (cred->cr_uid == 0 && suser_enabled(cred)) error = 0; return (error); } static int __noinline priv_check_cred_vfs_generation_slow(struct ucred *cred) { int error; error = priv_check_cred_pre(cred, PRIV_VFS_GENERATION); if (error) goto out; if (jailed(cred)) { error = EPERM; goto out; } if (cred->cr_uid == 0 && suser_enabled(cred)) { error = 0; goto out; } return (priv_check_cred_post(cred, PRIV_VFS_GENERATION, error, false)); out: return (priv_check_cred_post(cred, PRIV_VFS_GENERATION, error, true)); } int priv_check_cred_vfs_generation(struct ucred *cred) { int error; if (__predict_false(mac_priv_check_fp_flag || mac_priv_grant_fp_flag || SDT_PROBES_ENABLED())) return (priv_check_cred_vfs_generation_slow(cred)); error = EPERM; if (!jailed(cred) && cred->cr_uid == 0 && suser_enabled(cred)) error = 0; return (error); } diff --git a/sys/security/mac_grantbylabel/mac_grantbylabel.c b/sys/security/mac_grantbylabel/mac_grantbylabel.c index 848131e54590..4d14577820eb 100644 --- a/sys/security/mac_grantbylabel/mac_grantbylabel.c +++ b/sys/security/mac_grantbylabel/mac_grantbylabel.c @@ -1,506 +1,508 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2018-2023, Juniper Networks, Inc. * 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. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 #include "opt_mac.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "mac_grantbylabel.h" #include #define MAC_GRANTBYLABEL_FULLNAME "MAC/grantbylabel" SYSCTL_DECL(_security_mac); SYSCTL_NODE(_security_mac, OID_AUTO, grantbylabel, CTLFLAG_RW, 0, "MAC/grantbylabel policy controls"); #ifdef MAC_DEBUG static int mac_grantbylabel_debug; SYSCTL_INT(_security_mac_grantbylabel, OID_AUTO, debug, CTLFLAG_RW, &mac_grantbylabel_debug, 0, "Debug mac_grantbylabel"); #define GRANTBYLABEL_DEBUG(n, x) if (mac_grantbylabel_debug >= (n)) printf x #define MAC_GRANTBYLABEL_DBG(_lvl, _fmt, ...) \ do { \ GRANTBYLABEL_DEBUG((_lvl), (MAC_GRANTBYLABEL_FULLNAME ": " \ _fmt "\n", ##__VA_ARGS__)); \ } while(0) #else #define MAC_GRANTBYLABEL_DBG(_lvl, _fmt, ...) #endif /* label token prefix */ #define GBL_PREFIX "gbl/" static int mac_grantbylabel_slot; #define SLOT(l) \ mac_label_get((l), mac_grantbylabel_slot) #define SLOT_SET(l, v) \ mac_label_set((l), mac_grantbylabel_slot, (v)) /** * @brief parse label into bitmask * * We are only interested in tokens prefixed by GBL_PREFIX ("gbl/"). * * @return 32bit mask */ static gbl_label_t gbl_parse_label(const char *label) { gbl_label_t gbl; char *cp; if (!(label && *label)) return GBL_EMPTY; gbl = 0; for (cp = strstr(label, GBL_PREFIX); cp; cp = strstr(cp, GBL_PREFIX)) { /* check we didn't find "fugbl/" */ if (cp > label && cp[-1] != ',') { cp += sizeof(GBL_PREFIX); continue; } cp += sizeof(GBL_PREFIX) - 1; switch (*cp) { case 'b': if (strncmp(cp, "bind", 4) == 0) gbl |= GBL_BIND; break; case 'd': if (strncmp(cp, "daemon", 6) == 0) gbl |= (GBL_BIND|GBL_IPC|GBL_NET|GBL_PROC| GBL_SYSCTL|GBL_VACCESS); break; case 'i': if (strncmp(cp, "ipc", 3) == 0) gbl |= GBL_IPC; break; case 'k': if (strncmp(cp, "kmem", 4) == 0) gbl |= GBL_KMEM; break; case 'n': if (strncmp(cp, "net", 3) == 0) gbl |= GBL_NET; break; case 'p': if (strncmp(cp, "proc", 4) == 0) gbl |= GBL_PROC; break; case 'r': if (strncmp(cp, "rtsock", 6) == 0) gbl |= GBL_RTSOCK; break; case 's': if (strncmp(cp, "sysctl", 6) == 0) gbl |= GBL_SYSCTL; break; case 'v': if (strncmp(cp, "vaccess", 7) == 0) gbl |= GBL_VACCESS; else if (strncmp(cp, "veriexec", 8) == 0) gbl |= GBL_VERIEXEC; break; default: /* ignore unknown? */ MAC_GRANTBYLABEL_DBG(1, "ignoring unknown token at %s/%s", GBL_PREFIX, cp); break; } } return gbl; } /** * @brief get the v_label for a vnode * * Lookup the label if not already set in v_label * * @return 32bit mask or 0 on error */ static gbl_label_t gbl_get_vlabel(struct vnode *vp, struct ucred *cred) { struct vattr va; const char *label; gbl_label_t gbl; int error; gbl = SLOT(vp->v_label); if (gbl == 0) { error = VOP_GETATTR(vp, &va, cred); if (error == 0) { label = mac_veriexec_metadata_get_file_label(va.va_fsid, va.va_fileid, va.va_gen, FALSE); if (label) { MAC_GRANTBYLABEL_DBG(1, "label=%s dev=%ju, file %ju.%lu", label, (uintmax_t)va.va_fsid, (uintmax_t)va.va_fileid, va.va_gen); gbl = gbl_parse_label(label); } else { gbl = GBL_EMPTY; MAC_GRANTBYLABEL_DBG(2, "no label dev=%ju, file %ju.%lu", (uintmax_t)va.va_fsid, (uintmax_t)va.va_fileid, va.va_gen); } } } return gbl; } /** * @brief grant priv if warranted * * If the cred is root, we have nothing to do. * Otherwise see if the current process has a label * that grants it the requested priv. */ static int mac_grantbylabel_priv_grant(struct ucred *cred, int priv) { gbl_label_t label; int rc; rc = EPERM; /* default response */ if ((curproc->p_flag & (P_KPROC|P_SYSTEM))) return rc; /* not interested */ switch (priv) { + case PRIV_PROC_MEM_WRITE: case PRIV_KMEM_READ: case PRIV_KMEM_WRITE: break; case PRIV_VERIEXEC_DIRECT: case PRIV_VERIEXEC_NOVERIFY: /* XXX might want to skip in FIPS mode */ break; default: if (cred->cr_uid == 0) return rc; /* not interested */ break; } label = (gbl_label_t)(SLOT(curproc->p_textvp->v_label) | SLOT(curproc->p_label)); /* * We look at the extra privs granted * via process label. */ switch (priv) { case PRIV_IPC_READ: case PRIV_IPC_WRITE: if (label & GBL_IPC) rc = 0; break; + case PRIV_PROC_MEM_WRITE: case PRIV_KMEM_READ: case PRIV_KMEM_WRITE: if (label & GBL_KMEM) rc = 0; break; case PRIV_NETINET_BINDANY: case PRIV_NETINET_RESERVEDPORT: /* socket bind low port */ case PRIV_NETINET_REUSEPORT: if (label & GBL_BIND) rc = 0; break; case PRIV_NETINET_ADDRCTRL6: case PRIV_NET_LAGG: case PRIV_NET_SETIFFIB: case PRIV_NET_SETIFVNET: case PRIV_NETINET_SETHDROPTS: case PRIV_NET_VXLAN: case PRIV_NETINET_GETCRED: case PRIV_NETINET_IPSEC: case PRIV_NETINET_RAW: if (label & GBL_NET) rc = 0; break; case PRIV_NETINET_MROUTE: case PRIV_NET_ROUTE: if (label & GBL_RTSOCK) rc = 0; break; case PRIV_PROC_LIMIT: case PRIV_PROC_SETRLIMIT: if (label & GBL_PROC) rc = 0; break; case PRIV_SYSCTL_WRITE: if (label & GBL_SYSCTL) rc = 0; break; case PRIV_VFS_READ: case PRIV_VFS_WRITE: if (label & GBL_KMEM) rc = 0; /* FALLTHROUGH */ case PRIV_VFS_ADMIN: case PRIV_VFS_BLOCKRESERVE: case PRIV_VFS_CHOWN: case PRIV_VFS_EXEC: /* vaccess file and accmode & VEXEC */ case PRIV_VFS_GENERATION: case PRIV_VFS_LOOKUP: /* vaccess DIR */ if (label & GBL_VACCESS) rc = 0; break; case PRIV_VERIEXEC_DIRECT: /* * We are here because we are attempting to direct exec * something with the 'indirect' flag set. * We need to check parent label for this one. */ PROC_LOCK(curproc); label = (gbl_label_t)SLOT(curproc->p_pptr->p_textvp->v_label); if (label & GBL_VERIEXEC) { rc = 0; /* * Of course the only reason to be running an * interpreter this way is to bypass O_VERIFY * so we can run unsigned script. * We set GBL_VERIEXEC on p_label for * PRIV_VERIEXEC_NOVERIFY below */ SLOT_SET(curproc->p_label, GBL_VERIEXEC); } PROC_UNLOCK(curproc); break; case PRIV_VERIEXEC_NOVERIFY: /* we look at p_label! see above */ label = (gbl_label_t)SLOT(curproc->p_label); if (label & GBL_VERIEXEC) rc = 0; break; default: break; } MAC_GRANTBYLABEL_DBG(rc ? 1 : 2, "pid=%d priv=%d, label=%#o rc=%d", curproc->p_pid, priv, label, rc); return rc; } /* * If proc->p_textvp does not yet have a label, * fetch file info from mac_veriexec * and set label (if any) else set. * If there is no label set it to GBL_EMPTY. */ static int mac_grantbylabel_proc_check_resource(struct ucred *cred, struct proc *proc) { gbl_label_t gbl; if (!SLOT(proc->p_textvp->v_label)) { gbl = gbl_get_vlabel(proc->p_textvp, cred); if (gbl == 0) gbl = GBL_EMPTY; SLOT_SET(proc->p_textvp->v_label, gbl); } return 0; } static int mac_grantbylabel_syscall(struct thread *td, int call, void *arg) { cap_rights_t rights; struct mac_grantbylabel_fetch_gbl_args gbl_args; struct file *fp; struct proc *proc; int error; int proc_locked; switch (call) { case MAC_GRANTBYLABEL_FETCH_GBL: case MAC_GRANTBYLABEL_FETCH_PID_GBL: error = copyin(arg, &gbl_args, sizeof(gbl_args)); if (error) return error; gbl_args.gbl = 0; break; default: return EOPNOTSUPP; break; } proc_locked = 0; switch (call) { case MAC_GRANTBYLABEL_FETCH_GBL: error = getvnode(td, gbl_args.u.fd, cap_rights_init(&rights), &fp); if (error) return (error); if (fp->f_type != DTYPE_VNODE) { error = EINVAL; goto cleanup_file; } vn_lock(fp->f_vnode, LK_SHARED | LK_RETRY); gbl_args.gbl = gbl_get_vlabel(fp->f_vnode, td->td_ucred); if (gbl_args.gbl == 0) error = EOPNOTSUPP; else error = 0; VOP_UNLOCK(fp->f_vnode); cleanup_file: fdrop(fp, td); break; case MAC_GRANTBYLABEL_FETCH_PID_GBL: error = 0; if (gbl_args.u.pid == 0 || gbl_args.u.pid == curproc->p_pid) { proc = curproc; } else { proc = pfind(gbl_args.u.pid); if (proc == NULL) return (EINVAL); proc_locked = 1; } gbl_args.gbl = (SLOT(proc->p_textvp->v_label) | SLOT(proc->p_label)); if (proc_locked) PROC_UNLOCK(proc); break; } if (error == 0) { error = copyout(&gbl_args, arg, sizeof(gbl_args)); } return error; } static void mac_grantbylabel_proc_init_label(struct label *label) { SLOT_SET(label, 0); /* not yet set! */ } static void mac_grantbylabel_vnode_init_label(struct label *label) { SLOT_SET(label, 0); /* not yet set! */ } /** * @brief set v_label if needed */ static int mac_grantbylabel_vnode_check_exec(struct ucred *cred __unused, struct vnode *vp __unused, struct label *label __unused, struct image_params *imgp, struct label *execlabel __unused) { gbl_label_t gbl; gbl = SLOT(vp->v_label); if (gbl == 0) { gbl = gbl_get_vlabel(vp, cred); if (gbl == 0) gbl = GBL_EMPTY; MAC_GRANTBYLABEL_DBG(1, "vnode_check_exec label=%#o", gbl); SLOT_SET(vp->v_label, gbl); } return 0; } static void mac_grantbylabel_copy_label(struct label *src, struct label *dest) { SLOT_SET(dest, SLOT(src)); } /** * @brief if interpreting copy script v_label to proc p_label */ static int mac_grantbylabel_vnode_execve_will_transition(struct ucred *old, struct vnode *vp, struct label *vplabel, struct label *interpvplabel, struct image_params *imgp, struct label *execlabel) { gbl_label_t gbl; if (imgp->interpreted) { gbl = SLOT(interpvplabel); if (gbl) { SLOT_SET(imgp->proc->p_label, gbl); } MAC_GRANTBYLABEL_DBG(1, "execve_will_transition label=%#o", gbl); } return 0; } static struct mac_policy_ops mac_grantbylabel_ops = { .mpo_proc_check_resource = mac_grantbylabel_proc_check_resource, .mpo_priv_grant = mac_grantbylabel_priv_grant, .mpo_syscall = mac_grantbylabel_syscall, .mpo_proc_init_label = mac_grantbylabel_proc_init_label, .mpo_vnode_check_exec = mac_grantbylabel_vnode_check_exec, .mpo_vnode_copy_label = mac_grantbylabel_copy_label, .mpo_vnode_execve_will_transition = mac_grantbylabel_vnode_execve_will_transition, .mpo_vnode_init_label = mac_grantbylabel_vnode_init_label, }; MAC_POLICY_SET(&mac_grantbylabel_ops, mac_grantbylabel, MAC_GRANTBYLABEL_FULLNAME, MPC_LOADTIME_FLAG_NOTLATE, &mac_grantbylabel_slot); MODULE_VERSION(mac_grantbylabel, 1); MODULE_DEPEND(mac_grantbylabel, mac_veriexec, MAC_VERIEXEC_VERSION, MAC_VERIEXEC_VERSION, MAC_VERIEXEC_VERSION); diff --git a/sys/security/mac_veriexec/mac_veriexec.c b/sys/security/mac_veriexec/mac_veriexec.c index 7ac09e2acf0f..490601863197 100644 --- a/sys/security/mac_veriexec/mac_veriexec.c +++ b/sys/security/mac_veriexec/mac_veriexec.c @@ -1,1186 +1,1187 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2011-2023 Juniper Networks, Inc. * 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. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 #include "opt_capsicum.h" #include "opt_mac.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef COMPAT_FREEBSD32 #include #include #include #endif #include #include #include #include "mac_veriexec.h" #include "mac_veriexec_internal.h" #define SLOT(l) \ mac_label_get((l), mac_veriexec_slot) #define SLOT_SET(l, v) \ mac_label_set((l), mac_veriexec_slot, (v)) #ifdef MAC_VERIEXEC_DEBUG #define MAC_VERIEXEC_DBG(_lvl, _fmt, ...) \ do { \ VERIEXEC_DEBUG((_lvl), (MAC_VERIEXEC_FULLNAME ": " _fmt \ "\n", ##__VA_ARGS__)); \ } while(0) #else #define MAC_VERIEXEC_DBG(_lvl, _fmt, ...) #endif static int sysctl_mac_veriexec_state(SYSCTL_HANDLER_ARGS); static int sysctl_mac_veriexec_db(SYSCTL_HANDLER_ARGS); static struct mac_policy_ops mac_veriexec_ops; SYSCTL_DECL(_security_mac); SYSCTL_NODE(_security_mac, OID_AUTO, veriexec, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, "MAC/veriexec policy controls"); int mac_veriexec_debug; SYSCTL_INT(_security_mac_veriexec, OID_AUTO, debug, CTLFLAG_RW, &mac_veriexec_debug, 0, "Debug level"); static int mac_veriexec_state; SYSCTL_PROC(_security_mac_veriexec, OID_AUTO, state, CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_NEEDGIANT, 0, 0, sysctl_mac_veriexec_state, "A", "Verified execution subsystem state"); SYSCTL_PROC(_security_mac_veriexec, OID_AUTO, db, CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_SKIP | CTLFLAG_NEEDGIANT, 0, 0, sysctl_mac_veriexec_db, "A", "Verified execution fingerprint database"); static int mac_veriexec_slot; static int mac_veriexec_block_unlink; SYSCTL_INT(_security_mac_veriexec, OID_AUTO, block_unlink, CTLFLAG_RDTUN, &mac_veriexec_block_unlink, 0, "Veriexec unlink protection"); MALLOC_DEFINE(M_VERIEXEC, "veriexec", "Verified execution data"); /** * @internal * @brief Handler for security.mac.veriexec.db sysctl * * Display a human-readable form of the current fingerprint database. */ static int sysctl_mac_veriexec_db(SYSCTL_HANDLER_ARGS) { struct sbuf sb; int error; error = sysctl_wire_old_buffer(req, 0); if (error != 0) return (error); sbuf_new_for_sysctl(&sb, NULL, 1024, req); mac_veriexec_metadata_print_db(&sb); error = sbuf_finish(&sb); sbuf_delete(&sb); return (error); } /** * @internal * @brief Generate human-readable output about the current verified execution * state. * * @param sbp sbuf to write output to */ static void mac_veriexec_print_state(struct sbuf *sbp) { if (mac_veriexec_state & VERIEXEC_STATE_INACTIVE) sbuf_printf(sbp, "inactive "); if (mac_veriexec_state & VERIEXEC_STATE_LOADED) sbuf_printf(sbp, "loaded "); if (mac_veriexec_state & VERIEXEC_STATE_ACTIVE) sbuf_printf(sbp, "active "); if (mac_veriexec_state & VERIEXEC_STATE_ENFORCE) sbuf_printf(sbp, "enforce "); if (mac_veriexec_state & VERIEXEC_STATE_LOCKED) sbuf_printf(sbp, "locked "); if (mac_veriexec_state != 0) sbuf_trim(sbp); } /** * @internal * @brief Handler for security.mac.veriexec.state sysctl * * Display a human-readable form of the current verified execution subsystem * state. */ static int sysctl_mac_veriexec_state(SYSCTL_HANDLER_ARGS) { struct sbuf sb; int error; sbuf_new(&sb, NULL, 128, SBUF_AUTOEXTEND); mac_veriexec_print_state(&sb); sbuf_finish(&sb); error = SYSCTL_OUT(req, sbuf_data(&sb), sbuf_len(&sb)); sbuf_delete(&sb); return (error); } /** * @internal * @brief Event handler called when a virtual file system is mounted. * * We need to record the file system identifier in the MAC per-policy slot * assigned to veriexec, so we have a key to use in order to reference the * mount point in the meta-data store. * * @param arg unused argument * @param mp mount point that is being mounted * @param fsrootvp vnode of the file system root * @param td calling thread */ static void mac_veriexec_vfs_mounted(void *arg __unused, struct mount *mp, struct vnode *fsrootvp, struct thread *td) { struct vattr va; int error; error = VOP_GETATTR(fsrootvp, &va, td->td_ucred); if (error) return; SLOT_SET(mp->mnt_label, va.va_fsid); MAC_VERIEXEC_DBG(3, "set fsid to %ju for mount %p", (uintmax_t)va.va_fsid, mp); } /** * @internal * @brief Event handler called when a virtual file system is unmounted. * * If we recorded a file system identifier in the MAC per-policy slot assigned * to veriexec, then we need to tell the meta-data store to clean up. * * @param arg unused argument * @param mp mount point that is being unmounted * @param td calling thread */ static void mac_veriexec_vfs_unmounted(void *arg __unused, struct mount *mp, struct thread *td) { dev_t fsid; fsid = SLOT(mp->mnt_label); if (fsid) { MAC_VERIEXEC_DBG(3, "fsid %ju, cleaning up mount", (uintmax_t)fsid); mac_veriexec_metadata_unmounted(fsid, td); } } /** * @internal * @brief The mount point is being initialized, set the value in the MAC * per-policy slot for veriexec to zero. * * @note A value of zero in this slot indicates no file system identifier * is assigned. * * @param label the label that is being initialized */ static void mac_veriexec_mount_init_label(struct label *label) { SLOT_SET(label, 0); } /** * @internal * @brief The mount-point is being destroyed, reset the value in the MAC * per-policy slot for veriexec back to zero. * * @note A value of zero in this slot indicates no file system identifier * is assigned. * * @param label the label that is being destroyed */ static void mac_veriexec_mount_destroy_label(struct label *label) { SLOT_SET(label, 0); } /** * @internal * @brief The vnode label is being initialized, set the value in the MAC * per-policy slot for veriexec to @c FINGERPRINT_INVALID * * @note @c FINGERPRINT_INVALID indicates the fingerprint is invalid. * * @param label the label that is being initialized */ static void mac_veriexec_vnode_init_label(struct label *label) { SLOT_SET(label, FINGERPRINT_INVALID); } /** * @internal * @brief The vnode label is being destroyed, reset the value in the MAC * per-policy slot for veriexec back to @c FINGERPRINT_INVALID * * @note @c FINGERPRINT_INVALID indicates the fingerprint is invalid. * * @param label the label that is being destroyed */ static void mac_veriexec_vnode_destroy_label(struct label *label) { SLOT_SET(label, FINGERPRINT_INVALID); } /** * @internal * @brief Copy the value in the MAC per-policy slot assigned to veriexec from * the @p src label to the @p dest label */ static void mac_veriexec_copy_label(struct label *src, struct label *dest) { SLOT_SET(dest, SLOT(src)); } /** * @internal * @brief Check if the requested process can be debugged * * @param cred credentials to use * @param p process to debug * * @return 0 if debugging is allowed, otherwise an error code. */ static int mac_veriexec_proc_check_debug(struct ucred *cred, struct proc *p) { int error, flags; /* If we are not enforcing veriexec, nothing for us to check */ if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0) return (0); error = mac_veriexec_metadata_get_executable_flags(cred, p, &flags, 0); if (error != 0) return (0); error = (flags & (VERIEXEC_NOTRACE|VERIEXEC_TRUSTED)) ? EACCES : 0; MAC_VERIEXEC_DBG(4, "%s flags=%#x error=%d", __func__, flags, error); return (error); } /** * @internal * @brief A KLD load has been requested and needs to be validated. * * @param cred credentials to use * @param vp vnode of the KLD that has been requested * @param vlabel vnode label assigned to the vnode * * @return 0 if the KLD load is allowed, otherwise an error code. */ static int mac_veriexec_kld_check_load(struct ucred *cred, struct vnode *vp, struct label *vlabel) { struct vattr va; struct thread *td = curthread; fingerprint_status_t status; int error; /* * If we are not actively enforcing, allow it */ if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0) return (0); /* Get vnode attributes */ error = VOP_GETATTR(vp, &va, cred); if (error) return (error); /* * Fetch the fingerprint status for the vnode * (starting with files first) */ error = mac_veriexec_metadata_fetch_fingerprint_status(vp, &va, td, VERIEXEC_FILES_FIRST); if (error && error != EAUTH) return (error); /* * By now we should have status... */ status = mac_veriexec_get_fingerprint_status(vp); switch (status) { case FINGERPRINT_FILE: case FINGERPRINT_VALID: case FINGERPRINT_INDIRECT: if (error) return (error); break; default: /* * kldload should fail unless there is a valid fingerprint * registered. */ MAC_VERIEXEC_DBG(2, "fingerprint status is %d for dev %ju, " "file %ju.%ju\n", status, (uintmax_t)va.va_fsid, (uintmax_t)va.va_fileid, (uintmax_t)va.va_gen); return (EAUTH); } /* Everything is good, allow the KLD to be loaded */ return (0); } /** * @internal * @brief Check privileges that veriexec needs to be concerned about. * * The following privileges are checked by this function: * - PRIV_KMEM_WRITE\n * Check if writes to /dev/mem and /dev/kmem are allowed\n * (Only trusted processes are allowed) * - PRIV_VERIEXEC_CONTROL\n * Check if manipulating veriexec is allowed\n * (only trusted processes are allowed) * * @param cred credentials to use * @param priv privilege to check * * @return 0 if the privilege is allowed, error code otherwise. */ static int mac_veriexec_priv_check(struct ucred *cred, int priv) { int error; /* If we are not enforcing veriexec, nothing for us to check */ if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0) return (0); error = 0; switch (priv) { case PRIV_KMEM_WRITE: + case PRIV_PROC_MEM_WRITE: case PRIV_VERIEXEC_CONTROL: /* * Do not allow writing to memory or manipulating veriexec, * unless trusted */ if (mac_veriexec_proc_is_trusted(cred, curproc) == 0 && mac_priv_grant(cred, priv) != 0) error = EPERM; MAC_VERIEXEC_DBG(4, "%s priv=%d error=%d", __func__, priv, error); break; default: break; } return (error); } /** * @internal * @brief Check if the requested sysctl should be allowed * * @param cred credentials to use * @param oidp sysctl OID * @param arg1 first sysctl argument * @param arg2 second sysctl argument * @param req sysctl request information * * @return 0 if the sysctl should be allowed, otherwise an error code. */ static int mac_veriexec_sysctl_check(struct ucred *cred, struct sysctl_oid *oidp, void *arg1, int arg2, struct sysctl_req *req) { struct sysctl_oid *oid; /* If we are not enforcing veriexec, nothing for us to check */ if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0) return (0); oid = oidp; if (req->newptr && (oid->oid_kind & CTLFLAG_SECURE)) { return (EPERM); /* XXX call mac_veriexec_priv_check? */ } return 0; } /** * @internal * @brief A program is being executed and needs to be validated. * * @param cred credentials to use * @param vp vnode of the program that is being executed * @param label vnode label assigned to the vnode * @param imgp parameters for the image to be executed * @param execlabel optional exec label * * @return 0 if the program should be allowed to execute, otherwise an error * code. */ static int mac_veriexec_vnode_check_exec(struct ucred *cred __unused, struct vnode *vp __unused, struct label *label __unused, struct image_params *imgp, struct label *execlabel __unused) { struct thread *td = curthread; int error; error = mac_veriexec_fingerprint_check_image(imgp, 0, td); return (error); } /** * @brief Check fingerprint for the specified vnode and validate it * * @param cred credentials to use * @param vp vnode of the file * @param accmode access mode to check (read, write, append, create, * verify, etc.) * * @return 0 if the file validated, otherwise an error code. */ static int mac_veriexec_check_vp(struct ucred *cred, struct vnode *vp, accmode_t accmode) { struct vattr va; struct thread *td = curthread; fingerprint_status_t status; int error; /* Get vnode attributes */ error = VOP_GETATTR(vp, &va, cred); if (error) return (error); /* Get the fingerprint status for the file */ error = mac_veriexec_metadata_fetch_fingerprint_status(vp, &va, td, VERIEXEC_FILES_FIRST); if (error && error != EAUTH) return (error); /* * By now we should have status... */ status = mac_veriexec_get_fingerprint_status(vp); if (accmode & VWRITE) { /* * If file has a fingerprint then deny the write request, * otherwise invalidate the status so we don't keep checking * for the file having a fingerprint. */ switch (status) { case FINGERPRINT_FILE: case FINGERPRINT_VALID: case FINGERPRINT_INDIRECT: MAC_VERIEXEC_DBG(2, "attempted write to fingerprinted file for dev " "%ju, file %ju.%ju\n", (uintmax_t)va.va_fsid, (uintmax_t)va.va_fileid, (uintmax_t)va.va_gen); return (EPERM); default: break; } } if (accmode & VVERIFY) { switch (status) { case FINGERPRINT_FILE: case FINGERPRINT_VALID: case FINGERPRINT_INDIRECT: if (error) return (error); break; default: /* Allow for overriding verification requirement */ if (mac_priv_grant(cred, PRIV_VERIEXEC_NOVERIFY) == 0) return (0); /* * Caller wants open to fail unless there is a valid * fingerprint registered. */ MAC_VERIEXEC_DBG(2, "fingerprint status is %d for dev " "%ju, file %ju.%ju\n", status, (uintmax_t)va.va_fsid, (uintmax_t)va.va_fileid, (uintmax_t)va.va_gen); return (EAUTH); } } return (0); } /** * @brief Opening a file has been requested and may need to be validated. * * @param cred credentials to use * @param vp vnode of the file to open * @param label vnode label assigned to the vnode * @param accmode access mode to use for opening the file (read, write, * append, create, verify, etc.) * * @return 0 if opening the file should be allowed, otherwise an error code. */ static int mac_veriexec_vnode_check_open(struct ucred *cred, struct vnode *vp, struct label *label __unused, accmode_t accmode) { int error; /* * Look for the file on the fingerprint lists iff it has not been seen * before. */ if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0) return (0); error = mac_veriexec_check_vp(cred, vp, accmode); return (error); } /** * @brief Unlink on a file has been requested and may need to be validated. * * @param cred credentials to use * @param dvp parent directory for file vnode vp * @param dlabel vnode label assigned to the directory vnode * @param vp vnode of the file to unlink * @param label vnode label assigned to the vnode * @param cnp component name for vp * * * @return 0 if opening the file should be allowed, otherwise an error code. */ static int mac_veriexec_vnode_check_unlink(struct ucred *cred, struct vnode *dvp __unused, struct label *dvplabel __unused, struct vnode *vp, struct label *label __unused, struct componentname *cnp __unused) { int error; /* * Look for the file on the fingerprint lists iff it has not been seen * before. */ if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0) return (0); error = mac_veriexec_check_vp(cred, vp, VVERIFY); if (error == 0) { /* * The target is verified, so disallow replacement. */ MAC_VERIEXEC_DBG(2, "(UNLINK) attempted to unlink a protected file (euid: %u)", cred->cr_uid); return (EAUTH); } return (0); } /** * @brief Rename the file has been requested and may need to be validated. * * @param cred credentials to use * @param dvp parent directory for file vnode vp * @param dlabel vnode label assigned to the directory vnode * @param vp vnode of the file to rename * @param label vnode label assigned to the vnode * @param cnp component name for vp * * * @return 0 if opening the file should be allowed, otherwise an error code. */ static int mac_veriexec_vnode_check_rename_from(struct ucred *cred, struct vnode *dvp __unused, struct label *dvplabel __unused, struct vnode *vp, struct label *label __unused, struct componentname *cnp __unused) { int error; /* * Look for the file on the fingerprint lists iff it has not been seen * before. */ if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0) return (0); error = mac_veriexec_check_vp(cred, vp, VVERIFY); if (error == 0) { /* * The target is verified, so disallow replacement. */ MAC_VERIEXEC_DBG(2, "(RENAME_FROM) attempted to rename a protected file (euid: %u)", cred->cr_uid); return (EAUTH); } return (0); } /** * @brief Rename to file into the directory (overwrite the file name) has been * requested and may need to be validated. * * @param cred credentials to use * @param dvp parent directory for file vnode vp * @param dlabel vnode label assigned to the directory vnode * @param vp vnode of the overwritten file * @param label vnode label assigned to the vnode * @param samedir 1 if the source and destination directories are the same * @param cnp component name for vp * * * @return 0 if opening the file should be allowed, otherwise an error code. */ static int mac_veriexec_vnode_check_rename_to(struct ucred *cred, struct vnode *dvp __unused, struct label *dvplabel __unused, struct vnode *vp, struct label *label __unused, int samedir __unused, struct componentname *cnp __unused) { int error; /* * If there is no existing file to overwrite, vp and label will be * NULL. */ if (vp == NULL) return (0); /* * Look for the file on the fingerprint lists iff it has not been seen * before. */ if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0) return (0); error = mac_veriexec_check_vp(cred, vp, VVERIFY); if (error == 0) { /* * The target is verified, so disallow replacement. */ MAC_VERIEXEC_DBG(2, "(RENAME_TO) attempted to overwrite a protected file (euid: %u)", cred->cr_uid); return (EAUTH); } return (0); } /** * @brief Check mode changes on file to ensure they should be allowed. * * We cannot allow chmod of SUID or SGID on verified files. * * @param cred credentials to use * @param vp vnode of the file to open * @param label vnode label assigned to the vnode * @param mode mode flags to set * * @return 0 if the mode change should be allowed, EAUTH otherwise. */ static int mac_veriexec_vnode_check_setmode(struct ucred *cred, struct vnode *vp, struct label *label __unused, mode_t mode) { int error; if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0) return (0); /* * Prohibit chmod of verified set-[gu]id file. */ error = mac_veriexec_check_vp(cred, vp, VVERIFY); if (error == EAUTH) /* target not verified */ return (0); if (error == 0 && (mode & (S_ISUID|S_ISGID)) != 0) return (EAUTH); return (0); } /** * @internal * @brief Initialize the mac_veriexec MAC policy * * @param mpc MAC policy configuration */ static void mac_veriexec_init(struct mac_policy_conf *mpc __unused) { /* Initialize state */ mac_veriexec_state = VERIEXEC_STATE_INACTIVE; /* Initialize meta-data storage */ mac_veriexec_metadata_init(); /* Initialize fingerprint ops */ mac_veriexec_fingerprint_init(); /* Register event handlers */ EVENTHANDLER_REGISTER(vfs_mounted, mac_veriexec_vfs_mounted, NULL, EVENTHANDLER_PRI_FIRST); EVENTHANDLER_REGISTER(vfs_unmounted, mac_veriexec_vfs_unmounted, NULL, EVENTHANDLER_PRI_LAST); /* Check if unlink control is activated via tunable value */ if (!mac_veriexec_block_unlink) mac_veriexec_ops.mpo_vnode_check_unlink = NULL; } #ifdef COMPAT_FREEBSD32 struct mac_veriexec_syscall_params32 { char fp_type[VERIEXEC_FPTYPELEN]; unsigned char fingerprint[MAXFINGERPRINTLEN]; char label[MAXLABELLEN]; uint32_t labellen; unsigned char flags; }; struct mac_veriexec_syscall_params_args32 { union { pid_t pid; uint32_t filename; } u; /* input only */ uint32_t params; /* result */ }; #endif /** * @internal * @brief MAC policy-specific syscall for mac_veriexec * * The following syscalls are implemented: * - @c MAC_VERIEXEC_CHECK_SYSCALL * Check if the file referenced by a file descriptor has a fingerprint * registered in the meta-data store. * * @param td calling thread * @param call system call number * @param arg arugments to the syscall * * @return 0 on success, otherwise an error code. */ static int mac_veriexec_syscall(struct thread *td, int call, void *arg) { struct image_params img; struct nameidata nd; cap_rights_t rights; struct vattr va; struct file *fp; struct mac_veriexec_syscall_params_args pargs; struct mac_veriexec_syscall_params result; #ifdef COMPAT_FREEBSD32 struct mac_veriexec_syscall_params_args32 pargs32; struct mac_veriexec_syscall_params32 result32; #endif struct mac_veriexec_file_info *ip; struct proc *proc; struct vnode *textvp; int error, flags, proc_locked; nd.ni_vp = NULL; proc_locked = 0; textvp = NULL; switch (call) { case MAC_VERIEXEC_GET_PARAMS_PID_SYSCALL: case MAC_VERIEXEC_GET_PARAMS_PATH_SYSCALL: #ifdef COMPAT_FREEBSD32 if (SV_PROC_FLAG(td->td_proc, SV_ILP32)) { error = copyin(arg, &pargs32, sizeof(pargs32)); if (error) return error; bzero(&pargs, sizeof(pargs)); switch (call) { case MAC_VERIEXEC_GET_PARAMS_PID_SYSCALL: CP(pargs32, pargs, u.pid); break; case MAC_VERIEXEC_GET_PARAMS_PATH_SYSCALL: PTRIN_CP(pargs32, pargs, u.filename); break; } PTRIN_CP(pargs32, pargs, params); } else #endif error = copyin(arg, &pargs, sizeof(pargs)); if (error) return error; break; } switch (call) { case MAC_VERIEXEC_CHECK_FD_SYSCALL: /* Get the vnode associated with the file descriptor passed */ error = getvnode(td, (uintptr_t) arg, cap_rights_init_one(&rights, CAP_READ), &fp); if (error) return (error); if (fp->f_type != DTYPE_VNODE) { MAC_VERIEXEC_DBG(3, "MAC_VERIEXEC_CHECK_SYSCALL: " "file is not vnode type (type=0x%x)", fp->f_type); error = EINVAL; goto cleanup_file; } /* * setup the bits of image_params that are used by * mac_veriexec_check_fingerprint(). */ bzero(&img, sizeof(img)); img.proc = td->td_proc; img.vp = fp->f_vnode; img.attr = &va; /* * Get vnode attributes * (need to obtain a lock on the vnode first) */ vn_lock(img.vp, LK_EXCLUSIVE | LK_RETRY); error = VOP_GETATTR(fp->f_vnode, &va, td->td_ucred); if (error) goto check_done; MAC_VERIEXEC_DBG(2, "mac_veriexec_fingerprint_check_image: " "va_mode=%o, check_files=%d\n", va.va_mode, ((va.va_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0)); error = mac_veriexec_fingerprint_check_image(&img, ((va.va_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0), td); check_done: /* Release the lock we obtained earlier */ VOP_UNLOCK(img.vp); cleanup_file: fdrop(fp, td); break; case MAC_VERIEXEC_CHECK_PATH_SYSCALL: /* Look up the path to get the vnode */ NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | LOCKSHARED | AUDITVNODE1, UIO_USERSPACE, arg); flags = FREAD; error = vn_open(&nd, &flags, 0, NULL); if (error != 0) break; NDFREE_PNBUF(&nd); /* Check the fingerprint status of the vnode */ error = mac_veriexec_check_vp(td->td_ucred, nd.ni_vp, VVERIFY); /* nd.ni_vp cleaned up below */ break; case MAC_VERIEXEC_GET_PARAMS_PID_SYSCALL: if (pargs.u.pid == 0 || pargs.u.pid == curproc->p_pid) { proc = curproc; } else { proc = pfind(pargs.u.pid); if (proc == NULL) return (EINVAL); proc_locked = 1; } textvp = proc->p_textvp; /* FALLTHROUGH */ case MAC_VERIEXEC_GET_PARAMS_PATH_SYSCALL: if (textvp == NULL) { /* Look up the path to get the vnode */ NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | AUDITVNODE1, UIO_USERSPACE, pargs.u.filename); flags = FREAD; error = vn_open(&nd, &flags, 0, NULL); if (error != 0) break; NDFREE_PNBUF(&nd); textvp = nd.ni_vp; } error = VOP_GETATTR(textvp, &va, curproc->p_ucred); if (proc_locked) PROC_UNLOCK(proc); if (error != 0) break; error = mac_veriexec_metadata_get_file_info(va.va_fsid, va.va_fileid, va.va_gen, NULL, &ip, FALSE); if (error != 0) break; #ifdef COMPAT_FREEBSD32 if (SV_PROC_FLAG(td->td_proc, SV_ILP32)) { bzero(&result32, sizeof(result32)); result32.flags = ip->flags; strlcpy(result32.fp_type, ip->ops->type, sizeof(result32.fp_type)); result.labellen = ip->labellen; CP(result, result32, labellen); if (ip->labellen > 0) strlcpy(result32.label, ip->label, sizeof(result32.label)); result32.label[result.labellen] = '\0'; memcpy(result32.fingerprint, ip->fingerprint, ip->ops->digest_len); error = copyout(&result32, pargs.params, sizeof(result32)); break; /* yes */ } #endif bzero(&result, sizeof(result)); result.flags = ip->flags; strlcpy(result.fp_type, ip->ops->type, sizeof(result.fp_type)); result.labellen = ip->labellen; if (ip->labellen > 0) strlcpy(result.label, ip->label, sizeof(result.label)); result.label[result.labellen] = '\0'; memcpy(result.fingerprint, ip->fingerprint, ip->ops->digest_len); error = copyout(&result, pargs.params, sizeof(result)); break; default: error = EOPNOTSUPP; } if (nd.ni_vp != NULL) { VOP_UNLOCK(nd.ni_vp); vn_close(nd.ni_vp, FREAD, td->td_ucred, td); } return (error); } static struct mac_policy_ops mac_veriexec_ops = { .mpo_init = mac_veriexec_init, .mpo_kld_check_load = mac_veriexec_kld_check_load, .mpo_mount_destroy_label = mac_veriexec_mount_destroy_label, .mpo_mount_init_label = mac_veriexec_mount_init_label, .mpo_priv_check = mac_veriexec_priv_check, .mpo_proc_check_debug = mac_veriexec_proc_check_debug, .mpo_syscall = mac_veriexec_syscall, .mpo_system_check_sysctl = mac_veriexec_sysctl_check, .mpo_vnode_check_exec = mac_veriexec_vnode_check_exec, .mpo_vnode_check_open = mac_veriexec_vnode_check_open, .mpo_vnode_check_unlink = mac_veriexec_vnode_check_unlink, .mpo_vnode_check_rename_to = mac_veriexec_vnode_check_rename_to, .mpo_vnode_check_rename_from = mac_veriexec_vnode_check_rename_from, .mpo_vnode_check_setmode = mac_veriexec_vnode_check_setmode, .mpo_vnode_copy_label = mac_veriexec_copy_label, .mpo_vnode_destroy_label = mac_veriexec_vnode_destroy_label, .mpo_vnode_init_label = mac_veriexec_vnode_init_label, }; MAC_POLICY_SET(&mac_veriexec_ops, mac_veriexec, MAC_VERIEXEC_FULLNAME, MPC_LOADTIME_FLAG_NOTLATE, &mac_veriexec_slot); MODULE_VERSION(mac_veriexec, MAC_VERIEXEC_VERSION); static struct vnode * mac_veriexec_bottom_vnode(struct vnode *vp) { struct vnode *ldvp = NULL; /* * XXX This code is bogus. nullfs is not the only stacking * filesystem. Less bogus code would add a VOP to reach bottom * vnode and would not make assumptions how to get there. */ if (vp->v_mount != NULL && strcmp(vp->v_mount->mnt_vfc->vfc_name, "nullfs") == 0) ldvp = NULLVPTOLOWERVP(vp); return (ldvp); } /** * @brief Get the fingerprint status set on a vnode. * * @param vp vnode to obtain fingerprint status from * * @return Fingerprint status assigned to the vnode. */ fingerprint_status_t mac_veriexec_get_fingerprint_status(struct vnode *vp) { fingerprint_status_t fps; struct vnode *ldvp; fps = SLOT(vp->v_label); switch (fps) { case FINGERPRINT_VALID: case FINGERPRINT_INDIRECT: case FINGERPRINT_FILE: break; default: /* we may need to recurse */ ldvp = mac_veriexec_bottom_vnode(vp); if (ldvp != NULL) return mac_veriexec_get_fingerprint_status(ldvp); break; } return fps; } /** * @brief Get the current verified execution subsystem state. * * @return Current set of verified execution subsystem state flags. */ int mac_veriexec_get_state(void) { return (mac_veriexec_state); } /** * @brief Determine if the verified execution subsystem state has specific * flags set. * * @param state mask of flags to check * * @return State flags set within the masked bits */ int mac_veriexec_in_state(int state) { return (mac_veriexec_state & state); } /** * @brief Set the fingerprint status for a vnode * * Fingerprint status is stored in the MAC per-policy slot assigned to * mac_veriexec. * * @param vp vnode to store the fingerprint status on * @param fp_status fingerprint status to store */ void mac_veriexec_set_fingerprint_status(struct vnode *vp, fingerprint_status_t fp_status) { struct vnode *ldvp; /* recurse until we find the real storage */ ldvp = mac_veriexec_bottom_vnode(vp); if (ldvp != NULL) { mac_veriexec_set_fingerprint_status(ldvp, fp_status); return; } SLOT_SET(vp->v_label, fp_status); } /** * @brief Set verified execution subsystem state flags * * @note Flags can only be added to the current state, not removed. * * @param state state flags to add to the current state */ void mac_veriexec_set_state(int state) { mac_veriexec_state |= state; } /** * @brief Determine if the process is trusted * * @param cred credentials to use * @param p the process in question * * @return 1 if the process is trusted, otherwise 0. */ int mac_veriexec_proc_is_trusted(struct ucred *cred, struct proc *p) { int already_locked, error, flags; /* Make sure we lock the process if we do not already have the lock */ already_locked = PROC_LOCKED(p); if (!already_locked) PROC_LOCK(p); error = mac_veriexec_metadata_get_executable_flags(cred, p, &flags, 0); /* Unlock the process if we locked it previously */ if (!already_locked) PROC_UNLOCK(p); /* Any errors, deny access */ if (error != 0) return (0); /* Check that the trusted flag is set */ return ((flags & VERIEXEC_TRUSTED) == VERIEXEC_TRUSTED); } diff --git a/sys/sys/priv.h b/sys/sys/priv.h index a61de8d32fe0..7a5773da220f 100644 --- a/sys/sys/priv.h +++ b/sys/sys/priv.h @@ -1,559 +1,560 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2006 nCircle Network Security, Inc. * All rights reserved. * * This software was developed by Robert N. M. Watson for the TrustedBSD * Project under contract to nCircle Network Security, Inc. * * 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, NCIRCLE NETWORK SECURITY, * INC., 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. */ /* * Privilege checking interface for BSD kernel. */ #ifndef _SYS_PRIV_H_ #define _SYS_PRIV_H_ /* * Privilege list, sorted loosely by kernel subsystem. * * Think carefully before adding or reusing one of these privileges -- are * there existing instances referring to the same privilege? Third party * vendors may request the assignment of privileges to be used in loadable * modules. Particular numeric privilege assignments are part of the * loadable kernel module ABI, and should not be changed across minor * releases. * * When adding a new privilege, remember to determine if it's appropriate * for use in jail, and update the privilege switch in prison_priv_check() * in kern_jail.c as necessary. */ /* * Track beginning of privilege list. */ #define _PRIV_LOWEST 1 /* * The remaining privileges typically correspond to one or a small * number of specific privilege checks, and have (relatively) precise * meanings. They are loosely sorted into a set of base system * privileges, such as the ability to reboot, and then loosely by * subsystem, indicated by a subsystem name. */ #define _PRIV_ROOT 1 /* Removed. */ #define PRIV_ACCT 2 /* Manage process accounting. */ #define PRIV_MAXFILES 3 /* Exceed system open files limit. */ #define PRIV_MAXPROC 4 /* Exceed system processes limit. */ #define PRIV_KTRACE 5 /* Set/clear KTRFAC_ROOT on ktrace. */ #define PRIV_SETDUMPER 6 /* Configure dump device. */ #define PRIV_REBOOT 8 /* Can reboot system. */ #define PRIV_SWAPON 9 /* Can swapon(). */ #define PRIV_SWAPOFF 10 /* Can swapoff(). */ #define PRIV_MSGBUF 11 /* Can read kernel message buffer. */ #define PRIV_IO 12 /* Can perform low-level I/O. */ #define PRIV_KEYBOARD 13 /* Reprogram keyboard. */ #define PRIV_DRIVER 14 /* Low-level driver privilege. */ #define PRIV_ADJTIME 15 /* Set time adjustment. */ #define PRIV_NTP_ADJTIME 16 /* Set NTP time adjustment. */ #define PRIV_CLOCK_SETTIME 17 /* Can call clock_settime. */ #define PRIV_SETTIMEOFDAY 18 /* Can call settimeofday. */ #define _PRIV_SETHOSTID 19 /* Removed. */ #define _PRIV_SETDOMAINNAME 20 /* Removed. */ /* * Audit subsystem privileges. */ #define PRIV_AUDIT_CONTROL 40 /* Can configure audit. */ #define PRIV_AUDIT_FAILSTOP 41 /* Can run during audit fail stop. */ #define PRIV_AUDIT_GETAUDIT 42 /* Can get proc audit properties. */ #define PRIV_AUDIT_SETAUDIT 43 /* Can set proc audit properties. */ #define PRIV_AUDIT_SUBMIT 44 /* Can submit an audit record. */ /* * Credential management privileges. */ #define PRIV_CRED_SETUID 50 /* setuid. */ #define PRIV_CRED_SETEUID 51 /* seteuid to !ruid and !svuid. */ #define PRIV_CRED_SETGID 52 /* setgid. */ #define PRIV_CRED_SETEGID 53 /* setgid to !rgid and !svgid. */ #define PRIV_CRED_SETGROUPS 54 /* Set process additional groups. */ #define PRIV_CRED_SETREUID 55 /* setreuid. */ #define PRIV_CRED_SETREGID 56 /* setregid. */ #define PRIV_CRED_SETRESUID 57 /* setresuid. */ #define PRIV_CRED_SETRESGID 58 /* setresgid. */ #define PRIV_SEEOTHERGIDS 59 /* Exempt bsd.seeothergids. */ #define PRIV_SEEOTHERUIDS 60 /* Exempt bsd.seeotheruids. */ #define PRIV_SEEJAILPROC 61 /* Exempt from bsd.see_jail_proc. */ /* * Debugging privileges. */ #define PRIV_DEBUG_DIFFCRED 80 /* Exempt debugging other users. */ #define PRIV_DEBUG_SUGID 81 /* Exempt debugging setuid proc. */ #define PRIV_DEBUG_UNPRIV 82 /* Exempt unprivileged debug limit. */ #define PRIV_DEBUG_DENIED 83 /* Exempt P2_NOTRACE. */ /* * Dtrace privileges. */ #define PRIV_DTRACE_KERNEL 90 /* Allow use of DTrace on the kernel. */ #define PRIV_DTRACE_PROC 91 /* Allow attaching DTrace to process. */ #define PRIV_DTRACE_USER 92 /* Process may submit DTrace events. */ /* * Firmware privilegs. */ #define PRIV_FIRMWARE_LOAD 100 /* Can load firmware. */ /* * Jail privileges. */ #define PRIV_JAIL_ATTACH 110 /* Attach to a jail. */ #define PRIV_JAIL_SET 111 /* Set jail parameters. */ #define PRIV_JAIL_REMOVE 112 /* Remove a jail. */ /* * Kernel environment privileges. */ #define PRIV_KENV_SET 120 /* Set kernel env. variables. */ #define PRIV_KENV_UNSET 121 /* Unset kernel env. variables. */ /* * Loadable kernel module privileges. */ #define PRIV_KLD_LOAD 130 /* Load a kernel module. */ #define PRIV_KLD_UNLOAD 131 /* Unload a kernel module. */ /* * Privileges associated with the MAC Framework and specific MAC policy * modules. */ #define PRIV_MAC_PARTITION 140 /* Privilege in mac_partition policy. */ #define PRIV_MAC_PRIVS 141 /* Privilege in the mac_privs policy. */ /* * Process-related privileges. */ #define PRIV_PROC_LIMIT 160 /* Exceed user process limit. */ #define PRIV_PROC_SETLOGIN 161 /* Can call setlogin. */ #define PRIV_PROC_SETRLIMIT 162 /* Can raise resources limits. */ #define PRIV_PROC_SETLOGINCLASS 163 /* Can call setloginclass(2). */ /* * System V IPC privileges. */ #define PRIV_IPC_READ 170 /* Can override IPC read perm. */ #define PRIV_IPC_WRITE 171 /* Can override IPC write perm. */ #define PRIV_IPC_ADMIN 172 /* Can override IPC owner-only perm. */ #define PRIV_IPC_MSGSIZE 173 /* Exempt IPC message queue limit. */ /* * POSIX message queue privileges. */ #define PRIV_MQ_ADMIN 180 /* Can override msgq owner-only perm. */ /* * Performance monitoring counter privileges. */ #define PRIV_PMC_MANAGE 190 /* Can administer PMC. */ #define PRIV_PMC_SYSTEM 191 /* Can allocate a system-wide PMC. */ /* * Scheduling privileges. */ #define PRIV_SCHED_DIFFCRED 200 /* Exempt scheduling other users. */ #define PRIV_SCHED_SETPRIORITY 201 /* Can set lower nice value for proc. */ #define PRIV_SCHED_RTPRIO 202 /* Can set real time scheduling. */ #define PRIV_SCHED_SETPOLICY 203 /* Can set scheduler policy. */ #define PRIV_SCHED_SET 204 /* Can set thread scheduler. */ #define PRIV_SCHED_SETPARAM 205 /* Can set thread scheduler params. */ #define PRIV_SCHED_CPUSET 206 /* Can manipulate cpusets. */ #define PRIV_SCHED_CPUSET_INTR 207 /* Can adjust IRQ to CPU binding. */ #define PRIV_SCHED_IDPRIO 208 /* Can set idle time scheduling. */ /* * POSIX semaphore privileges. */ #define PRIV_SEM_WRITE 220 /* Can override sem write perm. */ /* * Signal privileges. */ #define PRIV_SIGNAL_DIFFCRED 230 /* Exempt signalling other users. */ #define PRIV_SIGNAL_SUGID 231 /* Non-conserv signal setuid proc. */ /* * Sysctl privileges. */ #define PRIV_SYSCTL_DEBUG 240 /* Can invoke sysctl.debug. */ #define PRIV_SYSCTL_WRITE 241 /* Can write sysctls. */ #define PRIV_SYSCTL_WRITEJAIL 242 /* Can write sysctls, jail permitted. */ /* * TTY privileges. */ #define PRIV_TTY_CONSOLE 250 /* Set console to tty. */ #define PRIV_TTY_DRAINWAIT 251 /* Set tty drain wait time. */ #define PRIV_TTY_DTRWAIT 252 /* Set DTR wait on tty. */ #define PRIV_TTY_EXCLUSIVE 253 /* Override tty exclusive flag. */ #define _PRIV_TTY_PRISON 254 /* Removed. */ #define PRIV_TTY_STI 255 /* Simulate input on another tty. */ #define PRIV_TTY_SETA 256 /* Set tty termios structure. */ /* * UFS-specific privileges. */ #define PRIV_UFS_EXTATTRCTL 270 /* Can configure EAs on UFS1. */ #define PRIV_UFS_QUOTAOFF 271 /* quotaoff(). */ #define PRIV_UFS_QUOTAON 272 /* quotaon(). */ #define PRIV_UFS_SETUSE 273 /* setuse(). */ /* * ZFS-specific privileges. */ #define PRIV_ZFS_POOL_CONFIG 280 /* Can configure ZFS pools. */ #define PRIV_ZFS_INJECT 281 /* Can inject faults in the ZFS fault injection framework. */ #define PRIV_ZFS_JAIL 282 /* Can attach/detach ZFS file systems to/from jails. */ /* * NFS-specific privileges. */ #define PRIV_NFS_DAEMON 290 /* Can become the NFS daemon. */ #define PRIV_NFS_LOCKD 291 /* Can become NFS lock daemon. */ /* * VFS privileges. */ #define PRIV_VFS_READ 310 /* Override vnode DAC read perm. */ #define PRIV_VFS_WRITE 311 /* Override vnode DAC write perm. */ #define PRIV_VFS_ADMIN 312 /* Override vnode DAC admin perm. */ #define PRIV_VFS_EXEC 313 /* Override vnode DAC exec perm. */ #define PRIV_VFS_LOOKUP 314 /* Override vnode DAC lookup perm. */ #define PRIV_VFS_BLOCKRESERVE 315 /* Can use free block reserve. */ #define PRIV_VFS_CHFLAGS_DEV 316 /* Can chflags() a device node. */ #define PRIV_VFS_CHOWN 317 /* Can set user; group to non-member. */ #define PRIV_VFS_CHROOT 318 /* chroot(). */ #define PRIV_VFS_RETAINSUGID 319 /* Can retain sugid bits on change. */ #define PRIV_VFS_EXCEEDQUOTA 320 /* Exempt from quota restrictions. */ #define PRIV_VFS_EXTATTR_SYSTEM 321 /* Operate on system EA namespace. */ #define PRIV_VFS_FCHROOT 322 /* fchroot(). */ #define PRIV_VFS_FHOPEN 323 /* Can fhopen(). */ #define PRIV_VFS_FHSTAT 324 /* Can fhstat(). */ #define PRIV_VFS_FHSTATFS 325 /* Can fhstatfs(). */ #define PRIV_VFS_GENERATION 326 /* stat() returns generation number. */ #define PRIV_VFS_GETFH 327 /* Can retrieve file handles. */ #define PRIV_VFS_GETQUOTA 328 /* getquota(). */ #define PRIV_VFS_LINK 329 /* bsd.hardlink_check_uid */ #define PRIV_VFS_MKNOD_BAD 330 /* Was: mknod() can mark bad inodes. */ #define PRIV_VFS_MKNOD_DEV 331 /* Can mknod() to create dev nodes. */ #define PRIV_VFS_MKNOD_WHT 332 /* Can mknod() to create whiteout. */ #define PRIV_VFS_MOUNT 333 /* Can mount(). */ #define PRIV_VFS_MOUNT_OWNER 334 /* Can manage other users' file systems. */ #define PRIV_VFS_MOUNT_EXPORTED 335 /* Can set MNT_EXPORTED on mount. */ #define PRIV_VFS_MOUNT_PERM 336 /* Override dev node perms at mount. */ #define PRIV_VFS_MOUNT_SUIDDIR 337 /* Can set MNT_SUIDDIR on mount. */ #define PRIV_VFS_MOUNT_NONUSER 338 /* Can perform a non-user mount. */ #define PRIV_VFS_SETGID 339 /* Can setgid if not in group. */ #define PRIV_VFS_SETQUOTA 340 /* setquota(). */ #define PRIV_VFS_STICKYFILE 341 /* Can set sticky bit on file. */ #define PRIV_VFS_SYSFLAGS 342 /* Can modify system flags. */ #define PRIV_VFS_UNMOUNT 343 /* Can unmount(). */ #define PRIV_VFS_STAT 344 /* Override vnode MAC stat perm. */ #define PRIV_VFS_READ_DIR 345 /* Can read(2) a dirfd, needs sysctl. */ /* * Virtual memory privileges. */ #define PRIV_VM_MADV_PROTECT 360 /* Can set MADV_PROTECT. */ #define PRIV_VM_MLOCK 361 /* Can mlock(), mlockall(). */ #define PRIV_VM_MUNLOCK 362 /* Can munlock(), munlockall(). */ #define PRIV_VM_SWAP_NOQUOTA 363 /* * Can override the global * swap reservation limits. */ #define PRIV_VM_SWAP_NORLIMIT 364 /* * Can override the per-uid * swap reservation limits. */ /* * Device file system privileges. */ #define PRIV_DEVFS_RULE 370 /* Can manage devfs rules. */ #define PRIV_DEVFS_SYMLINK 371 /* Can create symlinks in devfs. */ /* * Random number generator privileges. */ #define PRIV_RANDOM_RESEED 380 /* Closing /dev/random reseeds. */ /* * Network stack privileges. */ #define PRIV_NET_BRIDGE 390 /* Administer bridge. */ #define PRIV_NET_GRE 391 /* Administer GRE. */ #define _PRIV_NET_PPP 392 /* Removed. */ #define _PRIV_NET_SLIP 393 /* Removed. */ #define PRIV_NET_BPF 394 /* Monitor BPF. */ #define PRIV_NET_RAW 395 /* Open raw socket. */ #define PRIV_NET_ROUTE 396 /* Administer routing. */ #define PRIV_NET_TAP 397 /* Can open tap device. */ #define PRIV_NET_SETIFMTU 398 /* Set interface MTU. */ #define PRIV_NET_SETIFFLAGS 399 /* Set interface flags. */ #define PRIV_NET_SETIFCAP 400 /* Set interface capabilities. */ #define PRIV_NET_SETIFNAME 401 /* Set interface name. */ #define PRIV_NET_SETIFMETRIC 402 /* Set interface metrics. */ #define PRIV_NET_SETIFPHYS 403 /* Set interface physical layer prop. */ #define PRIV_NET_SETIFMAC 404 /* Set interface MAC label. */ #define PRIV_NET_ADDMULTI 405 /* Add multicast addr. to ifnet. */ #define PRIV_NET_DELMULTI 406 /* Delete multicast addr. from ifnet. */ #define PRIV_NET_HWIOCTL 407 /* Issue hardware ioctl on ifnet. */ #define PRIV_NET_SETLLADDR 408 /* Set interface link-level address. */ #define PRIV_NET_ADDIFGROUP 409 /* Add new interface group. */ #define PRIV_NET_DELIFGROUP 410 /* Delete interface group. */ #define PRIV_NET_IFCREATE 411 /* Create cloned interface. */ #define PRIV_NET_IFDESTROY 412 /* Destroy cloned interface. */ #define PRIV_NET_ADDIFADDR 413 /* Add protocol addr to interface. */ #define PRIV_NET_DELIFADDR 414 /* Delete protocol addr on interface. */ #define PRIV_NET_LAGG 415 /* Administer lagg interface. */ #define PRIV_NET_GIF 416 /* Administer gif interface. */ #define PRIV_NET_SETIFVNET 417 /* Move interface to vnet. */ #define PRIV_NET_SETIFDESCR 418 /* Set interface description. */ #define PRIV_NET_SETIFFIB 419 /* Set interface fib. */ #define PRIV_NET_VXLAN 420 /* Administer vxlan. */ #define PRIV_NET_SETLANPCP 421 /* Set LAN priority. */ #define PRIV_NET_SETVLANPCP PRIV_NET_SETLANPCP /* Alias Set VLAN priority */ #define PRIV_NET_OVPN 422 /* Administer OpenVPN DCO. */ #define PRIV_NET_ME 423 /* Administer ME interface. */ #define PRIV_NET_WG 424 /* Administer WireGuard interface. */ /* * 802.11-related privileges. */ #define PRIV_NET80211_VAP_GETKEY 440 /* Query VAP 802.11 keys. */ #define PRIV_NET80211_VAP_MANAGE 441 /* Administer 802.11 VAP */ #define PRIV_NET80211_VAP_SETMAC 442 /* Set VAP MAC address */ #define PRIV_NET80211_CREATE_VAP 443 /* Create a new VAP */ /* * Placeholder for AppleTalk privileges, not supported anymore. */ #define _PRIV_NETATALK_RESERVEDPORT 450 /* Bind low port number. */ /* * ATM privileges. */ #define PRIV_NETATM_CFG 460 #define PRIV_NETATM_ADD 461 #define PRIV_NETATM_DEL 462 #define PRIV_NETATM_SET 463 /* * Bluetooth privileges. */ #define PRIV_NETBLUETOOTH_RAW 470 /* Open raw bluetooth socket. */ /* * Netgraph and netgraph module privileges. */ #define PRIV_NETGRAPH_CONTROL 480 /* Open netgraph control socket. */ #define PRIV_NETGRAPH_TTY 481 /* Configure tty for netgraph. */ /* * IPv4 and IPv6 privileges. */ #define PRIV_NETINET_RESERVEDPORT 490 /* Bind low port number. */ #define PRIV_NETINET_IPFW 491 /* Administer IPFW firewall. */ #define PRIV_NETINET_DIVERT 492 /* Open IP divert socket. */ #define PRIV_NETINET_PF 493 /* Administer pf firewall. */ #define PRIV_NETINET_DUMMYNET 494 /* Administer DUMMYNET. */ #define PRIV_NETINET_CARP 495 /* Administer CARP. */ #define PRIV_NETINET_MROUTE 496 /* Administer multicast routing. */ #define PRIV_NETINET_RAW 497 /* Open netinet raw socket. */ #define PRIV_NETINET_GETCRED 498 /* Query netinet pcb credentials. */ #define PRIV_NETINET_ADDRCTRL6 499 /* Administer IPv6 address scopes. */ #define PRIV_NETINET_ND6 500 /* Administer IPv6 neighbor disc. */ #define PRIV_NETINET_SCOPE6 501 /* Administer IPv6 address scopes. */ #define PRIV_NETINET_ALIFETIME6 502 /* Administer IPv6 address lifetimes. */ #define PRIV_NETINET_IPSEC 503 /* Administer IPSEC. */ #define PRIV_NETINET_REUSEPORT 504 /* Allow [rapid] port/address reuse. */ #define PRIV_NETINET_SETHDROPTS 505 /* Set certain IPv4/6 header options. */ #define PRIV_NETINET_BINDANY 506 /* Allow bind to any address. */ #define PRIV_NETINET_HASHKEY 507 /* Get and set hash keys for IPv4/6. */ /* * Placeholders for IPX/SPX privileges, not supported any more. */ #define _PRIV_NETIPX_RESERVEDPORT 520 /* Bind low port number. */ #define _PRIV_NETIPX_RAW 521 /* Open netipx raw socket. */ /* * NCP privileges. */ #define PRIV_NETNCP 530 /* Use another user's connection. */ /* * SMB privileges. */ #define PRIV_NETSMB 540 /* Use another user's connection. */ /* * VM86 privileges. */ #define PRIV_VM86_INTCALL 550 /* Allow invoking vm86 int handlers. */ /* * Set of reserved privilege values, which will be allocated to code as * needed, in order to avoid renumbering later privileges due to insertion. */ #define _PRIV_RESERVED0 560 #define _PRIV_RESERVED1 561 #define _PRIV_RESERVED2 562 #define _PRIV_RESERVED3 563 #define _PRIV_RESERVED4 564 #define _PRIV_RESERVED5 565 #define _PRIV_RESERVED6 566 #define _PRIV_RESERVED7 567 #define _PRIV_RESERVED8 568 #define _PRIV_RESERVED9 569 #define _PRIV_RESERVED10 570 #define _PRIV_RESERVED11 571 #define _PRIV_RESERVED12 572 #define _PRIV_RESERVED13 573 #define _PRIV_RESERVED14 574 #define _PRIV_RESERVED15 575 /* * Define a set of valid privilege numbers that can be used by loadable * modules that don't yet have privilege reservations. Ideally, these should * not be used, since their meaning is opaque to any policies that are aware * of specific privileges, such as jail, and as such may be arbitrarily * denied. */ #define PRIV_MODULE0 600 #define PRIV_MODULE1 601 #define PRIV_MODULE2 602 #define PRIV_MODULE3 603 #define PRIV_MODULE4 604 #define PRIV_MODULE5 605 #define PRIV_MODULE6 606 #define PRIV_MODULE7 607 #define PRIV_MODULE8 608 #define PRIV_MODULE9 609 #define PRIV_MODULE10 610 #define PRIV_MODULE11 611 #define PRIV_MODULE12 612 #define PRIV_MODULE13 613 #define PRIV_MODULE14 614 #define PRIV_MODULE15 615 /* * DDB(4) privileges. */ #define PRIV_DDB_CAPTURE 620 /* Allow reading of DDB capture log. */ /* * Arla/nnpfs privileges. */ #define PRIV_NNPFS_DEBUG 630 /* Perforn ARLA_VIOC_NNPFSDEBUG. */ /* * cpuctl(4) privileges. */ #define PRIV_CPUCTL_WRMSR 640 /* Write model-specific register. */ #define PRIV_CPUCTL_UPDATE 641 /* Update cpu microcode. */ /* * Capi4BSD privileges. */ #define PRIV_C4B_RESET_CTLR 650 /* Load firmware, reset controller. */ #define PRIV_C4B_TRACE 651 /* Unrestricted CAPI message tracing. */ /* * OpenAFS privileges. */ #define PRIV_AFS_ADMIN 660 /* Can change AFS client settings. */ #define PRIV_AFS_DAEMON 661 /* Can become the AFS daemon. */ /* * Resource Limits privileges. */ #define PRIV_RCTL_GET_RACCT 670 #define PRIV_RCTL_GET_RULES 671 #define PRIV_RCTL_GET_LIMITS 672 #define PRIV_RCTL_ADD_RULE 673 #define PRIV_RCTL_REMOVE_RULE 674 /* * mem(4) privileges. */ #define PRIV_KMEM_READ 680 /* Open mem/kmem for reading. */ #define PRIV_KMEM_WRITE 681 /* Open mem/kmem for writing. */ +#define PRIV_PROC_MEM_WRITE 682 /* Open /proc//mem for writing. */ /* * Kernel debugger privileges. */ #define PRIV_KDB_SET_BACKEND 690 /* Allow setting KDB backend. */ /* * veriexec override privileges - very rare! */ #define PRIV_VERIEXEC_DIRECT 700 /* Can override 'indirect' */ #define PRIV_VERIEXEC_NOVERIFY 701 /* Can override O_VERIFY */ #define PRIV_VERIEXEC_CONTROL 702 /* Can configure veriexec */ /* * Track end of privilege list. */ #define _PRIV_HIGHEST 703 /* * Validate that a named privilege is known by the privilege system. Invalid * privileges presented to the privilege system by a priv_check interface * will result in a panic. This is only approximate due to sparse allocation * of the privilege space. */ #define PRIV_VALID(x) ((x) > _PRIV_LOWEST && (x) < _PRIV_HIGHEST) #ifdef _KERNEL /* * Privilege check interfaces, modeled after historic suser() interfaces, but * with the addition of a specific privilege name. No flags are currently * defined for the API. Historically, flags specified using the real uid * instead of the effective uid, and whether or not the check should be * allowed in jail. */ struct thread; struct ucred; int priv_check(struct thread *td, int priv); int priv_check_cred(struct ucred *cred, int priv); int priv_check_cred_vfs_lookup(struct ucred *cred); int priv_check_cred_vfs_lookup_nomac(struct ucred *cred); int priv_check_cred_vfs_generation(struct ucred *cred); #endif #endif /* !_SYS_PRIV_H_ */