Skip site navigation (1)Skip section navigation (2)
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>