Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F133084983
D8554.id44112.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
78 KB
Referenced Files
None
Subscribers
None
D8554.id44112.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D8554: Verified execution (veriexec) as a MAC module.
Attached
Detach File
Event Timeline
Log In to Comment