Page MenuHomeFreeBSD

D8554.id44112.diff
No OneTemporary

D8554.id44112.diff

Index: head/sys/conf/files
===================================================================
--- head/sys/conf/files
+++ head/sys/conf/files
@@ -3424,6 +3424,7 @@
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_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
Index: head/sys/modules/Makefile
===================================================================
--- head/sys/modules/Makefile
+++ head/sys/modules/Makefile
@@ -237,6 +237,12 @@
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 \
Index: head/sys/modules/mac_veriexec/Makefile
===================================================================
--- head/sys/modules/mac_veriexec/Makefile
+++ head/sys/modules/mac_veriexec/Makefile
@@ -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>
+
Index: head/sys/modules/mac_veriexec_rmd160/Makefile
===================================================================
--- head/sys/modules/mac_veriexec_rmd160/Makefile
+++ head/sys/modules/mac_veriexec_rmd160/Makefile
@@ -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>
+
Index: head/sys/modules/mac_veriexec_sha1/Makefile
===================================================================
--- head/sys/modules/mac_veriexec_sha1/Makefile
+++ head/sys/modules/mac_veriexec_sha1/Makefile
@@ -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>
+
Index: head/sys/modules/mac_veriexec_sha256/Makefile
===================================================================
--- head/sys/modules/mac_veriexec_sha256/Makefile
+++ head/sys/modules/mac_veriexec_sha256/Makefile
@@ -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>
+
Index: head/sys/modules/mac_veriexec_sha384/Makefile
===================================================================
--- head/sys/modules/mac_veriexec_sha384/Makefile
+++ head/sys/modules/mac_veriexec_sha384/Makefile
@@ -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>
+
Index: head/sys/modules/mac_veriexec_sha512/Makefile
===================================================================
--- head/sys/modules/mac_veriexec_sha512/Makefile
+++ head/sys/modules/mac_veriexec_sha512/Makefile
@@ -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>
+
Index: head/sys/security/mac_veriexec/mac_veriexec.h
===================================================================
--- head/sys/security/mac_veriexec/mac_veriexec.h
+++ head/sys/security/mac_veriexec/mac_veriexec.h
@@ -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"
+
+/* MAC/veriexec syscalls */
+#define MAC_VERIEXEC_CHECK_FD_SYSCALL 1
+#define MAC_VERIEXEC_CHECK_PATH_SYSCALL 2
+
+/**
+ * Enough room for the largest signature...
+ */
+#define MAXFINGERPRINTLEN 64 /* enough room for largest signature */
+
+/*
+ * 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 */
+/* XXX these are currently unimplemented */
+#define VERIEXEC_NOFIPS (1<<4) /**< Not allowed in FIPS mode */
+
+#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 */
+
+#ifdef _KERNEL
+/**
+ * Version of the MAC/veriexec module
+ */
+#define MAC_VERIEXEC_VERSION 1
+
+/* 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],
+ 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 */
Index: head/sys/security/mac_veriexec/mac_veriexec.c
===================================================================
--- head/sys/security/mac_veriexec/mac_veriexec.c
+++ head/sys/security/mac_veriexec/mac_veriexec.c
@@ -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);
+}
Index: head/sys/security/mac_veriexec/mac_veriexec_internal.h
===================================================================
--- head/sys/security/mac_veriexec/mac_veriexec_internal.h
+++ head/sys/security/mac_veriexec/mac_veriexec_internal.h
@@ -0,0 +1,103 @@
+/*
+ * $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_INTERNAL_H
+#define _SECURITY_MAC_VERIEXEC_INTERNAL_H
+
+#ifndef _KERNEL
+#error "no user-serviceable parts inside"
+#endif
+
+#include <sys/queue.h>
+#include <sys/malloc.h>
+#include <sys/sysctl.h>
+
+#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];
+ 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);
+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_print_db(struct sbuf *);
+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 */
Index: head/sys/security/mac_veriexec/mac_veriexec_rmd160.c
===================================================================
--- head/sys/security/mac_veriexec/mac_veriexec_rmd160.c
+++ head/sys/security/mac_veriexec/mac_veriexec_rmd160.c
@@ -0,0 +1,45 @@
+/*
+ * $FreeBSD$
+ *
+ * Copyright (c) 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 <sys/param.h>
+#include <sys/systm.h>
+
+#include <opencrypto/rmd160.h>
+
+#include <security/mac_veriexec/mac_veriexec.h>
+
+#ifndef RMD160_DIGEST_LENGTH
+#define RMD160_DIGEST_LENGTH 20
+#endif
+
+MAC_VERIEXEC_FPMOD(RMD160, RMD160_DIGEST_LENGTH, sizeof(RMD160_CTX),
+ (mac_veriexec_fpop_init_t) RMD160Init,
+ (mac_veriexec_fpop_update_t) RMD160Update,
+ (mac_veriexec_fpop_final_t) RMD160Final, 1);
Index: head/sys/security/mac_veriexec/mac_veriexec_sha1.c
===================================================================
--- head/sys/security/mac_veriexec/mac_veriexec_sha1.c
+++ head/sys/security/mac_veriexec/mac_veriexec_sha1.c
@@ -0,0 +1,49 @@
+/*
+ * $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 <sys/param.h>
+#include <sys/systm.h>
+
+#include <crypto/sha1.h>
+
+#include <security/mac_veriexec/mac_veriexec.h>
+
+#define SHA1_Init (mac_veriexec_fpop_init_t) sha1_init
+#define SHA1_Update (mac_veriexec_fpop_update_t) sha1_loop
+
+static void
+SHA1_Final(unsigned char *buf, void *ctx)
+{
+
+ sha1_result((SHA1_CTX *) ctx, (caddr_t) buf);
+}
+
+MAC_VERIEXEC_FPMOD(SHA1, SHA1_RESULTLEN, sizeof(SHA1_CTX), SHA1_Init,
+ SHA1_Update, SHA1_Final, 1);
Index: head/sys/security/mac_veriexec/mac_veriexec_sha256.c
===================================================================
--- head/sys/security/mac_veriexec/mac_veriexec_sha256.c
+++ head/sys/security/mac_veriexec/mac_veriexec_sha256.c
@@ -0,0 +1,41 @@
+/*
+ * $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 <sys/param.h>
+#include <sys/systm.h>
+
+#include <crypto/sha2/sha256.h>
+
+#include <security/mac_veriexec/mac_veriexec.h>
+
+MAC_VERIEXEC_FPMOD(SHA256, SHA256_DIGEST_LENGTH, sizeof(SHA256_CTX),
+ (mac_veriexec_fpop_init_t) SHA256_Init,
+ (mac_veriexec_fpop_update_t) SHA256_Update,
+ (mac_veriexec_fpop_final_t) SHA256_Final, 1);
Index: head/sys/security/mac_veriexec/mac_veriexec_sha384.c
===================================================================
--- head/sys/security/mac_veriexec/mac_veriexec_sha384.c
+++ head/sys/security/mac_veriexec/mac_veriexec_sha384.c
@@ -0,0 +1,41 @@
+/*
+ * $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 <sys/param.h>
+#include <sys/systm.h>
+
+#include <crypto/sha2/sha384.h>
+
+#include <security/mac_veriexec/mac_veriexec.h>
+
+MAC_VERIEXEC_FPMOD(SHA384, SHA384_DIGEST_LENGTH, sizeof(SHA384_CTX),
+ (mac_veriexec_fpop_init_t) SHA384_Init,
+ (mac_veriexec_fpop_update_t) SHA384_Update,
+ (mac_veriexec_fpop_final_t) SHA384_Final, 1);
Index: head/sys/security/mac_veriexec/mac_veriexec_sha512.c
===================================================================
--- head/sys/security/mac_veriexec/mac_veriexec_sha512.c
+++ head/sys/security/mac_veriexec/mac_veriexec_sha512.c
@@ -0,0 +1,41 @@
+/*
+ * $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 <sys/param.h>
+#include <sys/systm.h>
+
+#include <crypto/sha2/sha512.h>
+
+#include <security/mac_veriexec/mac_veriexec.h>
+
+MAC_VERIEXEC_FPMOD(SHA512, SHA512_DIGEST_LENGTH, sizeof(SHA512_CTX),
+ (mac_veriexec_fpop_init_t) SHA512_Init,
+ (mac_veriexec_fpop_update_t) SHA512_Update,
+ (mac_veriexec_fpop_final_t) SHA512_Final, 1);
Index: head/sys/security/mac_veriexec/veriexec_fingerprint.c
===================================================================
--- head/sys/security/mac_veriexec/veriexec_fingerprint.c
+++ head/sys/security/mac_veriexec/veriexec_fingerprint.c
@@ -0,0 +1,443 @@
+/*
+ * $FreeBSD$
+ *
+ * Copyright (c) 2011, 2012, 2013, 2015, 2016, 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 <sys/cdefs.h>
+
+#include "opt_mac.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/imgact.h>
+#include <sys/jail.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mount.h>
+#include <sys/mutex.h>
+#include <sys/proc.h>
+#include <sys/sbuf.h>
+#include <sys/syslog.h>
+#include <sys/vnode.h>
+
+#include "mac_veriexec.h"
+#include "mac_veriexec_internal.h"
+
+/**
+ * @var fpops_list
+ * @internal
+ * @brief Fingerprint operations list
+ *
+ * This is essentially the list of fingerprint modules currently loaded
+ */
+static LIST_HEAD(fpopshead, mac_veriexec_fpops) fpops_list;
+
+static int mac_veriexec_late;
+
+static int sysctl_mac_veriexec_algorithms(SYSCTL_HANDLER_ARGS);
+
+SYSCTL_PROC(_security_mac_veriexec, OID_AUTO, algorithms,
+ CTLTYPE_STRING | CTLFLAG_RD, 0, 0, sysctl_mac_veriexec_algorithms, "A",
+ "Verified execution supported hashing algorithms");
+
+static int
+sysctl_mac_veriexec_algorithms(SYSCTL_HANDLER_ARGS)
+{
+ struct sbuf sb;
+ struct mac_veriexec_fpops *fpops;
+ int algorithms, error;
+
+ algorithms = 0;
+ sbuf_new(&sb, NULL, 128, SBUF_AUTOEXTEND);
+ LIST_FOREACH(fpops, &fpops_list, entries) {
+ if (algorithms++)
+ sbuf_printf(&sb, " ");
+ sbuf_printf(&sb, "%s", fpops->type);
+ }
+ sbuf_finish(&sb);
+ error = SYSCTL_OUT(req, sbuf_data(&sb), sbuf_len(&sb));
+ sbuf_delete(&sb);
+ return (error);
+}
+
+/**
+ * @internal
+ * @brief Consistently identify file encountering errors
+ *
+ * @param imgp image params to display
+ * @param td calling thread
+ * @param msg message to display
+ *
+ * @return String form of the information stored in @p imgp
+ */
+static void
+identify_error (struct image_params *imgp, struct thread *td, const char *msg)
+{
+ struct proc *parent;
+ pid_t ppid, gppid;
+
+ parent = imgp->proc->p_pptr;
+ ppid = (parent != NULL) ? parent->p_pid : 0;
+ gppid = (parent != NULL && parent->p_pptr != NULL) ?
+ parent->p_pptr->p_pid : 0;
+
+ log(LOG_ERR, MAC_VERIEXEC_FULLNAME ": %s (file=%s fsid=%lu fileid=%lu "
+ "gen=%lu uid=%u pid=%u ppid=%u gppid=%u)", msg,
+ (imgp->args != NULL) ? imgp->args->fname : "",
+ imgp->attr->va_fsid, imgp->attr->va_fileid, imgp->attr->va_gen,
+ td->td_ucred->cr_ruid, imgp->proc->p_pid, ppid, gppid);
+}
+
+/**
+ * @internal
+ * @brief Check the fingerprint type for the given file and evaluate the
+ * fingerprint for that file.
+ *
+ * It is assumed that @p fingerprint has sufficient storage to hold the
+ * resulting fingerprint string.
+ *
+ * @param vp vnode to check
+ * @param ip file info from the meta-data store
+ * @param td calling thread
+ * @param file_size size of the file to read
+ * @param fingerprint resulting fingerprint
+ *
+ * @return 0 on success, otherwise an error code.
+ */
+static int
+evaluate_fingerprint(struct vnode *vp, struct mac_veriexec_file_info *ip,
+ struct thread *td, off_t file_size, unsigned char *fingerprint)
+{
+ uint8_t *filebuf;
+ void *ctx;
+ off_t offset;
+ size_t count, nread, resid;
+ int error = EINVAL;
+
+ filebuf = malloc(PAGE_SIZE, M_VERIEXEC, M_WAITOK);
+ ctx = malloc(ip->ops->context_size, M_VERIEXEC, M_WAITOK);
+
+ (ip->ops->init)(ctx);
+ for (offset = 0; offset < file_size; offset += nread) {
+ if ((offset + PAGE_SIZE) > file_size)
+ count = file_size - offset;
+ else
+ count = PAGE_SIZE;
+
+ error = vn_rdwr_inchunks(UIO_READ, vp, filebuf, count, offset,
+ UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, NOCRED, &resid,
+ td);
+ if (error)
+ goto failed;
+
+ nread = count - resid;
+ (ip->ops->update)(ctx, filebuf, nread);
+ }
+ (ip->ops->final)(fingerprint, ctx);
+
+#ifdef DEBUG_VERIEXEC_FINGERPRINT
+ for (offset = 0; offset < ip->ops->digest_len; offset++)
+ printf("%02x", fingerprint[offset]);
+ printf("\n");
+#endif
+
+failed:
+ free(ctx, M_VERIEXEC);
+ free(filebuf, M_VERIEXEC);
+ return (error);
+}
+
+/**
+ * @internal
+ * @brief Compare the two given fingerprints to see if they are the same.
+ *
+ * Differing fingerprint methods may have differing lengths which
+ * is handled by this routine.
+ *
+ * @param ip file info from the meta-data store
+ * @param digest digest to compare
+ *
+ * @return 0 if the fingerprints match and non-zero if they do not.
+ */
+static int
+fingerprintcmp(struct mac_veriexec_file_info *ip, unsigned char *digest)
+{
+
+ return memcmp(ip->fingerprint, digest, ip->ops->digest_len);
+}
+
+/**
+ * @brief Check if @p fingerprint matches the one associated with the vnode
+ * @p vp
+ *
+ * @param vp vnode to check
+ * @param ip file info from the meta-data store
+ * @param td calling thread
+ * @param file_size size of the file to read
+ * @param fingerprint fingerprint to compare
+ *
+ * @return 0 if they match, otherwise an error code.
+ */
+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)
+{
+ int error;
+
+ /* reject fingerprint if writers are active */
+ if (vp->v_writecount)
+ return (ETXTBSY);
+
+ if ((vp->v_mount->mnt_flag & MNT_VERIFIED) != 0) {
+ VERIEXEC_DEBUG(2, ("file %lu.%lu on verified %s mount\n",
+ ip->fileid, ip->gen, vp->v_mount->mnt_vfc->vfc_name));
+
+ /*
+ * The VFS is backed by a file which has been verified.
+ * No need to waste time here.
+ */
+ return (0);
+ }
+
+ error = evaluate_fingerprint(vp, ip, td, file_size, fingerprint);
+ if (error)
+ return (error);
+
+ if (fingerprintcmp(ip, fingerprint) != 0)
+ return (EAUTH);
+
+ return (0);
+}
+
+/**
+ * @brief Check a file signature and validate it.
+ *
+ * @param imgp parameters for the image to check
+ * @param check_files if 1, check the files list first, otherwise check the
+ * exectuables list first
+ * @param td calling thread
+ *
+ * @note Called with imgp->vp locked.
+ *
+ * @return 0 if the signature is valid, otherwise an error code.
+ */
+int
+mac_veriexec_fingerprint_check_image(struct image_params *imgp,
+ int check_files, struct thread *td)
+{
+ struct vnode *vp = imgp->vp;
+ int error;
+ fingerprint_status_t status;
+
+ if (!mac_veriexec_in_state(VERIEXEC_STATE_ACTIVE))
+ return 0;
+
+ error = mac_veriexec_metadata_fetch_fingerprint_status(vp, imgp->attr,
+ td, check_files);
+ if (error && error != EAUTH)
+ return (error);
+
+ /*
+ * By now status is set.
+ */
+ status = mac_veriexec_get_fingerprint_status(vp);
+ switch (status) {
+ case FINGERPRINT_INVALID: /* should not happen */
+ identify_error(imgp, td, "got unexpected FINGERPRINT_INVALID");
+ error = EPERM;
+ break;
+
+ case FINGERPRINT_FILE:
+ if (!check_files) {
+ if (prison0.pr_securelevel > 1 ||
+ mac_veriexec_in_state(VERIEXEC_STATE_ENFORCE))
+ error = EPERM;
+ }
+ break;
+
+ case FINGERPRINT_VALID: /* is ok - report so if debug is on */
+ VERIEXEC_DEBUG(4, ("Fingerprint matches\n"));
+ break;
+
+ case FINGERPRINT_INDIRECT: /* fingerprint ok but need to check
+ for direct execution */
+ if (!imgp->interpreted) {
+ identify_error(imgp, td, "attempted direct execution");
+ if (prison0.pr_securelevel > 1 ||
+ mac_veriexec_in_state(VERIEXEC_STATE_ENFORCE))
+ error = EPERM;
+ }
+ break;
+
+ case FINGERPRINT_NOMATCH: /* does not match - whine about it */
+ identify_error(imgp, td,
+ "fingerprint does not match loaded value");
+ if (prison0.pr_securelevel > 1 ||
+ mac_veriexec_in_state(VERIEXEC_STATE_ENFORCE))
+ error = EAUTH;
+ break;
+
+ case FINGERPRINT_NOENTRY: /* no entry in the list, complain */
+ identify_error(imgp, td, "no fingerprint");
+ if (prison0.pr_securelevel > 1 ||
+ mac_veriexec_in_state(VERIEXEC_STATE_ENFORCE))
+ error = EAUTH;
+ break;
+
+ case FINGERPRINT_NODEV: /* no signatures for the device, complain */
+ identify_error(imgp, td, "no signatures for device");
+ if (prison0.pr_securelevel > 1 ||
+ mac_veriexec_in_state(VERIEXEC_STATE_ENFORCE))
+ error = EAUTH;
+ break;
+
+ default: /* this should never happen. */
+ identify_error(imgp, td, "invalid status field for vnode");
+ error = EPERM;
+ }
+ return error;
+}
+
+/**
+ * @brief Look up the fingerprint operations for a specific digest type
+ *
+ * @return A pointer to fingerprint operations, if found, or else @c NULL.
+ */
+struct mac_veriexec_fpops *
+mac_veriexec_fingerprint_lookup_ops(const char *type)
+{
+ struct mac_veriexec_fpops *fpops;
+
+ if (type == NULL)
+ return (NULL);
+
+ LIST_FOREACH(fpops, &fpops_list, entries) {
+ if (!strcasecmp(type, fpops->type))
+ break;
+ }
+ return (fpops);
+}
+
+/**
+ * @brief Add fingerprint operations for a specific digest type
+ *
+ * Any attempts to add a duplicate digest type results in an error.
+ *
+ * @return 0 if the ops were added successfully, otherwise an error code.
+ */
+int
+mac_veriexec_fingerprint_add_ops(struct mac_veriexec_fpops *fpops)
+{
+
+ /* Sanity check the ops */
+ if (fpops->type == NULL || fpops->digest_len == 0 ||
+ fpops->context_size == 0 || fpops->init == NULL ||
+ fpops->update == NULL || fpops->final == NULL)
+ return (EINVAL);
+
+ /* Make sure we do not already have ops for this digest type */
+ if (mac_veriexec_fingerprint_lookup_ops(fpops->type))
+ return (EEXIST);
+
+ /* Add the ops to the list */
+ LIST_INSERT_HEAD(&fpops_list, fpops, entries);
+
+ printf("MAC/veriexec fingerprint module loaded: %s\n", fpops->type);
+
+ return (0);
+}
+
+/**
+ * @brief Initialize the fingerprint operations list
+ */
+void
+mac_veriexec_fingerprint_init(void)
+{
+
+ LIST_INIT(&fpops_list);
+}
+
+/**
+ * @brief Handle fingerprint module events
+ *
+ * This function is called by the @c MAC_VERIEXEC_FPMOD macro.
+ *
+ * @param mod module information
+ * @param type event type
+ * @param data event-specific data
+ *
+ * @return On @c MOD_LOAD, 0 if the fingerprint ops were added successfully,
+ * otherwise an error code. All other event types result in an error code.
+ */
+int
+mac_veriexec_fingerprint_modevent(module_t mod, int type, void *data)
+{
+ struct mac_veriexec_fpops *fpops;
+ int error;
+
+ error = 0;
+ fpops = (struct mac_veriexec_fpops *) data;
+
+ switch (type) {
+ case MOD_LOAD:
+ /* We do not allow late loading of fingerprint modules */
+ if (mac_veriexec_late) {
+ printf("%s: can't load %s fingerprint module after "
+ "booting\n", __func__, fpops->type);
+ error = EBUSY;
+ break;
+ }
+ error = mac_veriexec_fingerprint_add_ops(fpops);
+ break;
+ case MOD_UNLOAD:
+ error = EBUSY;
+ break;
+ default:
+ error = EOPNOTSUPP;
+ break;
+ }
+
+ return (error);
+}
+
+/**
+ * @internal
+ * @brief Mark veriexec late initialization flag
+ */
+static void
+mac_veriexec_late_init(void)
+{
+
+ mac_veriexec_late = 1;
+}
+
+SYSINIT(mac_veriexec_late, SI_SUB_MAC_LATE, SI_ORDER_ANY,
+ mac_veriexec_late_init, NULL);
Index: head/sys/security/mac_veriexec/veriexec_metadata.c
===================================================================
--- head/sys/security/mac_veriexec/veriexec_metadata.c
+++ head/sys/security/mac_veriexec/veriexec_metadata.c
@@ -0,0 +1,727 @@
+/*
+ * $FreeBSD$
+ *
+ * Copyright (c) 2011, 2012, 2013, 2015, 2016, 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 <sys/cdefs.h>
+
+#include "opt_mac.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/exec.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mutex.h>
+#include <sys/proc.h>
+#include <sys/sbuf.h>
+#include <sys/vnode.h>
+
+#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 %lu.%lu on device %lu,"
+ " files=%d\n", fileid, gen, (unsigned long)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 %lu\n",
+ 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);
+ 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 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 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
+ *
+ * @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 *
+find_veriexec_file(dev_t fsid, long fileid, unsigned long gen, int *found_dev,
+ 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 %lu, file %lu\n",
+ __func__, fsid, fileid));
+
+ /* 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);
+}
+
+/**
+ * @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: %lu\n", 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 (find_veriexec_file(fsid, fileid, gen, NULL,
+ VERIEXEC_FILES_FIRST) != NULL);
+}
+
+/**
+ * @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);
+ 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 seach, 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);
+}
+
+/**
+ * @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;
+
+ ip = find_veriexec_file(fsid, fileid, gen, &found_dev, check_files);
+ if (ip == NULL)
+ return (ENOENT);
+
+ *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 = find_veriexec_file(vap->va_fsid, vap->va_fileid,
+ vap->va_gen, &found_dev, check_files);
+ if (ip == NULL) {
+ status = (found_dev) ? FINGERPRINT_NOENTRY :
+ FINGERPRINT_NODEV;
+ VERIEXEC_DEBUG(3,
+ ("fingerprint status is %d for dev %lu, file "
+ "%lu.%lu\n", status, vap->va_fsid, 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 %lu, file "
+ "%lu.%lu\n",
+ (status == FINGERPRINT_INDIRECT) ?
+ "indirect " :
+ (status == FINGERPRINT_FILE) ?
+ "file " : "", vap->va_fsid,
+ 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 %lu, file "
+ "%lu.%lu %s != %s\n", vap->va_fsid,
+ 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],
+ 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;
+
+ /* 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);
+ } 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);
+
+ VERIEXEC_DEBUG(3, ("add file %lu.%lu (files=%d)\n", 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 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);
+}

File Metadata

Mime Type
text/plain
Expires
Thu, Oct 23, 8:19 PM (18 h, 52 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
24072028
Default Alt Text
D8554.id44112.diff (78 KB)

Event Timeline