Add verifying manifest loader for mac_veriexec

This tool will verify a signed manifest and load contents into
mac_veriexec for storage

Sponsored by:	Juniper Networks
Differential Revision:	D16575
This commit is contained in:
Simon J. Gerraty 2019-02-26 06:17:23 +00:00
parent a92958df34
commit eb12b8ea5e
10 changed files with 880 additions and 3 deletions

View File

@ -160,6 +160,8 @@
..
usb
..
veriexec
..
vkbd
..
wi
@ -354,6 +356,8 @@
..
mac_partition
..
mac_veriexec
..
..
ssp
..

View File

@ -47,7 +47,7 @@ LSUBDIRS= cam/ata cam/mmc cam/nvme cam/scsi \
dev/hwpmc dev/hyperv \
dev/ic dev/iicbus dev/io dev/mfi dev/mmc dev/nvme \
dev/ofw dev/pbio dev/pci ${_dev_powermac_nvram} dev/ppbus dev/smbus \
dev/speaker dev/tcp_log dev/vkbd dev/wi \
dev/speaker dev/tcp_log dev/veriexec dev/vkbd dev/wi \
fs/devfs fs/fdescfs fs/msdosfs fs/nandfs fs/nfs fs/nullfs \
fs/procfs fs/smbfs fs/udf fs/unionfs \
geom/cache geom/concat geom/eli geom/gate geom/journal geom/label \
@ -60,6 +60,7 @@ LSUBDIRS= cam/ata cam/mmc cam/nvme cam/scsi \
security/audit \
security/mac_biba security/mac_bsdextended security/mac_lomac \
security/mac_mls security/mac_partition \
security/mac_veriexec \
sys/disk \
ufs/ffs ufs/ufs
@ -157,7 +158,7 @@ copies: .PHONY .META
done; \
fi
.endfor
.for i in ${LDIRS} ${LSUBDIRS:Ndev/agp:Ndev/acpica:Ndev/bktr:Ndev/evdev:Ndev/hyperv:Ndev/nand:Ndev/pci} ${LSUBSUBDIRS}
.for i in ${LDIRS} ${LSUBDIRS:Ndev/agp:Ndev/acpica:Ndev/bktr:Ndev/evdev:Ndev/hyperv:Ndev/nand:Ndev/pci:Ndev/veriexec} ${LSUBSUBDIRS}
cd ${SRCTOP}/sys; \
${INSTALL} -C ${TAG_ARGS} -o ${BINOWN} -g ${BINGRP} -m 444 $i/*.h \
${SDESTDIR}${INCLUDEDIR}/$i
@ -196,6 +197,9 @@ copies: .PHONY .META
cd ${SRCTOP}/sys/dev/pci; \
${INSTALL} -C ${TAG_ARGS} -o ${BINOWN} -g ${BINGRP} -m 444 pcireg.h \
${SDESTDIR}${INCLUDEDIR}/dev/pci
cd ${SRCTOP}/sys/dev/veriexec; \
${INSTALL} -C -o ${BINOWN} -g ${BINGRP} -m 444 veriexec_ioctl.h \
${SDESTDIR}${INCLUDEDIR}/dev/veriexec
cd ${SRCTOP}/sys/fs/cd9660/; \
${INSTALL} -C ${TAG_ARGS} -o ${BINOWN} -g ${BINGRP} -m 444 *.h \
${SDESTDIR}${INCLUDEDIR}/isofs/cd9660
@ -264,7 +268,7 @@ symlinks: .PHONY .META
${INSTALL_SYMLINK} ${TAG_ARGS} ../../../sys/$i/$$h ${SDESTDIR}${INCLUDEDIR}/$i; \
done
.endfor
.for i in ${LSUBDIRS:Ndev/agp:Ndev/acpica:Ndev/bktr:Ndev/evdev:Ndev/hyperv:Ndev/nand:Ndev/pci}
.for i in ${LSUBDIRS:Ndev/agp:Ndev/acpica:Ndev/bktr:Ndev/evdev:Ndev/hyperv:Ndev/nand:Ndev/pci:Ndev/veriexec}
cd ${SRCTOP}/sys/$i; \
for h in *.h; do \
${INSTALL_SYMLINK} ${TAG_ARGS} ../../../../sys/$i/$$h ${SDESTDIR}${INCLUDEDIR}/$i; \
@ -312,6 +316,11 @@ symlinks: .PHONY .META
${INSTALL_SYMLINK} ${TAG_ARGS} ../../../../sys/dev/pci/$$h \
${SDESTDIR}${INCLUDEDIR}/dev/pci; \
done
cd ${SRCTOP}/sys/dev/veriexec; \
for h in veriexec_ioctl.h; do \
ln -fs ../../../../sys/dev/veriexec/$$h \
${SDESTDIR}${INCLUDEDIR}/dev/veriexec; \
done
.for i in ${LSUBSUBDIRS}
cd ${SRCTOP}/sys/$i; \
for h in *.h; do \

View File

@ -87,6 +87,7 @@ SUBDIR.${MK_PF}+= pfctl
SUBDIR.${MK_PF}+= pflogd
SUBDIR.${MK_QUOTAS}+= quotacheck
SUBDIR.${MK_ROUTED}+= routed
SUBDIR.${MK_VERIEXEC}+= veriexec
SUBDIR.${MK_ZFS}+= bectl
SUBDIR.${MK_ZFS}+= zfsbootcfg

20
sbin/veriexec/Makefile Normal file
View File

@ -0,0 +1,20 @@
# $FreeBSD$
PROG= veriexec
MAN= veriexec.8
SRCS= \
veriexec.c \
manifest_parser.y \
manifest_lexer.l
LIBADD+= veriexec secureboot bearssl
NO_SHARED=
.include <bsd.prog.mk>
CFLAGS+= -I${.CURDIR} ${XCFLAGS.${.TARGET:T:R}:U}
XCFLAGS.manifest_lexer+= -Wno-missing-variable-declarations \
-Wno-unneeded-internal-declaration
XCFLAGS.manifest_parser+= -Wno-missing-variable-declarations

View File

@ -0,0 +1,20 @@
# $FreeBSD$
# Autogenerated - do NOT edit!
DIRDEPS = \
gnu/lib/csu \
include \
include/xlocale \
lib/${CSU_DIR} \
lib/libbearssl \
lib/libc \
lib/libcompiler_rt \
lib/libsecureboot \
lib/libveriexec \
.include <dirdeps.mk>
.if ${DEP_RELDIR} == ${_DEP_RELDIR}
# local dependencies - needed for -jN in clean tree
.endif

View File

@ -0,0 +1,151 @@
%{
/*-
* Copyright (c) 2004-2018, Juniper Networks, Inc.
*
* 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 COPYRIGHT HOLDERS AND CONTRIBUTORS
* "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 COPYRIGHT
* OWNER OR CONTRIBUTORS 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 <stdio.h>
#include <string.h>
#include "veriexec.h"
#include "manifest_parser.h"
#define YY_NO_UNPUT
int lineno = 1;
int bol = 1;
extern int parser_version;
void yyerror(const char *message);
void warning(const char *message);
int yylex(void);
%}
%%
\n {
lineno++;
bol=1;
return EOL;
}
[/a-zA-Z0-9\.][^ \t\n=]* {
yylval.string = strdup(yytext);
if (bol) {
bol=0;
return PATH;
} else
return STRING;
}
= {
return EQ;
}
[ \t\r] ; /* eat white ones */
#>[0-9]+ {
/*
* If we are older than the specified version
* ignore rest of line, otherwise just discard this token.
*/
int skip = atoi(&yytext[2]);
VERBOSE(3, ("%s: skip if %d <= %d\n", yytext, parser_version, skip));
if (parser_version <= skip) {
/* treat as a comment, yyless() is cheaper than yyunput() */
yytext[yyleng - 1] = '#';
yyless(2);
}
}
#[^>\n].* ; /* comment */
. yyerror("invalid character");
%%
static char *manifest_file = NULL;
struct string_buf {
const char *buf;
size_t pos, size;
};
static int
read_string_buf (void *token, char *dest, int count)
{
struct string_buf *str_buf_p = (struct string_buf *)token;
ssize_t n;
if (count < 0)
return 0;
n = str_buf_p->size - str_buf_p->pos;
if (count < n)
n = count;
memcpy(dest, str_buf_p->buf + str_buf_p->pos, n);
str_buf_p->pos += n;
return n;
}
FILE *
manifest_open (const char *file, const char *file_content)
{
static struct string_buf str_buf;
if (manifest_file) {
free(manifest_file);
fclose(yyin);
}
str_buf.buf = file_content;
str_buf.pos = 0;
str_buf.size = strlen(file_content);
yyin = fropen(&str_buf, read_string_buf);
if (yyin) {
manifest_file = strdup(file);
lineno = 1;
manifest_parser_init();
} else
manifest_file = NULL;
return yyin;
}
void
yyerror(const char *string)
{
fprintf(stderr, "%s: %d: %s at %s\n",
manifest_file, lineno, string, yytext);
}
int
yywrap(void)
{
return (1);
}

View File

@ -0,0 +1,301 @@
%{
/*-
* Copyright (c) 2004-2018, Juniper Networks, Inc.
*
* 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 COPYRIGHT HOLDERS AND CONTRIBUTORS
* "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 COPYRIGHT
* OWNER OR CONTRIBUTORS 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/stat.h>
#include <stdio.h>
#include <ctype.h>
#include <err.h>
#include <sysexits.h>
#include <libsecureboot.h>
#include "veriexec.h"
int yylex(void);
void yyerror(const char *);
/* function prototypes */
static int convert(char *fp, unsigned int count, unsigned char *out);
static void do_ioctl(void);
static int get_fingerprint_type(const char *fp_type);
/* ioctl parameter struct */
#ifdef MAXLABELLEN
static struct verified_exec_label_params lparams;
static struct verified_exec_params *params = &lparams.params;
#else
static struct verified_exec_params oparams;
static struct verified_exec_params *params = &oparams;
#endif
#ifndef SHA256_DIGEST_LENGTH
# define SHA_DIGEST_LENGTH br_sha1_SIZE
# define SHA256_DIGEST_LENGTH br_sha256_SIZE
# define SHA384_DIGEST_LENGTH br_sha384_SIZE
#endif
static int fmode;
extern int lineno;
extern int dev_fd;
struct fingerprint_type {
const char *fp_type;
int fp_size;
};
/* static globals */
static const struct fingerprint_type fingerprint_table[] = {
{ "sha1", SHA_DIGEST_LENGTH },
{ "sha256", SHA256_DIGEST_LENGTH },
#if MAXFINGERPRINTLEN > 32
{ "sha384", SHA384_DIGEST_LENGTH },
#endif
{ NULL, 0 }
};
/*
* Indicate to lexer our version.
* A token #>NUMBER will be consumed (and discared)
* by lexer if parser_version > NUMBER
* Otherwise the rest of the line will be discared
* as for a comment.
*/
int parser_version = 1;
%}
%union {
char *string;
int intval;
}
%token EOL
%token <string> EQ
%token <string> PATH
%token <string> STRING
%%
statement: /* empty */
| statement path attributes eol
| statement error eol {
yyclearin; /* discard lookahead */
yyerrok; /* no more error */
fprintf(stderr,
"skipping to next fingerprint\n");
}
;
attributes: /* empty */
| attributes flag
| attributes attr
;
attr: STRING EQ STRING
{
int fptype;
fptype = get_fingerprint_type($1);
/*
* There's only one attribute we care about
*/
if (fingerprint_table[fptype].fp_size) {
strlcpy(params->fp_type, $1, sizeof(params->fp_type));
if (convert($3, fingerprint_table[fptype].fp_size,
params->fingerprint) < 0) {
yyerror("bad fingerprint");
YYERROR;
}
} else if (strcmp($1, "label") == 0) {
static int warned_labels = 0;
#ifdef VERIEXEC_LABEL
strlcpy(lparams.label, $3, sizeof(lparams.label));
VERBOSE(3, ("version=%d label=%s\n", VeriexecVersion,
lparams.label));
if (VeriexecVersion > 1) {
params->flags |= VERIEXEC_LABEL;
} else
#endif
if (!warned_labels) {
warnx("ignoring labels");
warned_labels = 1;
}
} else if (strcmp($1, "mode") == 0) {
fmode = (int)strtol($3, NULL, 8);
}
};
flag: STRING
{
/*
* indirect only matters if the interpreter itself is not
* executable.
*/
if (!strcmp($1, "indirect")) {
params->flags |= VERIEXEC_INDIRECT;
} else if (!strcmp($1, "no_ptrace")) {
params->flags |= VERIEXEC_NOTRACE;
} else if (!strcmp($1, "trusted")) {
params->flags |= VERIEXEC_TRUSTED;
} else if (!strcmp($1, "no_fips")) {
#ifdef VERIEXEC_NOFIPS
params->flags |= VERIEXEC_NOFIPS;
#endif
}
}
;
path: PATH
{
if (strlen($1) >= MAXPATHLEN) {
yyerror("Path >= MAXPATHLEN");
YYERROR;
}
/*
* The majority of files in the manifest are relative
* to the package mount point, but we want absolute paths.
* Prepending '/' is actually all we need.
*/
if (snprintf(params->file, sizeof(params->file), "%s%s%s",
Cdir ? Cdir : "",
($1[0] == '/') ? "" : "/",
$1) >= (int)sizeof(params->file)) {
errx(EX_DATAERR, "cannot form pathname");
}
params->flags = 0;
fmode = -1; /* unknown */
};
eol: EOL
{
if (!YYRECOVERING()) { /* Don't do the ioctl if we saw an error */
do_ioctl();
}
params->fp_type[0] = '\0'; /* invalidate it */
};
%%
void
manifest_parser_init(void)
{
params->fp_type[0] = '\0'; /* invalidate it */
}
int
get_fingerprint_type(const char *fp_type)
{
int i;
for (i = 0; fingerprint_table[i].fp_type; i++)
if (!strcmp(fp_type, fingerprint_table[i].fp_type))
break;
return (i);
}
/*
* Convert: takes the hexadecimal string pointed to by fp and converts
* it to a "count" byte binary number which is stored in the array pointed to
* by out. Returns -1 if the conversion fails.
*/
static int
convert(char *fp, unsigned int count, unsigned char *out)
{
unsigned int i;
int value;
for (i = 0; i < count; i++) {
value = 0;
if (isdigit(fp[i * 2]))
value += fp[i * 2] - '0';
else if (isxdigit(fp[i * 2]))
value += 10 + tolower(fp[i * 2]) - 'a';
else
return (-1);
value <<= 4;
if (isdigit(fp[i * 2 + 1]))
value += fp[i * 2 + 1] - '0';
else if (isxdigit(fp[i * 2 + 1]))
value += 10 + tolower(fp[i * 2 + 1]) - 'a';
else
return (-1);
out[i] = value;
}
return (i);
}
/*
* Perform the load of the fingerprint. Assumes that the fingerprint
* pseudo-device is opened and the file handle is in fd.
*/
static void
do_ioctl(void)
{
struct stat st;
if (params->fp_type[0] == '\0') {
VERBOSE(1,("skipping %s\n", params->file));
return;
}
/*
* See if the path is executable, if not put it on the FILE list.
*/
if (fmode > 0) {
if (!(fmode & (S_IXUSR|S_IXGRP|S_IXOTH))) {
params->flags |= VERIEXEC_FILE;
}
} else if (stat(params->file, &st) == 0) {
if (!(st.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH))) {
params->flags |= VERIEXEC_FILE;
}
}
/*
* We may be forcing some flags...
*/
params->flags |= ForceFlags;
VERBOSE(1, ("loading %s for %s %s flags=%#x\n",
params->fp_type,
(params->flags == VERIEXEC_FILE) ? "file" : "executable",
params->file, params->flags));
#ifdef VERIEXEC_LABEL
if (params->flags & VERIEXEC_LABEL) {
if (ioctl(dev_fd, VERIEXEC_LABEL_LOAD, &lparams) < 0)
warn("cannot update veriexec label for %s",
params->file);
} else
#endif
if (ioctl(dev_fd, VERIEXEC_SIGNED_LOAD, params) < 0)
warn("cannot update veriexec for %s", params->file);
params->fp_type[0] = '\0';
}

146
sbin/veriexec/veriexec.8 Normal file
View File

@ -0,0 +1,146 @@
.\"-
.\" Copyright (c) 2018, Juniper Networks, Inc.
.\"
.\" 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 COPYRIGHT HOLDERS AND CONTRIBUTORS
.\" "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 COPYRIGHT
.\" OWNER OR CONTRIBUTORS 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$
.\"
.Dd July 4, 2018
.Dt VERIEXEC 8
.Os
.Sh NAME
.Nm veriexec
.Nd manipulate state of mac_veriexec
.Sh SYNOPSIS
.Nm
.Op Fl v
.Op Fl C Ar directory
.Pa manifest
.Nm
.Fl z Ar state
.Nm
.Fl i Ar state
.Nm
.Fl x
.Ar file ...
.Sh DESCRIPTION
.Nm
is a utility to query or manipulate the state of
.Xr mac_veriexec 4 .
.Pp
The first form is for loading a
.Pa manifest .
.Nm
first verifies a digital signature of the
.Ar manifest
and if successful, parses it and feeds its content to kernel.
.Pp
The second form with
.Fl z
is used to modify the
.Ar state ,
and with
.Fl i
to query the current
.Ar state .
.Pp
The final form with
.Fl x
is used to test whether
.Ar file
is verified or not.
This requires
.Xr mac_veriexec 4
to be in the
.Ql active
or
.Ql enforce
state.
.Pp
The possible states
are:
.Bl -tag -width enforce
.It Ar loaded
set automatically when first
.Pa manifest
has been loaded.
.It Ar active
.Xr mac_veriexec 4
will begin checking files.
This state can only be entered from the
.Ar loaded
state.
.It Ar enforce
.Xr mac_veriexec 4
will fail attempts to
.Xr exec 2
or
.Xr open 2
files with
.Dv O_VERIFY
unless verified.
.It Ar locked
prevent loading of any more manifests.
.El
.Sh MANIFESTS
The manifest contains a mapping of relative pathnames to fingerprints
with optional flags.
For example:
.Bd -literal -offset indent
sbin/veriexec sha256=f22136...c0ff71 no_ptrace
usr/bin/python sha256=5944d9...876525 indirect
sbin/somedaemon sha256=77fc2f...63f5687 label=mod1/val1,mod2/val2
.Ed
The supported flags are:
.Bl -tag -width indirect
.It Ql indirect
the executable cannot be run directly,
but can be used as an interpreter for example via:
.Bd -literal -offset indent
#!/usr/bin/python
.Ed
.It Ql no_ptrace
do not allow running executable under a debugger.
Useful for any application critical to the security state of system.
.El
.Pp
The
.Ql label
argument allows associating a
.Xr maclabel 7
with the executable.
Neither
.Nm
nor
.Xr mac_veriexec 4
(if it supports labels)
pay any attention to the content of the label
they are provided for the use of other
.Xr mac 4
modules.
.Sh HISTORY
The Verified Exec system first appeared in NetBSD.
This utility derrives from the one found in Junos.
The key difference is the requirement that manifest files
be digitally signed.

177
sbin/veriexec/veriexec.c Normal file
View File

@ -0,0 +1,177 @@
/*-
* Copyright (c) 2018, Juniper Networks, Inc.
*
* 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 COPYRIGHT HOLDERS AND CONTRIBUTORS
* "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 COPYRIGHT
* OWNER OR CONTRIBUTORS 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 <stdlib.h>
#include <sysexits.h>
#include <unistd.h>
#include <paths.h>
#include <err.h>
#include <syslog.h>
#include <libsecureboot.h>
#include <libveriexec.h>
#include "veriexec.h"
int dev_fd = -1;
int ForceFlags = 0;
int Verbose = 0;
int VeriexecVersion = 0;
const char *Cdir = NULL;
static int
veriexec_load(const char *manifest)
{
unsigned char *content;
int rc;
content = verify_signed(manifest, VEF_VERBOSE);
if (!content)
errx(EX_USAGE, "cannot verify %s", manifest);
if (manifest_open(manifest, content)) {
rc = yyparse();
} else {
err(EX_NOINPUT, "cannot load %s", manifest);
}
free(content);
return (rc);
}
int
main(int argc, char *argv[])
{
unsigned long ctl;
int c;
int x;
dev_fd = open(_PATH_DEV_VERIEXEC, O_WRONLY, 0);
while ((c = getopt(argc, argv, "C:i:x:vz:")) != -1) {
switch (c) {
case 'C':
Cdir = optarg;
break;
case 'i':
if (dev_fd < 0) {
err(EX_UNAVAILABLE, "cannot open veriexec");
}
if (ioctl(dev_fd, VERIEXEC_GETSTATE, &x)) {
err(EX_UNAVAILABLE,
"Cannot get veriexec state");
}
switch (optarg[0]) {
case 'a': /* active */
ctl = VERIEXEC_STATE_ACTIVE;
break;
case 'e': /* enforce */
ctl = VERIEXEC_STATE_ENFORCE;
break;
case 'l': /* loaded/locked */
ctl = (strncmp(optarg, "lock", 4)) ?
VERIEXEC_STATE_LOCKED :
VERIEXEC_STATE_LOADED;
break;
default:
errx(EX_USAGE, "unknown state %s", optarg);
break;
}
exit((x & ctl) == 0);
break;
case 'v':
Verbose++;
break;
case 'x':
/*
* -x says all other args are paths to check.
*/
for (x = 0; optind < argc; optind++) {
if (veriexec_check_path(argv[optind])) {
warn("%s", argv[optind]);
x = 2;
}
}
exit(x);
break;
case 'z':
switch (optarg[0]) {
case 'a': /* active */
ctl = VERIEXEC_ACTIVE;
break;
case 'd': /* debug* */
ctl = (strstr(optarg, "off")) ?
VERIEXEC_DEBUG_OFF : VERIEXEC_DEBUG_ON;
if (optind < argc && ctl == VERIEXEC_DEBUG_ON) {
x = atoi(argv[optind]);
if (x == 0)
ctl = VERIEXEC_DEBUG_OFF;
}
break;
case 'e': /* enforce */
ctl = VERIEXEC_ENFORCE;
break;
case 'g':
ctl = VERIEXEC_GETSTATE; /* get state */
break;
case 'l': /* lock */
ctl = VERIEXEC_LOCK;
break;
default:
errx(EX_USAGE, "unknown command %s", optarg);
break;
}
if (dev_fd < 0) {
err(EX_UNAVAILABLE, "cannot open veriexec");
}
if (ioctl(dev_fd, ctl, &x)) {
err(EX_UNAVAILABLE, "cannot %s veriexec", optarg);
}
if (ctl == VERIEXEC_DEBUG_ON ||
ctl == VERIEXEC_DEBUG_OFF) {
printf("debug is: %d\n", x);
} else if (ctl == VERIEXEC_GETSTATE) {
printf("%#o\n", x);
}
exit(EX_OK);
break;
}
}
openlog(getprogname(), LOG_PID, LOG_AUTH);
if (ve_trust_init() < 1)
errx(EX_OSFILE, "cannot initialize trust store");
#ifdef VERIEXEC_GETVERSION
if (ioctl(dev_fd, VERIEXEC_GETVERSION, &VeriexecVersion)) {
VeriexecVersion = 0; /* unknown */
}
#endif
for (; optind < argc; optind++) {
if (veriexec_load(argv[optind])) {
err(EX_DATAERR, "cannot load %s", argv[optind]);
}
}
exit(EX_OK);
}

48
sbin/veriexec/veriexec.h Normal file
View File

@ -0,0 +1,48 @@
/*-
* Copyright (c) 2018, Juniper Networks, Inc.
*
* 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 COPYRIGHT HOLDERS AND CONTRIBUTORS
* "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 COPYRIGHT
* OWNER OR CONTRIBUTORS 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$
*/
#ifndef __VERIEXEC_H__
#define __VERIEXEC_H__
#include <sys/ioctl.h>
#include <dev/veriexec/veriexec_ioctl.h>
extern int dev_fd;
extern int parser_version;
extern int ForceFlags;
extern int Verbose;
extern int VeriexecVersion;
extern const char *Cdir;
#define VERBOSE(n, x) if (Verbose > n) printf x
FILE * manifest_open (const char *file, const char *file_content);
void manifest_parser_init(void);
int yyparse(void);
extern FILE *yyin;
#endif