diff --git a/lib/libveriexec/Makefile b/lib/libveriexec/Makefile index 2c68faf3356f..84e2b8329967 100644 --- a/lib/libveriexec/Makefile +++ b/lib/libveriexec/Makefile @@ -1,14 +1,16 @@ # $FreeBSD$ .include LIB= veriexec MAN= veriexec.3 INCS= libveriexec.h WARNS?= 2 -SRCS= veriexec_check.c +SRCS= \ + veriexec_check.c \ + veriexec_get.c .include diff --git a/lib/libveriexec/libveriexec.h b/lib/libveriexec/libveriexec.h index 42d2c964a174..d186db0ab8d9 100644 --- a/lib/libveriexec/libveriexec.h +++ b/lib/libveriexec/libveriexec.h @@ -1,37 +1,45 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2011, 2012, 2013, 2015, 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. */ #ifndef __LIBVERIEXEC_H__ #define __LIBVERIEXEC_H__ +struct mac_veriexec_syscall_params; + int veriexec_check_fd_mode(int, unsigned int); int veriexec_check_path_mode(const char *, unsigned int); int veriexec_check_fd(int); int veriexec_check_path(const char *); +int veriexec_get_pid_params(pid_t, struct mac_veriexec_syscall_params *); +int veriexec_get_path_params(const char *, + struct mac_veriexec_syscall_params *); +int veriexec_check_pid_label(pid_t, const char *); + +#define HAVE_VERIEXEC_CHECK_PID_LABEL 1 #endif /* __LIBVERIEXEC_H__ */ diff --git a/lib/libveriexec/veriexec_get.c b/lib/libveriexec/veriexec_get.c new file mode 100644 index 000000000000..46df6eecf76e --- /dev/null +++ b/lib/libveriexec/veriexec_get.c @@ -0,0 +1,184 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2021-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 +__FBSDID("$FreeBSD$"); +#include +#include +#include + +#include +#include + +#include + +/** + * @brief get veriexec params for a process + * + * @return + * @li 0 if successful + */ +int +veriexec_get_pid_params(pid_t pid, + struct mac_veriexec_syscall_params *params) +{ + struct mac_veriexec_syscall_params_args args; + + if (params == NULL) + return EINVAL; + + args.u.pid = pid; + args.params = params; + return mac_syscall(MAC_VERIEXEC_NAME, + MAC_VERIEXEC_GET_PARAMS_PID_SYSCALL, &args); +} + +/** + * @brief get veriexec params for a process + * + * @return + * @li 0 if successful + */ +int +veriexec_get_path_params(const char *file, + struct mac_veriexec_syscall_params *params) +{ + struct mac_veriexec_syscall_params_args args; + + if (file == NULL || params == NULL) + return EINVAL; + + args.u.filename = file; + args.params = params; + return mac_syscall(MAC_VERIEXEC_NAME, + MAC_VERIEXEC_GET_PARAMS_PATH_SYSCALL, &args); +} + +/** + * @brief check if label contains what we want + * + * @return + * @li 0 if no + * @li 1 if yes + */ +int +veriexec_check_pid_label(pid_t pid, const char *want) +{ + struct mac_veriexec_syscall_params params; + char *cp; + size_t n; + + if (want != NULL && + veriexec_get_pid_params(pid, ¶ms) == 0) { + /* Does label contain [,][,] ? */ + if (params.labellen > 0 && + (cp = strstr(params.label, want)) != NULL) { + if (cp == params.label || cp[-1] == ',') { + n = strlen(want); + if (cp[n] == '\0' || cp[n] == ',') + return 1; /* yes */ + } + } + } + return 0; /* no */ +} + +#ifdef UNIT_TEST +#include +#include +#include + +static char * +hash2hex(char *type, unsigned char *digest) +{ + static char buf[2*MAXFINGERPRINTLEN+1]; + size_t n; + int i; + + if (strcmp(type, "SHA1") == 0) { + n = 20; + } else if (strcmp(type, "SHA256") == 0) { + n = 32; + } else if (strcmp(type, "SHA384") == 0) { + n = 48; + } + for (i = 0; i < n; i++) { + sprintf(&buf[2*i], "%02x", (unsigned)digest[i]); + } + return buf; +} + +int +main(int argc, char *argv[]) +{ + struct mac_veriexec_syscall_params params; + pid_t pid; + char *want = NULL; + int pflag = 0; + int error; + int c; + + while ((c = getopt(argc, argv, "pw:")) != -1) { + switch (c) { + case 'p': + pflag = 1; + break; + case 'w': + want = optarg; + break; + default: + break; + } + } + for (; optind < argc; optind++) { + + if (pflag) { + pid = atoi(argv[optind]); + if (want) { + error = veriexec_check_pid_label(pid, want); + printf("pid=%d want='%s': %d\n", + pid, want, error); + continue; + } + error = veriexec_get_pid_params(pid, ¶ms); + } else { + error = veriexec_get_path_params(argv[optind], ¶ms); + } + if (error) { + err(2, "%s, error=%d", argv[optind], error); + } + + printf("arg=%s, type=%s, flags=%u, label='%s', fingerprint='%s'\n", + argv[optind], params.fp_type, (unsigned)params.flags, + params.label, + hash2hex(params.fp_type, params.fingerprint)); + } + return 0; +} +#endif diff --git a/sys/dev/veriexec/veriexec_ioctl.h b/sys/dev/veriexec/veriexec_ioctl.h index 2fcccbb3c175..1409ebb9f40f 100644 --- a/sys/dev/veriexec/veriexec_ioctl.h +++ b/sys/dev/veriexec/veriexec_ioctl.h @@ -1,67 +1,64 @@ /* * $FreeBSD$ * - * Copyright (c) 2011-2013, 2015, 2019, Juniper Networks, Inc. + * 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. */ /* * * Definitions for the Verified Executables kernel function. * */ #ifndef _DEV_VERIEXEC_VERIEXEC_IOCTL_H #define _DEV_VERIEXEC_VERIEXEC_IOCTL_H -#include #include -#define VERIEXEC_FPTYPELEN 16 - struct verified_exec_params { unsigned char flags; char fp_type[VERIEXEC_FPTYPELEN]; /* type of fingerprint */ char file[MAXPATHLEN]; unsigned char fingerprint[MAXFINGERPRINTLEN]; }; struct verified_exec_label_params { struct verified_exec_params params; char label[MAXLABELLEN]; }; #define VERIEXEC_LOAD _IOW('S', 0x1, struct verified_exec_params) #define VERIEXEC_ACTIVE _IO('S', 0x2) /* start checking */ #define VERIEXEC_ENFORCE _IO('S', 0x3) /* fail exec */ #define VERIEXEC_LOCK _IO('S', 0x4) /* don't allow new sigs */ #define VERIEXEC_DEBUG_ON _IOWR('S', 0x5, int) /* set/get debug level */ #define VERIEXEC_DEBUG_OFF _IO('S', 0x6) /* reset debug */ #define VERIEXEC_GETSTATE _IOR('S', 0x7, int) /* get state */ #define VERIEXEC_SIGNED_LOAD _IOW('S', 0x8, struct verified_exec_params) #define VERIEXEC_GETVERSION _IOR('S', 0x9, int) /* get version */ #define VERIEXEC_LABEL_LOAD _IOW('S', 0xa, struct verified_exec_label_params) #define _PATH_DEV_VERIEXEC _PATH_DEV "veriexec" #endif diff --git a/sys/dev/veriexec/verified_exec.c b/sys/dev/veriexec/verified_exec.c index 1cb3cd75dbbe..c00aa49c2f6c 100644 --- a/sys/dev/veriexec/verified_exec.c +++ b/sys/dev/veriexec/verified_exec.c @@ -1,269 +1,269 @@ /* * $FreeBSD$ * * Copyright (c) 2011-2013, 2015, 2019 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "veriexec_ioctl.h" /* * We need a mutex while updating lists etc. */ extern struct mtx ve_mutex; /* * Handle the ioctl for the device */ static int verifiedexecioctl(struct cdev *dev __unused, u_long cmd, caddr_t data, int flags, struct thread *td) { struct nameidata nid; struct vattr vattr; struct verified_exec_label_params *lparams; struct verified_exec_params *params; int error = 0; /* * These commands are considered safe requests for anyone who has * permission to access to device node. */ switch (cmd) { case VERIEXEC_GETSTATE: { int *ip = (int *)data; if (ip) *ip = mac_veriexec_get_state(); else error = EINVAL; return (error); } break; default: break; } /* * Anything beyond this point is considered dangerous, so we need to * only allow processes that have kmem write privs to do them. * * MAC/veriexec will grant kmem write privs to "trusted" processes. */ - error = priv_check(td, PRIV_KMEM_WRITE); + error = priv_check(td, PRIV_VERIEXEC_CONTROL); if (error) return (error); lparams = (struct verified_exec_label_params *)data; if (cmd == VERIEXEC_LABEL_LOAD) params = &lparams->params; else params = (struct verified_exec_params *)data; switch (cmd) { case VERIEXEC_ACTIVE: mtx_lock(&ve_mutex); if (mac_veriexec_in_state(VERIEXEC_STATE_LOADED)) mac_veriexec_set_state(VERIEXEC_STATE_ACTIVE); else error = EINVAL; mtx_unlock(&ve_mutex); break; case VERIEXEC_DEBUG_ON: mtx_lock(&ve_mutex); { int *ip = (int *)data; mac_veriexec_debug++; if (ip) { if (*ip > 0) mac_veriexec_debug = *ip; *ip = mac_veriexec_debug; } } mtx_unlock(&ve_mutex); break; case VERIEXEC_DEBUG_OFF: mac_veriexec_debug = 0; break; case VERIEXEC_ENFORCE: mtx_lock(&ve_mutex); if (mac_veriexec_in_state(VERIEXEC_STATE_LOADED)) mac_veriexec_set_state(VERIEXEC_STATE_ACTIVE | VERIEXEC_STATE_ENFORCE); else error = EINVAL; mtx_unlock(&ve_mutex); break; case VERIEXEC_GETVERSION: { int *ip = (int *)data; if (ip) *ip = MAC_VERIEXEC_VERSION; else error = EINVAL; } break; case VERIEXEC_LOCK: mtx_lock(&ve_mutex); mac_veriexec_set_state(VERIEXEC_STATE_LOCKED); mtx_unlock(&ve_mutex); break; case VERIEXEC_LOAD: if (prison0.pr_securelevel > 0) return (EPERM); /* no updates when secure */ /* FALLTHROUGH */ case VERIEXEC_LABEL_LOAD: case VERIEXEC_SIGNED_LOAD: /* * If we use a loader that will only use a * digitally signed hash list - which it verifies. * We can load fingerprints provided veriexec is not locked. */ if (prison0.pr_securelevel > 0 && !mac_veriexec_in_state(VERIEXEC_STATE_LOADED)) { /* * If securelevel has been raised and we * do not have any fingerprints loaded, * it would dangerous to do so now. */ return (EPERM); } if (mac_veriexec_in_state(VERIEXEC_STATE_LOCKED)) error = EPERM; else { size_t labellen = 0; int flags = FREAD; int override = (cmd != VERIEXEC_LOAD); /* * Get the attributes for the file name passed * stash the file's device id and inode number * along with it's fingerprint in a list for * exec to use later. */ /* * FreeBSD seems to copy the args to kernel space */ NDINIT(&nid, LOOKUP, FOLLOW, UIO_SYSSPACE, params->file); if ((error = vn_open(&nid, &flags, 0, NULL)) != 0) return (error); error = VOP_GETATTR(nid.ni_vp, &vattr, td->td_ucred); if (error != 0) { mac_veriexec_set_fingerprint_status(nid.ni_vp, FINGERPRINT_INVALID); VOP_UNLOCK(nid.ni_vp); (void) vn_close(nid.ni_vp, FREAD, td->td_ucred, td); return (error); } if (override) { /* * If the file is on a "verified" filesystem * someone may be playing games. */ if ((nid.ni_vp->v_mount->mnt_flag & MNT_VERIFIED) != 0) override = 0; } /* * invalidate the node fingerprint status * which will have been set in the vn_open * and would always be FINGERPRINT_NOTFOUND */ mac_veriexec_set_fingerprint_status(nid.ni_vp, FINGERPRINT_INVALID); VOP_UNLOCK(nid.ni_vp); (void) vn_close(nid.ni_vp, FREAD, td->td_ucred, td); if (params->flags & VERIEXEC_LABEL) labellen = strnlen(lparams->label, sizeof(lparams->label) - 1) + 1; mtx_lock(&ve_mutex); error = mac_veriexec_metadata_add_file( ((params->flags & VERIEXEC_FILE) != 0), vattr.va_fsid, vattr.va_fileid, vattr.va_gen, params->fingerprint, (params->flags & VERIEXEC_LABEL) ? lparams->label : NULL, labellen, params->flags, params->fp_type, override); mac_veriexec_set_state(VERIEXEC_STATE_LOADED); mtx_unlock(&ve_mutex); } break; default: error = ENODEV; } return (error); } struct cdevsw veriexec_cdevsw = { .d_version = D_VERSION, .d_ioctl = verifiedexecioctl, .d_name = "veriexec", }; static void veriexec_drvinit(void *unused __unused) { make_dev(&veriexec_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "veriexec"); } SYSINIT(veriexec, SI_SUB_PSEUDO, SI_ORDER_ANY, veriexec_drvinit, NULL); MODULE_DEPEND(veriexec, 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 52202f87f666..bae8c2b9055c 100644 --- a/sys/security/mac_veriexec/mac_veriexec.c +++ b/sys/security/mac_veriexec/mac_veriexec.c @@ -1,1046 +1,1130 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * - * Copyright (c) 2011, 2012, 2013, 2015, 2016, 2019 Juniper Networks, Inc. + * 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 #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_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; 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); #ifdef MAC_DEBUG MAC_VERIEXEC_DBG(3, "set fsid to %ju for mount %p", (uintmax_t)va.va_fsid, mp); #endif } /** * @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); - return ((flags & VERIEXEC_NOTRACE) ? EACCES : 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: - if (!mac_veriexec_proc_is_trusted(cred, curproc)) - return (EPERM); + 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 (0); + 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); /* Fetch tunable value in kernel env and define a corresponding read-only sysctl */ mac_veriexec_block_unlink = 0; TUNABLE_INT_FETCH("security.mac.veriexec.block_unlink", &mac_veriexec_block_unlink); SYSCTL_INT(_security_mac_veriexec, OID_AUTO, block_unlink, CTLFLAG_RDTUN, &mac_veriexec_block_unlink, 0, "Veriexec unlink protection"); /* Check if unlink control is activated via tunable value */ if (!mac_veriexec_block_unlink) mac_veriexec_ops.mpo_vnode_check_unlink = NULL; } /** * @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; - int error; + struct mac_veriexec_syscall_params_args pargs; + struct mac_veriexec_syscall_params result; + 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: + 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); - error = namei(&nd); + 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); - vput(nd.ni_vp); + /* 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; + + 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/security/mac_veriexec/mac_veriexec.h b/sys/security/mac_veriexec/mac_veriexec.h index db5a13bbd06c..e4d336ce4ff4 100644 --- a/sys/security/mac_veriexec/mac_veriexec.h +++ b/sys/security/mac_veriexec/mac_veriexec.h @@ -1,163 +1,186 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2011, 2012, 2013, 2015, 2016, 2019, 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. */ #ifndef _SECURITY_MAC_VERIEXEC_H #define _SECURITY_MAC_VERIEXEC_H +#include + #ifdef _KERNEL #include #include #include #include #endif /** * Name of the MAC module */ #define MAC_VERIEXEC_NAME "mac_veriexec" /* MAC/veriexec syscalls */ -#define MAC_VERIEXEC_CHECK_FD_SYSCALL 1 -#define MAC_VERIEXEC_CHECK_PATH_SYSCALL 2 +#define MAC_VERIEXEC_CHECK_FD_SYSCALL 1 +#define MAC_VERIEXEC_CHECK_PATH_SYSCALL 2 +#define MAC_VERIEXEC_GET_PARAMS_PID_SYSCALL 3 +#define MAC_VERIEXEC_GET_PARAMS_PATH_SYSCALL 4 + +#define VERIEXEC_FPTYPELEN 16 /* hash name */ /** * Enough room for the largest signature... */ #define MAXFINGERPRINTLEN 64 /* enough room for largest signature */ #define MAXLABELLEN 128 /* * Types of veriexec inodes we can have */ #define VERIEXEC_INDIRECT (1<<0) /* Only allow indirect execution */ #define VERIEXEC_FILE (1<<1) /* Fingerprint of a plain file */ #define VERIEXEC_NOTRACE (1<<2) /**< PTRACE not allowed */ #define VERIEXEC_TRUSTED (1<<3) /**< Safe to write /dev/mem */ #define VERIEXEC_NOFIPS (1<<4) /**< Not allowed in FIPS mode */ #define VERIEXEC_LABEL (1<<5) /**< We have a label */ #define VERIEXEC_STATE_INACTIVE 0 /**< Ignore */ #define VERIEXEC_STATE_LOADED (1<<0) /**< Sigs have been loaded */ #define VERIEXEC_STATE_ACTIVE (1<<1) /**< Pay attention to it */ #define VERIEXEC_STATE_ENFORCE (1<<2) /**< Fail execs for files that do not match signature */ #define VERIEXEC_STATE_LOCKED (1<<3) /**< Do not allow further changes */ +/* for MAC_VERIEXEC_GET_PARAMS_*_SYSCALL */ +struct mac_veriexec_syscall_params { + char fp_type[VERIEXEC_FPTYPELEN]; + unsigned char fingerprint[MAXFINGERPRINTLEN]; + char label[MAXLABELLEN]; + size_t labellen; + unsigned char flags; +}; + +struct mac_veriexec_syscall_params_args { + union { + pid_t pid; + const char *filename; + } u; /* input only */ + struct mac_veriexec_syscall_params *params; /* result */ +}; + #ifdef _KERNEL /** * Version of the MAC/veriexec module */ #define MAC_VERIEXEC_VERSION 2 /* Valid states for the fingerprint flag - if signed exec is being used */ typedef enum fingerprint_status { FINGERPRINT_INVALID, /**< Fingerprint has not been evaluated */ FINGERPRINT_VALID, /**< Fingerprint evaluated and matches list */ FINGERPRINT_INDIRECT, /**< Fingerprint eval'd/matched but only indirect execs allowed */ FINGERPRINT_FILE, /**< Fingerprint evaluated/matched but not executable */ FINGERPRINT_NOMATCH, /**< Fingerprint evaluated but does not match */ FINGERPRINT_NOENTRY, /**< Fingerprint evaluated but no list entry */ FINGERPRINT_NODEV, /**< Fingerprint evaluated but no dev list */ } fingerprint_status_t; typedef void (*mac_veriexec_fpop_init_t)(void *); typedef void (*mac_veriexec_fpop_update_t)(void *, const uint8_t *, size_t); typedef void (*mac_veriexec_fpop_final_t)(uint8_t *, void *); struct mac_veriexec_fpops { const char *type; size_t digest_len; size_t context_size; mac_veriexec_fpop_init_t init; mac_veriexec_fpop_update_t update; mac_veriexec_fpop_final_t final; LIST_ENTRY(mac_veriexec_fpops) entries; }; /** * Verified execution subsystem debugging level */ extern int mac_veriexec_debug; /** * @brief Define a fingerprint module. * * @param _name Name of the fingerprint module * @param _digest_len Length of the digest string, in number of characters * @param _context_size Size of the context structure, in bytes * @param _init Initialization function of type * mac_veriexec_fpop_init_t * @param _update Update function of type mac_veriexec_fpop_update_t * @param _final Finalize function of type mac_veriexec_fpop_final_t * @param _vers Module version */ #define MAC_VERIEXEC_FPMOD(_name, _digest_len, _context_size, _init, \ _update, _final, _vers) \ static struct mac_veriexec_fpops \ mac_veriexec_##_name##_fpops = { \ .type = #_name, \ .digest_len = _digest_len, \ .context_size = _context_size, \ .init = _init, \ .update = _update, \ .final = _final, \ }; \ static moduledata_t mac_veriexec_##_name##_mod = { \ "mac_veriexec/" #_name, \ mac_veriexec_fingerprint_modevent, \ &(mac_veriexec_##_name##_fpops) \ }; \ MODULE_VERSION(mac_veriexec_##_name, _vers); \ DECLARE_MODULE(mac_veriexec_##_name, \ mac_veriexec_##_name##_mod, SI_SUB_MAC_POLICY, \ SI_ORDER_ANY); \ MODULE_DEPEND(mac_veriexec_##_name, mac_veriexec, \ MAC_VERIEXEC_VERSION, MAC_VERIEXEC_VERSION, \ MAC_VERIEXEC_VERSION) /* * The following function should not be called directly. The prototype is * included here to satisfy the compiler when using the macro above. */ int mac_veriexec_fingerprint_modevent(module_t mod, int type, void *data); /* * Public functions */ int mac_veriexec_metadata_add_file(int file_dev, dev_t fsid, long fileid, unsigned long gen, unsigned char fingerprint[MAXFINGERPRINTLEN], char *label, size_t labellen, int flags, const char *fp_type, int override); int mac_veriexec_metadata_has_file(dev_t fsid, long fileid, unsigned long gen); int mac_veriexec_proc_is_trusted(struct ucred *cred, struct proc *p); #endif #endif /* _SECURITY_MAC_VERIEXEC_H */ diff --git a/sys/security/mac_veriexec/mac_veriexec_internal.h b/sys/security/mac_veriexec/mac_veriexec_internal.h index 6fc963a12393..e69f34df892e 100644 --- a/sys/security/mac_veriexec/mac_veriexec_internal.h +++ b/sys/security/mac_veriexec/mac_veriexec_internal.h @@ -1,107 +1,107 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2011, 2012, 2013, 2015, 2016, 2019, 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. */ #ifndef _SECURITY_MAC_VERIEXEC_INTERNAL_H #define _SECURITY_MAC_VERIEXEC_INTERNAL_H #ifndef _KERNEL #error "no user-serviceable parts inside" #endif #include #include #include #define MAC_VERIEXEC_FULLNAME "MAC/veriexec" #define VERIEXEC_FILES_FIRST 1 #if defined(VERIFIED_EXEC_DEBUG) || defined(VERIFIED_EXEC_DEBUG_VERBOSE) # define VERIEXEC_DEBUG(n, x) if (mac_veriexec_debug > (n)) printf x #else # define VERIEXEC_DEBUG(n, x) #endif struct mac_veriexec_file_info { int flags; long fileid; unsigned long gen; struct mac_veriexec_fpops *ops; unsigned char fingerprint[MAXFINGERPRINTLEN]; char *label; size_t labellen; LIST_ENTRY(mac_veriexec_file_info) entries; }; MALLOC_DECLARE(M_VERIEXEC); SYSCTL_DECL(_security_mac_veriexec); struct cred; struct image_params; struct proc; struct sbuf; struct thread; struct ucred; struct vattr; struct vnode; int mac_veriexec_metadata_fetch_fingerprint_status(struct vnode *vp, struct vattr *vap, struct thread *td, int check_files); int mac_veriexec_metadata_get_executable_flags(struct ucred *cred, struct proc *p, int *flags, int check_files); int mac_veriexec_metadata_get_file_flags(dev_t fsid, long fileid, unsigned long gen, int *flags, int check_files); -struct mac_veriexec_file_info * - mac_veriexec_metadata_get_file_info(dev_t fsid, long fileid, - unsigned long gen, int *found_dev, int check_files); +int mac_veriexec_metadata_get_file_info(dev_t fsid, long fileid, + unsigned long gen, int *found_dev, + struct mac_veriexec_file_info **ipp, int check_files); void mac_veriexec_metadata_init(void); void mac_veriexec_metadata_print_db(struct sbuf *sbp); int mac_veriexec_metadata_unmounted(dev_t fsid, struct thread *td); int mac_veriexec_fingerprint_add_ops(struct mac_veriexec_fpops *fpops); int mac_veriexec_fingerprint_check_image(struct image_params *imgp, int check_files, struct thread *td); int mac_veriexec_fingerprint_check_vnode(struct vnode *vp, struct mac_veriexec_file_info *ip, struct thread *td, off_t file_size, unsigned char *fingerprint); void mac_veriexec_fingerprint_init(void); struct mac_veriexec_fpops * mac_veriexec_fingerprint_lookup_ops(const char *type); fingerprint_status_t mac_veriexec_get_fingerprint_status(struct vnode *vp); int mac_veriexec_get_state(void); int mac_veriexec_in_state(int state); void mac_veriexec_set_fingerprint_status(struct vnode *vp, fingerprint_status_t fp_status); void mac_veriexec_set_state(int state); #endif /* !_SECURITY_MAC_VERIEXEC_INTERNAL_H */ diff --git a/sys/security/mac_veriexec/veriexec_metadata.c b/sys/security/mac_veriexec/veriexec_metadata.c index b5bfe70410d1..9e99f51e7e65 100644 --- a/sys/security/mac_veriexec/veriexec_metadata.c +++ b/sys/security/mac_veriexec/veriexec_metadata.c @@ -1,786 +1,791 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2011, 2012, 2013, 2015, 2016, 2019, Juniper Networks, Inc. * All rights reserved. * * Originally derived from: * $NetBSD: kern_verifiedexec.c,v 1.7 2003/11/18 13:13:03 martin Exp $ * * 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 "mac_veriexec.h" #include "mac_veriexec_internal.h" /** * @brief per-device meta-data storage */ struct veriexec_dev_list { dev_t fsid; /**< file system identifier of the mount point */ LIST_HEAD(filehead, mac_veriexec_file_info) file_head; /**< list of per-file meta-data information */ LIST_ENTRY(veriexec_dev_list) entries; /**< next entries in the device list */ }; typedef LIST_HEAD(veriexec_devhead, veriexec_dev_list) veriexec_devhead_t; /** * @brief Mutex to protect the meta-data store lists */ struct mtx ve_mutex; /** * @brief Executables meta-data storage * * This is used to store the fingerprints for potentially-executable files. */ veriexec_devhead_t veriexec_dev_head; /** * @brief Plain file meta-data storage * * This is used for files that are not allowed to be executed, but should * have fingerprint validation available. */ veriexec_devhead_t veriexec_file_dev_head; /** * @internal * @brief Search the @p head meta-data list for the specified file identifier * @p fileid in the file system identified by @p fsid * * If meta-data exists for file system identified by @p fsid, it has a * fingerprint list, and @p found_dev is not @c NULL then store true in the * location pointed to by @p found_dev * * @param head meta-data list to search * @param fsid file system identifier to look for * @param fileid file to look for * @param gen generation of file * @param found_dev indicator that an entry for the file system was found * * @return A pointer to the meta-data inforation if meta-data exists for * the specified file identifier, otherwise @c NULL */ static struct mac_veriexec_file_info * get_veriexec_file(struct veriexec_devhead *head, dev_t fsid, long fileid, unsigned long gen, int *found_dev) { struct veriexec_dev_list *lp; struct mac_veriexec_file_info *ip, *tip; ip = NULL; /* Initialize the value found_dev, if non-NULL */ if (found_dev != NULL) *found_dev = 0; VERIEXEC_DEBUG(3, ("searching for file %ju.%lu on device %ju," " files=%d\n", (uintmax_t)fileid, gen, (uintmax_t)fsid, (head == &veriexec_file_dev_head))); /* Get a lock to access the list */ mtx_lock(&ve_mutex); /* First, look for the file system */ for (lp = LIST_FIRST(head); lp != NULL; lp = LIST_NEXT(lp, entries)) if (lp->fsid == fsid) break; /* We found the file system in the list */ if (lp != NULL) { VERIEXEC_DEBUG(3, ("found matching dev number %ju\n", (uintmax_t)lp->fsid)); /* If found_dev is non-NULL, store true there */ if (found_dev != NULL) *found_dev = 1; /* Next, look for the meta-data information for the file */ LIST_FOREACH_SAFE(ip, &(lp->file_head), entries, tip) { if (ip->fileid == fileid) { if (ip->gen == gen) break; /* we need to garbage collect */ LIST_REMOVE(ip, entries); if (ip->label) free(ip->label, M_VERIEXEC); free(ip, M_VERIEXEC); } } } /* Release the lock we obtained earlier */ mtx_unlock(&ve_mutex); /* Return the meta-data information we found, if anything */ return (ip); } /** * @internal * @brief Display the fingerprint for each entry in the device list * * @param sbp sbuf to write output to * @param lp pointer to device list */ static void mac_veriexec_print_db_dev_list(struct sbuf *sbp, struct veriexec_dev_list *lp) { struct mac_veriexec_file_info *ip; #define FPB(i) (ip->fingerprint[i]) for (ip = LIST_FIRST(&(lp->file_head)); ip != NULL; ip = LIST_NEXT(ip, entries)) sbuf_printf(sbp, " %ld: %u %ld [%02x %02x %02x %02x %02x " "%02x %02x %02x...]\n", ip->fileid, ip->flags, ip->gen, FPB(0), FPB(1), FPB(2), FPB(3), FPB(4), FPB(5), FPB(6), FPB(7)); } /** * @internal * @brief Display the device list * * @param sbp sbuf to write output to * @param head pointer to head of the device list */ static void mac_veriexec_print_db_head(struct sbuf *sbp, struct veriexec_devhead *head) { struct veriexec_dev_list *lp; for (lp = LIST_FIRST(head); lp != NULL; lp = LIST_NEXT(lp, entries)) { sbuf_printf(sbp, " FS id: %ju\n", (uintmax_t)lp->fsid); mac_veriexec_print_db_dev_list(sbp, lp); } } /** * @internal * @brief Generate human-readable output for the current fingerprint database * * @param sbp sbuf to write output to */ void mac_veriexec_metadata_print_db(struct sbuf *sbp) { struct { struct veriexec_devhead *h; const char *name; } fpdbs[] = { { &veriexec_file_dev_head, "regular files" }, { &veriexec_dev_head, "executable files" }, }; int i; mtx_lock(&ve_mutex); for (i = 0; i < sizeof(fpdbs)/sizeof(fpdbs[0]); i++) { sbuf_printf(sbp, "%s fingerprint db:\n", fpdbs[i].name); mac_veriexec_print_db_head(sbp, fpdbs[i].h); } mtx_unlock(&ve_mutex); } /** * @brief Determine if the meta-data store has an entry for the specified file. * * @param fsid file system identifier to look for * @param fileid file to look for * @param gen generation of file * * @return 1 if there is an entry in the meta-data store, 0 otherwise. */ int mac_veriexec_metadata_has_file(dev_t fsid, long fileid, unsigned long gen) { return (mac_veriexec_metadata_get_file_info(fsid, fileid, gen, NULL, - VERIEXEC_FILES_FIRST) != NULL); + NULL, VERIEXEC_FILES_FIRST) == 0); } /** * @brief Search the list of devices looking for the one given, in order to * release the resources used by it. * * If found, free all file entries for it, and remove it from the list. * * @note Called with @a ve_mutex held * * @param fsid file system identifier to look for * @param head meta-data list to search * * @return 0 if the device entry was freed, otherwise an error code */ static int free_veriexec_dev(dev_t fsid, struct veriexec_devhead *head) { struct veriexec_dev_list *lp; struct mac_veriexec_file_info *ip, *nip; /* Look for the file system */ for (lp = LIST_FIRST(head); lp != NULL; lp = LIST_NEXT(lp, entries)) if (lp->fsid == fsid) break; /* If lp is NULL, we did not find it */ if (lp == NULL) return ENOENT; /* Unhook lp, before we free it and its content */ LIST_REMOVE(lp, entries); /* Release the lock */ mtx_unlock(&ve_mutex); /* Free the file entries in the list */ for (ip = LIST_FIRST(&(lp->file_head)); ip != NULL; ip = nip) { nip = LIST_NEXT(ip, entries); LIST_REMOVE(ip, entries); if (ip->label) free(ip->label, M_VERIEXEC); free(ip, M_VERIEXEC); } /* Free the meta-data entry for the device */ free(lp, M_VERIEXEC); /* Re-acquire the lock */ mtx_lock(&ve_mutex); return 0; } /** * @brief Search the list of devices looking for the one given. * * If it is not in the list then add it. * * @note Called with @a ve_mutex held * * @param fsid file system identifier to look for * @param head meta-data list to search * * @return A pointer to the meta-data entry for the device, if found or added, * otherwise @c NULL */ static struct veriexec_dev_list * find_veriexec_dev(dev_t fsid, struct veriexec_devhead *head) { struct veriexec_dev_list *lp; struct veriexec_dev_list *np = NULL; search: /* Look for the file system */ for (lp = LIST_FIRST(head); lp != NULL; lp = LIST_NEXT(lp, entries)) if (lp->fsid == fsid) break; if (lp == NULL) { if (np == NULL) { /* * If pointer is null then entry not there, * add a new one, first try to malloc while * we hold mutex - should work most of the time. */ np = malloc(sizeof(struct veriexec_dev_list), M_VERIEXEC, M_NOWAIT); if (np == NULL) { /* * So much for that plan, dop the mutex * and repeat... */ mtx_unlock(&ve_mutex); np = malloc(sizeof(struct veriexec_dev_list), M_VERIEXEC, M_WAITOK); mtx_lock(&ve_mutex); /* * Repeat the search, in case someone * added this while we slept. */ goto search; } } if (np) { /* Add the entry to the list */ lp = np; LIST_INIT(&(lp->file_head)); lp->fsid = fsid; LIST_INSERT_HEAD(head, lp, entries); } } else if (np) { /* * Someone else did it while we slept. */ mtx_unlock(&ve_mutex); free(np, M_VERIEXEC); mtx_lock(&ve_mutex); } return (lp); } /** * @internal * @brief Allocate and initialize label record with the provided data. * * @param labelp Location to store the initialized label * @param src Pointer to label string to copy * @param srclen Length of label string to copy * * @return Length of resulting label * * @note Called with ve_mutex locked. */ static size_t mac_veriexec_init_label(char **labelp, size_t labellen, char *src, size_t srclen) { char *label; label = *labelp; if (labellen < srclen) { mtx_unlock(&ve_mutex); if (label != NULL) free(label, M_VERIEXEC); label = malloc(srclen, M_VERIEXEC, M_WAITOK); mtx_lock(&ve_mutex); labellen = srclen; *labelp = label; } memcpy(label, src, srclen); return labellen; } /** * @brief When a device is unmounted, we want to toss the signatures recorded * against it. * * We are being called from unmount() with the root vnode just before it is * freed. * * @param fsid file system identifier to look for * @param td calling thread * * @return 0 on success, otherwise an error code. */ int mac_veriexec_metadata_unmounted(dev_t fsid, struct thread *td) { int error; /* * The device can have entries on both lists. */ mtx_lock(&ve_mutex); error = free_veriexec_dev(fsid, &veriexec_dev_head); if (error && error != ENOENT) { mtx_unlock(&ve_mutex); return error; } error = free_veriexec_dev(fsid, &veriexec_file_dev_head); mtx_unlock(&ve_mutex); if (error && error != ENOENT) { return error; } return 0; } /** * @brief Return the flags assigned to the file identified by file system * identifier @p fsid and file identifier @p fileid. * * @param fsid file system identifier * @param fileid file identifier within the file system * @param gen generation of file * @param flags pointer to location to store the flags * @param check_files if 1, check the files list first, otherwise check the * exectuables list first * * @return 0 on success, otherwise an error code. */ int mac_veriexec_metadata_get_file_flags(dev_t fsid, long fileid, unsigned long gen, int *flags, int check_files) { struct mac_veriexec_file_info *ip; - int found_dev; + int error; - ip = mac_veriexec_metadata_get_file_info(fsid, fileid, gen, &found_dev, - check_files); - if (ip == NULL) - return (ENOENT); + error = mac_veriexec_metadata_get_file_info(fsid, fileid, gen, NULL, + &ip, check_files); + if (error != 0) + return (error); *flags = ip->flags; return (0); } /** * @brief get the files for the specified process * * @param cred credentials to use * @param p process to get the flags for * @param flags where to store the flags * @param check_files if 1, check the files list first, otherwise check the * exectuables list first * * @return 0 if the process has an entry in the meta-data store, otherwise an * error code */ int mac_veriexec_metadata_get_executable_flags(struct ucred *cred, struct proc *p, int *flags, int check_files) { struct vnode *proc_vn; struct vattr vap; int error; /* Get the text vnode for the process */ proc_vn = p->p_textvp; if (proc_vn == NULL) return EINVAL; /* Get vnode attributes */ error = VOP_GETATTR(proc_vn, &vap, cred); if (error) return error; error = mac_veriexec_metadata_get_file_flags(vap.va_fsid, vap.va_fileid, vap.va_gen, flags, (check_files == VERIEXEC_FILES_FIRST)); return (error); } /** * @brief Ensure the fingerprint status for the vnode @p vp is assigned to its * MAC label. * * @param vp vnode to check * @param vap vnode attributes to use * @param td calling thread * @param check_files if 1, check the files list first, otherwise check the * exectuables list first * * @return 0 on success, otherwise an error code. */ int mac_veriexec_metadata_fetch_fingerprint_status(struct vnode *vp, struct vattr *vap, struct thread *td, int check_files) { unsigned char digest[MAXFINGERPRINTLEN]; struct mac_veriexec_file_info *ip; int error, found_dev; fingerprint_status_t status; error = 0; ip = NULL; status = mac_veriexec_get_fingerprint_status(vp); if (status == FINGERPRINT_INVALID || status == FINGERPRINT_NODEV) { found_dev = 0; - ip = mac_veriexec_metadata_get_file_info(vap->va_fsid, - vap->va_fileid, vap->va_gen, &found_dev, check_files); - if (ip == NULL) { + error = mac_veriexec_metadata_get_file_info(vap->va_fsid, + vap->va_fileid, vap->va_gen, &found_dev, &ip, check_files); + if (error != 0) { status = (found_dev) ? FINGERPRINT_NOENTRY : FINGERPRINT_NODEV; VERIEXEC_DEBUG(3, ("fingerprint status is %d for dev %ju, file " "%ju.%lu\n", status, (uintmax_t)vap->va_fsid, (uintmax_t)vap->va_fileid, vap->va_gen)); } else { /* * evaluate and compare fingerprint */ error = mac_veriexec_fingerprint_check_vnode(vp, ip, td, vap->va_size, digest); switch (error) { case 0: /* Process flags */ if ((ip->flags & VERIEXEC_INDIRECT)) status = FINGERPRINT_INDIRECT; else if ((ip->flags & VERIEXEC_FILE)) status = FINGERPRINT_FILE; else status = FINGERPRINT_VALID; VERIEXEC_DEBUG(2, ("%sfingerprint matches for dev %ju, file " "%ju.%lu\n", (status == FINGERPRINT_INDIRECT) ? "indirect " : (status == FINGERPRINT_FILE) ? "file " : "", (uintmax_t)vap->va_fsid, (uintmax_t)vap->va_fileid, vap->va_gen)); break; case EAUTH: #ifdef VERIFIED_EXEC_DEBUG_VERBOSE { char have[MAXFINGERPRINTLEN * 2 + 1]; char want[MAXFINGERPRINTLEN * 2 + 1]; int i, len; len = ip->ops->digest_len; for (i = 0; i < len; i++) { sprintf(&want[i * 2], "%02x", ip->fingerprint[i]); sprintf(&have[i * 2], "%02x", digest[i]); } log(LOG_ERR, MAC_VERIEXEC_FULLNAME ": fingerprint for dev %ju, file " "%ju.%lu %s != %s\n", (uintmax_t)vap->va_fsid, (uintmax_t)vap->va_fileid, vap->va_gen, have, want); } #endif status = FINGERPRINT_NOMATCH; break; default: VERIEXEC_DEBUG(2, ("fingerprint status error %d\n", error)); break; } } mac_veriexec_set_fingerprint_status(vp, status); } return (error); } /** * Add a file and its fingerprint to the list of files attached * to the device @p fsid. * * Only add the entry if it is not already on the list. * * @note Called with @a ve_mutex held * * @param file_dev if 1, the entry should be added on the file list, * otherwise it should be added on the executable list * @param fsid file system identifier of device * @param fileid file to add * @param gen generation of file * @param fingerprint fingerprint to add to the store * @param flags flags to set in the store * @param fp_type digest type * @param override if 1, override any values already stored * * @return 0 on success, otherwise an error code. */ int mac_veriexec_metadata_add_file(int file_dev, dev_t fsid, long fileid, unsigned long gen, unsigned char fingerprint[MAXFINGERPRINTLEN], char *label, size_t labellen, int flags, const char *fp_type, int override) { struct mac_veriexec_fpops *fpops; struct veriexec_dev_list *lp; struct veriexec_devhead *head; struct mac_veriexec_file_info *ip; struct mac_veriexec_file_info *np = NULL; /* Label and labellen must be set if VERIEXEC_LABEL is set */ if ((flags & VERIEXEC_LABEL) != 0 && (label == NULL || labellen == 0)) return (EINVAL); /* Look up the device entry */ if (file_dev) head = &veriexec_file_dev_head; else head = &veriexec_dev_head; lp = find_veriexec_dev(fsid, head); /* Look up the fingerprint operations for the digest type */ fpops = mac_veriexec_fingerprint_lookup_ops(fp_type); if (fpops == NULL) return (EOPNOTSUPP); search: for (ip = LIST_FIRST(&(lp->file_head)); ip != NULL; ip = LIST_NEXT(ip, entries)) { /* check for a dupe file in the list, skip if an entry * exists for this file except for when the flags contains * VERIEXEC_INDIRECT, always set the flags when it is so * we don't get a hole caused by conflicting flags on * hardlinked files. XXX maybe we should validate * fingerprint is same and complain if it is not... */ if (ip->fileid == fileid && ip->gen == gen) { if (override) { /* * for a signed load we allow overrides, * otherwise fingerpints needed for pkg loads * can fail (the files are on temp device). */ ip->flags = flags; ip->ops = fpops; memcpy(ip->fingerprint, fingerprint, fpops->digest_len); if (flags & VERIEXEC_LABEL) { ip->labellen = mac_veriexec_init_label( &ip->label, ip->labellen, label, labellen); } else if (ip->labellen > 0) { free(ip->label, M_VERIEXEC); ip->labellen = 0; ip->label = NULL; } } else if ((flags & (VERIEXEC_INDIRECT|VERIEXEC_FILE))) ip->flags |= flags; if (np) { /* unlikely but... we don't need it now. */ mtx_unlock(&ve_mutex); free(np, M_VERIEXEC); mtx_lock(&ve_mutex); } return (0); } } /* * We may have been past here before... */ if (np == NULL) { /* * We first try with mutex held and nowait. */ np = malloc(sizeof(struct mac_veriexec_file_info), M_VERIEXEC, M_NOWAIT); if (np == NULL) { /* * It was worth a try, now * drop mutex while we malloc. */ mtx_unlock(&ve_mutex); np = malloc(sizeof(struct mac_veriexec_file_info), M_VERIEXEC, M_WAITOK); mtx_lock(&ve_mutex); /* * We now have to repeat our search! */ goto search; } } /* Set up the meta-data entry */ ip = np; ip->flags = flags; ip->ops = fpops; ip->fileid = fileid; ip->gen = gen; memcpy(ip->fingerprint, fingerprint, fpops->digest_len); if (flags & VERIEXEC_LABEL) ip->labellen = mac_veriexec_init_label(&ip->label, ip->labellen, label, labellen); else { ip->label = NULL; ip->labellen = 0; } VERIEXEC_DEBUG(3, ("add file %ju.%lu (files=%d)\n", (uintmax_t)ip->fileid, ip->gen, file_dev)); /* Add the entry to the list */ LIST_INSERT_HEAD(&(lp->file_head), ip, entries); #ifdef DEBUG_VERIEXEC_FINGERPRINT { off_t offset; printf("Stored %s fingerprint:\n", fp_type); for (offset = 0; offset < fpops->digest_len; offset++) printf("%02x", fingerprint[offset]); printf("\n"); } #endif return (0); } /** * @brief Search the meta-data store for information on the specified file. * - * @param fsid file system identifier to look for - * @param fileid file to look for - * @param gen generation of file + * @param fsid file system identifier to look for + * @param fileid file to look for + * @param gen generation of file * @param found_dev indicator that an entry for the file system was found - * @param check_files if 1, check the files list first, otherwise check the - * exectuables list first + * @param ipp pointer to location to store the info pointer + * @param check_files if 1, check the files list first, otherwise check the + * exectuables list first * * @return A pointer to the meta-data inforation if meta-data exists for * the specified file identifier, otherwise @c NULL */ -struct mac_veriexec_file_info * +int mac_veriexec_metadata_get_file_info(dev_t fsid, long fileid, unsigned long gen, - int *found_dev, int check_files) + int *found_dev, struct mac_veriexec_file_info **ipp, int check_files) { struct veriexec_devhead *search[3]; struct mac_veriexec_file_info *ip; int x; /* Determine the order of the lists to search */ if (check_files) { search[0] = &veriexec_file_dev_head; search[1] = &veriexec_dev_head; } else { search[0] = &veriexec_dev_head; search[1] = &veriexec_file_dev_head; } search[2] = NULL; - VERIEXEC_DEBUG(3, ("%s: searching for dev %ju, file %lu\n", - __func__, (uintmax_t)fsid, fileid)); + VERIEXEC_DEBUG(3, ("%s: searching for dev %#jx, file %lu.%lu\n", + __func__, (uintmax_t)fsid, fileid, gen)); /* Search for the specified file */ for (ip = NULL, x = 0; ip == NULL && search[x]; x++) ip = get_veriexec_file(search[x], fsid, fileid, gen, found_dev); - return (ip); + if (ipp != NULL) + *ipp = ip; + if (ip == NULL) + return (ENOENT); + return (0); } /** * @brief Intialize the meta-data store */ void mac_veriexec_metadata_init(void) { mtx_init(&ve_mutex, "veriexec lock", NULL, MTX_DEF); LIST_INIT(&veriexec_dev_head); LIST_INIT(&veriexec_file_dev_head); } diff --git a/sys/sys/priv.h b/sys/sys/priv.h index 6574d8c42599..fe2de892f97a 100644 --- a/sys/sys/priv.h +++ b/sys/sys/priv.h @@ -1,559 +1,560 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * 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. * * $FreeBSD$ */ /* * 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. */ /* * 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. */ /* * 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 702 +#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_ */