Date: Wed, 20 Jun 2018 00:41:31 +0000 (UTC) From: "Stephen J. Kiernan" <stevek@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r335399 - in head/sys: conf modules modules/mac_veriexec modules/mac_veriexec_rmd160 modules/mac_veriexec_sha1 modules/mac_veriexec_sha256 modules/mac_veriexec_sha384 modules/mac_veriex... Message-ID: <201806200041.w5K0fVQ1035864@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: stevek Date: Wed Jun 20 00:41:30 2018 New Revision: 335399 URL: https://svnweb.freebsd.org/changeset/base/335399 Log: MAC/veriexec implements a verified execution environment using the MAC framework. The code is organized into a few distinct pieces: * The meta-data store (in veriexec_metadata.c) which maps a file system identifier, file identifier, and generation key tuple to veriexec meta-data record. * Fingerprint management (in veriexec_fingerprint.c) which deals with calculating the cryptographic hash for a file and verifying it. It also manages the loadable fingerprint modules. * MAC policy implementation (in mac_veriexec.c) which implements the following MAC methods: mpo_init Initializes the veriexec state, meta-data store, fingerprint modules, and registers mount and unmount EVENTHANDLERs mpo_syscall Implements the following per-policy system calls: MAC_VERIEXEC_CHECK_FD_SYSCALL Check a file descriptor to see if the referenced file has a valid fingerprint. MAC_VERIEXEC_CHECK_PATH_SYSCALL Check a path to see if the referenced file has a valid fingerprint. mpo_kld_check_load Check if loading a kld is allowed. This checks if the referenced vnode has a valid fingerprint. mpo_mount_destroy_label Clears the veriexec slot data in a mount point label. mpo_mount_init_label Initializes the veriexec slot data in a mount point label. The file system identifier is saved in the veriexec slot data. mpo_priv_check Check if a process is allowed to write to /dev/kmem and /dev/mem devices. If a process is flagged as trusted, it is allowed to write. mpo_proc_check_debug Check if a process is allowed to be debugged. If a process is not flagged with VERIEXEC_NOTRACE, then debugging is allowed. mpo_vnode_check_exec Check is an exectuable is allowed to run. If veriexec is not enforcing or the executable has a valid fingerprint, then it is allowed to run. NOTE: veriexec will complain about mismatched fingerprints if it is active, regardless of the state of the enforcement. mpo_vnode_check_open Check is a file is allowed to be opened. If verification was not requested, veriexec is not enforcing, or the file has a valid fingerprint, then veriexec will allow the file to be opened. mpo_vnode_copy_label Copies the veriexec slot data from one label to another. mpo_vnode_destroy_label Clears the veriexec slot data in a vnode label. mpo_vnode_init_label Initializes the veriexec slot data in a vnode label. The fingerprint status for the file is stored in the veriexec slot data. * Some sysctls, under security.mac.veriexec, for setting debug level, fetching the current state in a human-readable form, and dumping the fingerprint database are implemented. * The MAC policy implementation source file also contains some utility functions. * A set of fingerprint modules for the following cryptographic hash algorithms: RIPEMD-160, SHA1, SHA2-256, SHA2-384, SHA2-512 * Loadable module builds for MAC/veriexec and fingerprint modules. WARNING: Using veriexec with NFS (or other network-based) file systems is not recommended as one cannot guarantee the integrity of the files served, nor the uniqueness of file system identifiers which are used as key in the meta-data store. Reviewed by: ian, jtl Obtained from: Juniper Networks, Inc. Differential Revision: https://reviews.freebsd.org/D8554 Added: head/sys/modules/mac_veriexec/ head/sys/modules/mac_veriexec/Makefile (contents, props changed) head/sys/modules/mac_veriexec_rmd160/ head/sys/modules/mac_veriexec_rmd160/Makefile (contents, props changed) head/sys/modules/mac_veriexec_sha1/ head/sys/modules/mac_veriexec_sha1/Makefile (contents, props changed) head/sys/modules/mac_veriexec_sha256/ head/sys/modules/mac_veriexec_sha256/Makefile (contents, props changed) head/sys/modules/mac_veriexec_sha384/ head/sys/modules/mac_veriexec_sha384/Makefile (contents, props changed) head/sys/modules/mac_veriexec_sha512/ head/sys/modules/mac_veriexec_sha512/Makefile (contents, props changed) head/sys/security/mac_veriexec/ head/sys/security/mac_veriexec/mac_veriexec.c (contents, props changed) head/sys/security/mac_veriexec/mac_veriexec.h (contents, props changed) head/sys/security/mac_veriexec/mac_veriexec_internal.h (contents, props changed) head/sys/security/mac_veriexec/mac_veriexec_rmd160.c (contents, props changed) head/sys/security/mac_veriexec/mac_veriexec_sha1.c (contents, props changed) head/sys/security/mac_veriexec/mac_veriexec_sha256.c (contents, props changed) head/sys/security/mac_veriexec/mac_veriexec_sha384.c (contents, props changed) head/sys/security/mac_veriexec/mac_veriexec_sha512.c (contents, props changed) head/sys/security/mac_veriexec/veriexec_fingerprint.c (contents, props changed) head/sys/security/mac_veriexec/veriexec_metadata.c (contents, props changed) Modified: head/sys/conf/files head/sys/modules/Makefile Modified: head/sys/conf/files ============================================================================== --- head/sys/conf/files Wed Jun 20 00:14:54 2018 (r335398) +++ head/sys/conf/files Wed Jun 20 00:41:30 2018 (r335399) @@ -3424,6 +3424,7 @@ dev/videomode/videomode.c optional videomode dev/videomode/edid.c optional videomode dev/videomode/pickmode.c optional videomode dev/videomode/vesagtf.c optional videomode +dev/veriexec/verified_exec.c optional veriexec mac_veriexec dev/vge/if_vge.c optional vge dev/viapm/viapm.c optional viapm pci dev/virtio/virtio.c optional virtio @@ -4892,6 +4893,14 @@ security/mac_portacl/mac_portacl.c optional mac_portac security/mac_seeotheruids/mac_seeotheruids.c optional mac_seeotheruids security/mac_stub/mac_stub.c optional mac_stub security/mac_test/mac_test.c optional mac_test +security/mac_veriexec/mac_veriexec.c optional mac_veriexec +security/mac_veriexec/veriexec_fingerprint.c optional mac_veriexec +security/mac_veriexec/veriexec_metadata.c optional mac_veriexec +security/mac_veriexec/mac_veriexec_rmd160.c optional mac_veriexec_rmd160 +security/mac_veriexec/mac_veriexec_sha1.c optional mac_veriexec_sha1 +security/mac_veriexec/mac_veriexec_sha256.c optional mac_veriexec_sha256 +security/mac_veriexec/mac_veriexec_sha384.c optional mac_veriexec_sha384 +security/mac_veriexec/mac_veriexec_sha512.c optional mac_veriexec_sha512 teken/teken.c optional sc | vt ufs/ffs/ffs_alloc.c optional ffs ufs/ffs/ffs_balloc.c optional ffs Modified: head/sys/modules/Makefile ============================================================================== --- head/sys/modules/Makefile Wed Jun 20 00:14:54 2018 (r335398) +++ head/sys/modules/Makefile Wed Jun 20 00:41:30 2018 (r335399) @@ -237,6 +237,12 @@ SUBDIR= \ mac_seeotheruids \ mac_stub \ mac_test \ + mac_veriexec \ + mac_veriexec_rmd160 \ + mac_veriexec_sha1 \ + mac_veriexec_sha256 \ + mac_veriexec_sha384 \ + mac_veriexec_sha512 \ malo \ md \ mdio \ Added: head/sys/modules/mac_veriexec/Makefile ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/sys/modules/mac_veriexec/Makefile Wed Jun 20 00:41:30 2018 (r335399) @@ -0,0 +1,40 @@ +# $FreeBSD$ + +.PATH: ${.PARSEDIR:H:H}/security/mac_veriexec + +KMOD = mac_veriexec +SRCS = \ + bus_if.h \ + device_if.h \ + vnode_if.h +SRCS += \ + opt_capsicum.h \ + opt_global.h \ + opt_mac.h \ + opt_veriexec.h +SRCS += \ + mac_veriexec.c \ + veriexec_fingerprint.c \ + veriexec_metadata.c + +EXPORT_SYMS+= ve_mutex \ + mac_veriexec_in_state \ + mac_veriexec_get_executable_flags + +.if defined(KERNBUILDDIR) +MKDEP= -include ${KERNBUILDDIR}/opt_global.h +.else +CFLAGS+= -include opt_global.h +MKDEP= -include opt_global.h +opt_mac.h: + echo "#define MAC_DEBUG 1" >> ${.TARGET} +opt_global.h: + echo "#define MAC 1" > ${.TARGET} +.endif + +.ifndef WITHOUT_VERIEXEC_DEBUG +CFLAGS+= -DVERIFIED_EXEC_DEBUG +.endif + +.include <bsd.kmod.mk> + Added: head/sys/modules/mac_veriexec_rmd160/Makefile ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/sys/modules/mac_veriexec_rmd160/Makefile Wed Jun 20 00:41:30 2018 (r335399) @@ -0,0 +1,10 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/../../security/mac_veriexec +.PATH: ${.CURDIR}/../../opencrypto + +KMOD= mac_veriexec_rmd160 +SRCS= mac_veriexec_rmd160.c rmd160.c + +.include <bsd.kmod.mk> + Added: head/sys/modules/mac_veriexec_sha1/Makefile ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/sys/modules/mac_veriexec_sha1/Makefile Wed Jun 20 00:41:30 2018 (r335399) @@ -0,0 +1,10 @@ +# $FreeBSD$ + +.PATH: ${.PARSEDIR:H:H}/security/mac_veriexec +.PATH: ${.PARSEDIR:H:H}/crypto + +KMOD= mac_veriexec_sha1 +SRCS= mac_veriexec_sha1.c sha1.c + +.include <bsd.kmod.mk> + Added: head/sys/modules/mac_veriexec_sha256/Makefile ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/sys/modules/mac_veriexec_sha256/Makefile Wed Jun 20 00:41:30 2018 (r335399) @@ -0,0 +1,10 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/../../security/mac_veriexec +.PATH: ${.CURDIR}/../../crypto/sha2 + +KMOD= mac_veriexec_sha256 +SRCS= mac_veriexec_sha256.c sha256c.c + +.include <bsd.kmod.mk> + Added: head/sys/modules/mac_veriexec_sha384/Makefile ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/sys/modules/mac_veriexec_sha384/Makefile Wed Jun 20 00:41:30 2018 (r335399) @@ -0,0 +1,10 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/../../security/mac_veriexec +.PATH: ${.CURDIR}/../../crypto/sha2 + +KMOD= mac_veriexec_sha384 +SRCS= mac_veriexec_sha384.c sha512c.c + +.include <bsd.kmod.mk> + Added: head/sys/modules/mac_veriexec_sha512/Makefile ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/sys/modules/mac_veriexec_sha512/Makefile Wed Jun 20 00:41:30 2018 (r335399) @@ -0,0 +1,10 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/../../security/mac_veriexec +.PATH: ${.CURDIR}/../../crypto/sha2 + +KMOD= mac_veriexec_sha512 +SRCS= mac_veriexec_sha512.c sha512c.c + +.include <bsd.kmod.mk> + Added: head/sys/security/mac_veriexec/mac_veriexec.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/sys/security/mac_veriexec/mac_veriexec.c Wed Jun 20 00:41:30 2018 (r335399) @@ -0,0 +1,803 @@ +/* + * $FreeBSD$ + * + * Copyright (c) 2011, 2012, 2013, 2015, 2016, 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 <sys/cdefs.h> + +#include "opt_capsicum.h" +#include "opt_mac.h" + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/capsicum.h> +#include <sys/eventhandler.h> +#include <sys/fcntl.h> +#include <sys/file.h> +#include <sys/filedesc.h> +#include <sys/imgact.h> +#include <sys/jail.h> +#include <sys/kernel.h> +#include <sys/mac.h> +#include <sys/mount.h> +#include <sys/namei.h> +#include <sys/priv.h> +#include <sys/proc.h> +#include <sys/sbuf.h> +#include <sys/stat.h> +#include <sys/sysctl.h> +#include <sys/vnode.h> +#include <fs/nullfs/null.h> +#include <security/mac/mac_policy.h> + +#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); + +SYSCTL_DECL(_security_mac); + +SYSCTL_NODE(_security_mac, OID_AUTO, veriexec, CTLFLAG_RW, 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, 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, 0, 0, sysctl_mac_veriexec_db, + "A", "Verified execution fingerprint database"); + +static int mac_veriexec_slot; + +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_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 %u for mount %p", 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 %u, cleaning up mount", 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); +} + +/** + * @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 %u, " + "file %lu.%lu\n", status, va.va_fsid, va.va_fileid, + 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) + * + * @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) +{ + + /* If we are not enforcing veriexec, nothing for us to check */ + if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0) + return (0); + + switch (priv) { + case PRIV_KMEM_WRITE: + if (!mac_veriexec_proc_is_trusted(cred, curproc)) + return (EPERM); + break; + default: + break; + } + 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 " + "%u, file %lu.%lu\n", va.va_fsid, + va.va_fileid, 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: + /* + * Caller wants open to fail unless there is a valid + * fingerprint registered. + */ + MAC_VERIEXEC_DBG(2, "fingerprint status is %d for dev " + "%u, file %lu.%lu\n", status, va.va_fsid, + va.va_fileid, 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); +} + +/** + * @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); +} + +/** + * @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; + + 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(&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, 0); +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 | AUDITVNODE1, + UIO_USERSPACE, arg, td); + error = namei(&nd); + if (error != 0) + break; + NDFREE(&nd, NDF_ONLY_PNBUF); + + /* Check the fingerprint status of the vnode */ + error = mac_veriexec_check_vp(td->td_ucred, nd.ni_vp, VVERIFY); + vput(nd.ni_vp); + break; + default: + error = EOPNOTSUPP; + } + return (error); +} + +static struct mac_policy_ops mac_veriexec_ops = +{ + .mpo_init = mac_veriexec_init, + .mpo_syscall = mac_veriexec_syscall, + .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_vnode_check_exec = mac_veriexec_vnode_check_exec, + .mpo_vnode_check_open = mac_veriexec_vnode_check_open, + .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, 1); + +/** + * @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; + + fps = SLOT(vp->v_label); + switch (fps) { + case FINGERPRINT_VALID: + case FINGERPRINT_INDIRECT: + case FINGERPRINT_FILE: + break; + default: + /* we may need to recurse */ + if (strcmp(vp->v_tag, "null") == 0) { + struct vnode *ldvp; + + ldvp = NULLVPTOLOWERVP(vp); + 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) +{ + + /* recurse until we find the real storage */ + if (strcmp(vp->v_tag, "null") == 0) { + struct vnode *ldvp; + + ldvp = NULLVPTOLOWERVP(vp); + 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 error, flags; + + error = mac_veriexec_metadata_get_executable_flags(cred, p, &flags, 0); + + /* Any errors, deny access */ + if (error != 0) + return (0); + + /* Check that the trusted flag is set */ + return ((flags & VERIEXEC_TRUSTED) == VERIEXEC_TRUSTED); +} Added: head/sys/security/mac_veriexec/mac_veriexec.h ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/sys/security/mac_veriexec/mac_veriexec.h Wed Jun 20 00:41:30 2018 (r335399) @@ -0,0 +1,161 @@ +/* + * $FreeBSD$ + * + * Copyright (c) 2011, 2012, 2013, 2015, 2016, 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 + +#ifdef _KERNEL +#include <sys/types.h> +#include <sys/kernel.h> +#include <sys/queue.h> +#include <sys/module.h> +#endif + +/** + * Name of the MAC module + */ +#define MAC_VERIEXEC_NAME "mac_veriexec" + *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201806200041.w5K0fVQ1035864>