Page MenuHomeFreeBSD

D19281.id55761.diff
No OneTemporary

D19281.id55761.diff

Index: head/lib/libsecureboot/Makefile.libsa.inc
===================================================================
--- head/lib/libsecureboot/Makefile.libsa.inc
+++ head/lib/libsecureboot/Makefile.libsa.inc
@@ -29,6 +29,11 @@
-I${SRCTOP}/stand/efi/include/${MACHINE}
.endif
+.if ${MK_LOADER_VERIEXEC_PASS_MANIFEST} == "yes"
+SRCS+= \
+ pass_manifest.c
+.endif
+
# this is the list of paths (relative to a file
# that we need to verify) used to find a signed manifest.
# the signature extensions in VE_SIGNATURE_EXT_LIST
Index: head/lib/libsecureboot/h/verify_file.h
===================================================================
--- head/lib/libsecureboot/h/verify_file.h
+++ head/lib/libsecureboot/h/verify_file.h
@@ -32,6 +32,7 @@
#define VE_WANT 1 /* we want this verified */
#define VE_MUST 2 /* this must be verified */
+#define VE_NOT_CHECKED -42
#define VE_VERIFIED 1 /* all good */
#define VE_UNVERIFIED_OK 0 /* not verified but that's ok */
#define VE_NOT_VERIFYING 2 /* we are not verifying */
@@ -42,6 +43,8 @@
int ve_status_get(int);
void ve_efi_init(void);
int load_manifest(const char *, const char *, const char *, struct stat *);
+int pass_manifest(const char *, const char *);
+int pass_manifest_export_envs(void);
int verify_file(int, const char *, off_t, int);
void verify_pcr_export(void);
Index: head/lib/libsecureboot/libsecureboot-priv.h
===================================================================
--- head/lib/libsecureboot/libsecureboot-priv.h
+++ head/lib/libsecureboot/libsecureboot-priv.h
@@ -31,6 +31,8 @@
/* public api */
#include "libsecureboot.h"
+struct stat;
+
typedef struct {
unsigned char *data;
size_t hash_size;
@@ -49,6 +51,9 @@
const unsigned char *hash_oid,
unsigned char *mdata, size_t mlen,
unsigned char *sdata, size_t slen);
+
+int is_verified(struct stat *stp);
+void add_verify_status(struct stat *stp, int status);
int openpgp_self_tests(void);
Index: head/lib/libsecureboot/pass_manifest.c
===================================================================
--- head/lib/libsecureboot/pass_manifest.c
+++ head/lib/libsecureboot/pass_manifest.c
@@ -0,0 +1,152 @@
+/*-
+ * Copyright (c) 2019 Stormshield.
+ * Copyright (c) 2019 Semihalf.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/stat.h>
+
+#include "libsecureboot-priv.h"
+#include <verify_file.h>
+
+/*
+ * Values to pass to kernel by envs.
+ */
+static char manifest_path[MAXPATHLEN];
+static char manifest_prefix[MAXPATHLEN];
+static char manifest_hash[2 * br_sha256_SIZE + 2];
+static int manifest_present = 0;
+
+/*
+ * Verify and pass manifest path and digest to kernel through envs.
+ * The paths in manifest can be either absolute,
+ * or "prefix", if exists will be added to the ones that are not.
+ */
+int
+pass_manifest(const char *path, const char *prefix)
+{
+ char *content;
+ struct stat st;
+ unsigned char digest[br_sha256_SIZE];
+ const br_hash_class *md;
+ br_hash_compat_context ctx;
+ int rc;
+
+ content = NULL;
+ md = &br_sha256_vtable;
+
+ if (strnlen(path, MAXPATHLEN) == MAXPATHLEN ||
+ strnlen(prefix, MAXPATHLEN) == MAXPATHLEN)
+ return (EINVAL);
+
+ rc = stat(path, &st);
+ if (rc != 0)
+ goto out;
+
+ if (!S_ISREG(st.st_mode)) {
+ rc = EINVAL;
+ goto out;
+ }
+
+ rc = is_verified(&st);
+
+ if (rc != VE_NOT_CHECKED && rc != VE_VERIFIED) {
+ rc = EPERM;
+ goto out;
+ }
+
+ if (rc == VE_VERIFIED)
+ content = read_file(path, NULL);
+ else
+ content = (char *)verify_signed(path, VEF_VERBOSE);
+
+ if (content == NULL) {
+ add_verify_status(&st, VE_FINGERPRINT_WRONG);
+ rc = EIO;
+ goto out;
+ }
+
+ add_verify_status(&st, VE_VERIFIED);
+
+ md->init(&ctx.vtable);
+ md->update(&ctx.vtable, content, st.st_size);
+ md->out(&ctx.vtable, digest);
+
+ if (prefix == NULL)
+ manifest_prefix[0] = '\0';
+ else
+ strcpy(manifest_prefix, prefix);
+
+ strcpy(manifest_path, path);
+
+ hexdigest(manifest_hash, 2 * br_sha256_SIZE + 2,
+ digest, br_sha256_SIZE);
+ manifest_hash[2*br_sha256_SIZE] = '\0';
+
+ manifest_present = 1;
+ rc = 0;
+
+out:
+ if (content != NULL)
+ free(content);
+
+ return (rc);
+}
+
+/*
+ * Set appropriate envs to inform kernel about manifest location and digest.
+ * This should be called right before boot so that envs can't be replaced.
+ */
+int
+pass_manifest_export_envs()
+{
+ int rc;
+
+ /* If we have nothing to pass make sure that envs are empty. */
+ if (!manifest_present) {
+ unsetenv("veriexec.manifest_path");
+ unsetenv("veriexec.manifest_hash");
+ unsetenv("veriexec.manifest_prefix");
+ return (0);
+ }
+
+ rc = setenv("veriexec.manifest_path", manifest_path, 1);
+ if (rc != 0)
+ return (rc);
+
+ rc = setenv("veriexec.manifest_hash", manifest_hash, 1);
+ if (rc != 0) {
+ unsetenv("veriexec.manifest_path");
+ return (rc);
+ }
+
+ if (manifest_prefix[0] != '\0')
+ rc = setenv("veriexec.manifest_prefix", manifest_prefix, 1);
+
+ return (rc);
+}
+
Index: head/lib/libsecureboot/verify_file.c
===================================================================
--- head/lib/libsecureboot/verify_file.c
+++ head/lib/libsecureboot/verify_file.c
@@ -36,8 +36,6 @@
#include <verify_file.h>
#include <manifests.h>
-#define VE_NOT_CHECKED -42
-
#ifdef UNIT_TEST
# include <err.h>
# define panic warn
@@ -112,7 +110,7 @@
struct verify_status *vs_next;
};
-static int
+int
is_verified(struct stat *stp)
{
struct verify_status *vsp;
@@ -126,7 +124,7 @@
}
/* most recent first, since most likely to see repeated calls. */
-static void
+void
add_verify_status(struct stat *stp, int status)
{
struct verify_status *vsp;
Index: head/share/mk/src.opts.mk
===================================================================
--- head/share/mk/src.opts.mk
+++ head/share/mk/src.opts.mk
@@ -205,6 +205,7 @@
LOADER_FIREWIRE \
LOADER_FORCE_LE \
LOADER_VERBOSE \
+ LOADER_VERIEXEC_PASS_MANIFEST \
NAND \
OFED_EXTRA \
OPENLDAP \
@@ -545,6 +546,10 @@
MK_CLANG_EXTRAS:= no
MK_CLANG_FULL:= no
MK_LLVM_COV:= no
+.endif
+
+.if ${MK_LOADER_VERIEXEC} == "no"
+MK_LOADER_VERIEXEC_PASS_MANIFEST := no
.endif
#
Index: head/stand/common/boot.c
===================================================================
--- head/stand/common/boot.c
+++ head/stand/common/boot.c
@@ -108,6 +108,9 @@
#ifdef LOADER_VERIEXEC
verify_pcr_export(); /* for measured boot */
+#ifdef LOADER_VERIEXEC_PASS_MANIFEST
+ pass_manifest_export_envs();
+#endif
#endif
/* Call the exec handler from the loader matching the kernel */
Index: head/stand/common/module.c
===================================================================
--- head/stand/common/module.c
+++ head/stand/common/module.c
@@ -159,6 +159,13 @@
ve_debug_set(dflag);
return (load_manifest(argv[1], prefix, skip, NULL));
}
+#ifdef LOADER_VERIEXEC_PASS_MANIFEST
+ if (strncmp(typestr, "pass_manifest", 13) == 0) {
+ if (dflag > 0)
+ ve_debug_set(dflag);
+ return (pass_manifest(argv[1], prefix));
+ }
+#endif
#endif
fp = file_findfile(argv[1], typestr);
Index: head/stand/loader.mk
===================================================================
--- head/stand/loader.mk
+++ head/stand/loader.mk
@@ -77,6 +77,10 @@
CFLAGS+= -DLOADER_VERIEXEC -I${SRCTOP}/lib/libsecureboot/h
.endif
+.if ${MK_LOADER_VERIEXEC_PASS_MANIFEST} != "no"
+CFLAGS+= -DLOADER_VERIEXEC_PASS_MANIFEST -I${SRCTOP}/lib/libsecureboot/h
+.endif
+
.if defined(BOOT_PROMPT_123)
CFLAGS+= -DBOOT_PROMPT_123
.endif
Index: head/sys/conf/files
===================================================================
--- head/sys/conf/files
+++ head/sys/conf/files
@@ -4890,14 +4890,15 @@
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
+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_parser/mac_veriexec_parser.c optional mac_veriexec mac_veriexec_parser
+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 !SC_NO_TERM_TEKEN | vt
ufs/ffs/ffs_alloc.c optional ffs
ufs/ffs/ffs_balloc.c optional ffs
Index: head/sys/security/mac_veriexec_parser/mac_veriexec_parser.c
===================================================================
--- head/sys/security/mac_veriexec_parser/mac_veriexec_parser.c
+++ head/sys/security/mac_veriexec_parser/mac_veriexec_parser.c
@@ -0,0 +1,474 @@
+/*-
+ * Copyright (c) 2019 Stormshield.
+ * Copyright (c) 2019 Semihalf.
+ *
+ * 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>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/ctype.h>
+#include <sys/eventhandler.h>
+#include <sys/fcntl.h>
+#include <sys/lock.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/namei.h>
+#include <sys/proc.h>
+#include <sys/systm.h>
+#include <sys/vnode.h>
+
+#include <crypto/sha2/sha256.h>
+#include <crypto/sha2/sha384.h>
+#include <crypto/sha2/sha512.h>
+
+#include <security/mac_veriexec/mac_veriexec.h>
+#include <security/mac_veriexec/mac_veriexec_internal.h>
+
+/* The following are based on sbin/veriexec */
+struct fingerprint_type {
+ const char *fp_type;
+ int fp_size;
+};
+
+struct fp_flag {
+ const char *flag_name;
+ int flag;
+};
+
+static const struct fingerprint_type fp_table[] = {
+ {"sha256=", SHA256_DIGEST_LENGTH},
+#if MAXFINGERPRINTLEN >= SHA384_DIGEST_LENGTH
+ {"sha384=", SHA384_DIGEST_LENGTH},
+#endif
+#if MAXFINGERPRINTLEN >= SHA512_DIGEST_LENGTH
+ {"sha512=", SHA512_DIGEST_LENGTH},
+#endif
+ {NULL, 0}
+};
+
+static const struct fp_flag flags_table[] = {
+ {"indirect", VERIEXEC_INDIRECT},
+ {"no_ptrace", VERIEXEC_NOTRACE},
+ {"trusted", VERIEXEC_TRUSTED},
+ {"no_fips", VERIEXEC_NOFIPS},
+ {NULL, 0}
+};
+
+extern struct mtx ve_mutex;
+
+static unsigned char hexchar_to_byte(unsigned char c);
+static int hexstring_to_bin(unsigned char *buf);
+
+static int get_flags(const char *entry);
+static int get_fp(const char *entry, char **type,
+ unsigned char **digest, int *flags);
+static int verify_digest(const char *data, size_t len,
+ const unsigned char *expected_hash);
+
+static int open_file(const char *path, struct nameidata *nid);
+static char *read_manifest(char *path, unsigned char *digest);
+static int parse_entry(char *entry, char *prefix);
+static int parse_manifest(char *path, unsigned char *hash, char *prefix);
+
+static unsigned char
+hexchar_to_byte(unsigned char c)
+{
+
+ if (isdigit(c))
+ return (c - '0');
+
+ return (isupper(c) ? c - 'A' + 10 : c - 'a' + 10);
+}
+
+static int
+hexstring_to_bin(unsigned char *buf)
+{
+ size_t i, len;
+ unsigned char byte;
+
+ len = strlen(buf);
+ for (i = 0; i < len / 2; i++) {
+ if (!isxdigit(buf[2 * i]) || !isxdigit(buf[2 * i + 1]))
+ return (EINVAL);
+
+ byte = hexchar_to_byte(buf[2 * i]) << 4;
+ byte += hexchar_to_byte(buf[2 * i + 1]);
+ buf[i] = byte;
+ }
+ return (0);
+}
+
+static int
+get_flags(const char *entry)
+{
+ int i;
+ int result = 0;
+
+ for (i = 0; flags_table[i].flag_name != NULL; i++)
+ if (strstr(entry, flags_table[i].flag_name) != NULL)
+ result |= flags_table[i].flag;
+
+ return (result);
+}
+
+/*
+ * Parse a single line of manifest looking for a digest and its type.
+ * We expect it to be in form of "path shaX=hash".
+ * The line will be split into path, hash type and hash value.
+ */
+static int
+get_fp(const char *entry, char **type, unsigned char **digest, int *flags)
+{
+ char *delimiter;
+ char *local_digest;
+ char *fp_type;
+ char *prev_fp_type;
+ size_t min_len;
+ int i;
+
+ delimiter = NULL;
+ fp_type = NULL;
+ prev_fp_type = NULL;
+
+ for (i = 0; fp_table[i].fp_type != NULL; i++) {
+ fp_type = strstr(entry, fp_table[i].fp_type);
+ /* Look for the last "shaX=hash" in line */
+ while (fp_type != NULL) {
+ prev_fp_type = fp_type;
+ fp_type++;
+ fp_type = strstr(fp_type, fp_table[i].fp_type);
+ }
+ fp_type = prev_fp_type;
+ if (fp_type != NULL) {
+ if (fp_type == entry || fp_type[-1] != ' ')
+ return (EINVAL);
+
+ /*
+ * The entry should contain at least
+ * fp_type and digest in hexadecimal form.
+ */
+ min_len = strlen(fp_table[i].fp_type) +
+ 2 * fp_table[i].fp_size;
+
+ if (strnlen(fp_type, min_len) < min_len)
+ return (EINVAL);
+
+ local_digest = &fp_type[strlen(fp_table[i].fp_type)];
+ delimiter = &local_digest[2 * fp_table[i].fp_size];
+
+ /*
+ * Make sure that digest is followed by
+ * some kind of delimiter.
+ */
+ if (*delimiter != '\n' &&
+ *delimiter != '\0' &&
+ *delimiter != ' ')
+ return (EINVAL);
+
+ /*
+ * Does the entry contain flags we need to parse?
+ */
+ if (*delimiter == ' ' && flags != NULL)
+ *flags = get_flags(delimiter);
+
+ /*
+ * Split entry into three parts:
+ * path, fp_type and digest.
+ */
+ local_digest[-1] = '\0';
+ *delimiter = '\0';
+ fp_type[-1] = '\0';
+ break;
+ }
+ }
+
+ if (fp_type == NULL)
+ return (EINVAL);
+
+ if (type != NULL)
+ *type = fp_type;
+
+ if (digest != NULL)
+ *digest = local_digest;
+
+ return (0);
+}
+
+/*
+ * Currently we verify manifest using sha256.
+ * In future another env with hash type could be introduced.
+ */
+static int
+verify_digest(const char *data, size_t len, const unsigned char *expected_hash)
+{
+ SHA256_CTX ctx;
+ unsigned char hash[SHA256_DIGEST_LENGTH];
+
+ SHA256_Init(&ctx);
+ SHA256_Update(&ctx, data, len);
+ SHA256_Final(hash, &ctx);
+
+ return (memcmp(expected_hash, hash, SHA256_DIGEST_LENGTH));
+}
+
+
+static int
+open_file(const char *path, struct nameidata *nid)
+{
+ int flags, rc;
+
+ flags = FREAD;
+
+ pwd_ensure_dirs();
+
+ NDINIT(nid, LOOKUP, 0, UIO_SYSSPACE, path, curthread);
+ rc = vn_open(nid, &flags, 0, NULL);
+ NDFREE(nid, NDF_ONLY_PNBUF);
+ if (rc != 0)
+ return (rc);
+
+ return (0);
+}
+
+/*
+ * Read the manifest from location specified in path and verify its digest.
+ */
+static char*
+read_manifest(char *path, unsigned char *digest)
+{
+ struct nameidata nid;
+ struct vattr va;
+ char *data;
+ ssize_t bytes_read, resid;
+ int rc;
+
+ data = NULL;
+ bytes_read = 0;
+
+ rc = open_file(path, &nid);
+ if (rc != 0)
+ goto fail;
+
+ rc = VOP_GETATTR(nid.ni_vp, &va, curthread->td_ucred);
+ if (rc != 0)
+ goto fail;
+
+ data = (char *)malloc(va.va_size + 1, M_VERIEXEC, M_WAITOK);
+
+ while (bytes_read < va.va_size) {
+ rc = vn_rdwr(
+ UIO_READ, nid.ni_vp, data,
+ va.va_size - bytes_read, bytes_read,
+ UIO_SYSSPACE, IO_NODELOCKED,
+ curthread->td_ucred, NOCRED, &resid, curthread);
+ if (rc != 0)
+ goto fail;
+
+ bytes_read = va.va_size - resid;
+ }
+
+ data[bytes_read] = '\0';
+
+ VOP_UNLOCK(nid.ni_vp, 0);
+ (void)vn_close(nid.ni_vp, FREAD, curthread->td_ucred, curthread);
+
+ /*
+ * If digest is wrong someone might be trying to fool us.
+ */
+ if (verify_digest(data, va.va_size, digest))
+ panic("Manifest hash doesn't match expected value!");
+
+ return (data);
+
+fail:
+ if (data != NULL)
+ free(data, M_VERIEXEC);
+
+ return (NULL);
+}
+
+/*
+ * Process single line.
+ * First split it into path, digest_type and digest.
+ * Then try to open the file and insert its fingerprint into metadata store.
+ */
+static int
+parse_entry(char *entry, char *prefix)
+{
+ struct nameidata nid;
+ struct vattr va;
+ char path[MAXPATHLEN];
+ char *fp_type;
+ unsigned char *digest;
+ int rc, is_exec, flags;
+
+ fp_type = NULL;
+ digest = NULL;
+ flags = 0;
+
+ rc = get_fp(entry, &fp_type, &digest, &flags);
+ if (rc != 0)
+ return (rc);
+
+ rc = hexstring_to_bin(digest);
+ if (rc != 0)
+ return (rc);
+
+ if (strnlen(entry, MAXPATHLEN) == MAXPATHLEN)
+ return (EINVAL);
+
+ /* If the path is not absolute prepend it with a prefix */
+ if (prefix != NULL && entry[0] != '/') {
+ rc = snprintf(path, MAXPATHLEN, "%s/%s",
+ prefix, entry);
+ if (rc < 0)
+ return (-rc);
+ } else {
+ strcpy(path, entry);
+ }
+
+ rc = open_file(path, &nid);
+ NDFREE(&nid, NDF_ONLY_PNBUF);
+ if (rc != 0)
+ return (rc);
+
+ rc = VOP_GETATTR(nid.ni_vp, &va, curthread->td_ucred);
+ if (rc != 0)
+ goto out;
+
+ is_exec = (va.va_mode & VEXEC);
+
+ mtx_lock(&ve_mutex);
+ rc = mac_veriexec_metadata_add_file(
+ is_exec == 0,
+ va.va_fsid, va.va_fileid, va.va_gen,
+ digest, flags, fp_type, 1);
+ mtx_unlock(&ve_mutex);
+
+out:
+ VOP_UNLOCK(nid.ni_vp, 0);
+ vn_close(nid.ni_vp, FREAD, curthread->td_ucred, curthread);
+ return (rc);
+}
+
+/*
+ * Look for manifest in env that have beed passed by loader.
+ * This routine should be called right after the rootfs is mounted.
+ */
+static int
+parse_manifest(char *path, unsigned char *hash, char *prefix)
+{
+ char *data;
+ char *entry;
+ char *next_entry;
+ int rc, success_count;
+
+ data = NULL;
+ success_count = 0;
+ rc = 0;
+
+ data = read_manifest(path, hash);
+ if (data == NULL) {
+ rc = EIO;
+ goto out;
+ }
+
+ entry = data;
+ while (entry != NULL) {
+ next_entry = strchr(entry, '\n');
+ if (next_entry != NULL) {
+ *next_entry = '\0';
+ next_entry++;
+ }
+ if (entry[0] == '\n' || entry[0] == '\0') {
+ entry = next_entry;
+ continue;
+ }
+ if ((rc = parse_entry(entry, prefix)))
+ printf("mac_veriexec_parser: Warning: Failed to parse"
+ " entry with rc:%d, entry:\"%s\"\n", rc, entry);
+ else
+ success_count++;
+
+ entry = next_entry;
+ }
+ rc = 0;
+
+out:
+ if (data != NULL)
+ free(data, M_VERIEXEC);
+
+ if (success_count == 0)
+ rc = EINVAL;
+
+ return (rc);
+}
+
+static void
+parse_manifest_event(void *dummy)
+{
+ char *manifest_path;
+ char *manifest_prefix;
+ unsigned char *manifest_hash;
+ int rc;
+
+ /* If the envs are not set fail silently */
+ manifest_path = kern_getenv("veriexec.manifest_path");
+ if (manifest_path == NULL)
+ return;
+
+ manifest_hash = kern_getenv("veriexec.manifest_hash");
+ if (manifest_hash == NULL) {
+ freeenv(manifest_path);
+ return;
+ }
+
+ manifest_prefix = kern_getenv("veriexec.manifest_prefix");
+
+ if (strlen(manifest_hash) != 2 * SHA256_DIGEST_LENGTH)
+ panic("veriexec.manifest_hash has incorrect size");
+
+ rc = hexstring_to_bin(manifest_hash);
+ if (rc != 0)
+ panic("mac_veriexec: veriexec.loader.manifest_hash"
+ " doesn't contain a hash in hexadecimal form");
+
+ rc = parse_manifest(manifest_path, manifest_hash, manifest_prefix);
+ if (rc != 0)
+ panic("mac_veriexec: Failed to parse manifest err=%d", rc);
+
+ mtx_lock(&ve_mutex);
+ mac_veriexec_set_state(
+ VERIEXEC_STATE_LOADED | VERIEXEC_STATE_ACTIVE |
+ VERIEXEC_STATE_LOCKED | VERIEXEC_STATE_ENFORCE);
+ mtx_unlock(&ve_mutex);
+
+ freeenv(manifest_path);
+ freeenv(manifest_hash);
+ if (manifest_prefix != NULL)
+ freeenv(manifest_prefix);
+}
+
+EVENTHANDLER_DEFINE(mountroot, parse_manifest_event, NULL, 0);
Index: head/tools/build/options/WITH_LOADER_VERIEXEC_PASS_MANFIEST
===================================================================
--- head/tools/build/options/WITH_LOADER_VERIEXEC_PASS_MANFIEST
+++ head/tools/build/options/WITH_LOADER_VERIEXEC_PASS_MANFIEST
@@ -0,0 +1,8 @@
+.\" $FreeBSD$
+Enable building
+.Xr loader 8
+with support to pass a verified manifest to kernel.
+Kernel has to be build with a module to parse the manfiest.
+.Pp
+It depends on
+.Va WITH_LOADER_VERIEXEC

File Metadata

Mime Type
text/plain
Expires
Sun, Feb 1, 5:48 AM (34 m, 41 s)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
28289927
Default Alt Text
D19281.id55761.diff (22 KB)

Event Timeline