Index: head/sbin/veriexecctl/Makefile =================================================================== --- head/sbin/veriexecctl/Makefile +++ head/sbin/veriexecctl/Makefile @@ -0,0 +1,11 @@ +# $FreeBSD$ + +PROG= veriexecctl +MAN= veriexecctl.8 +SRCS= veriexecctl_parse.y veriexecctl_conf.l veriexecctl.c + +WARNS?= 3 + +LIBADD= l + +.include Index: head/sbin/veriexecctl/veriexecctl.8 =================================================================== --- head/sbin/veriexecctl/veriexecctl.8 +++ head/sbin/veriexecctl/veriexecctl.8 @@ -0,0 +1,121 @@ +.\" $NetBSD: veriexecctl.8,v 1.5 2004/03/06 23:40:13 wiz Exp $ +.\" +.\" Copyright (c) 1999 +.\" Brett Lymn - blymn@baea.com.au, brett_lymn@yahoo.com.au +.\" +.\" This code is donated to The NetBSD Foundation by the author. +.\" +.\" 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. +.\" 3. The name of the Author may not be used to endorse or promote +.\" products derived from this software without specific prior written +.\" permission. +.\" +.\" 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$ +.\" +.Dd June 19, 2018 +.Dt VERIEXECCTL 8 +.Os +.Sh NAME +.Nm veriexecctl +.Nd load verified exec fingerprints +.Sh SYNOPSIS +.Nm +.Ar fingerprints +.Sh DESCRIPTION +The +.Nm +command loads an in-kernel metadata store of the fingerprints +given in the +.Ar fingerprints +file. +The kernel can then calculate the fingerprint of programs at time of +execution or files that are opened with +.Dv O_VERIFY +and verify whether the fingerprints match. +.Pp +The +.Ar fingerprints +file contains lines of fields separated by one or more whitespace +characters: +.Pp +.Dl path type fingerprint options +.Bl -tag -width fingerprint +.It Em path +Full path to the file. +.It Em type +Type of fingerprint used. +Currently this may be any of rmd160, sha1, sha256, sha384, or sha512. +Availability of these fingerprint types is dependent on kernel support. +The +.Va security.mac.veriexec.algorithms +sysctl is consulted to determine the list of valid fingerprint types. +.It Em fingerprint +A hexadecimal representation of the fingerprint for the file. +.It Em options +Associated options for the file. +Currently there are four valid options: +.Bl -tag -width INDIRECT +.It Pa INDIRECT +If this option is set then the executable cannot be invoked directly, it +can only be used as an interpreter in shell scripts. +.It Pa FILE +Indicates that the fingerprint is associated with a file, not an +executable. +Files have their fingerprints verified during +.Xr open 2 +and are automatically made read only. +This option may be used to verify shared libraries have not been +tampered with. +.It Pa NO_PTRACE +If this option is set then the executable cannot be traced with the +.Xr ptrace 2 process tracing and debugging call. +.It Pa TRUSTED +If this option is set then the executable is allowed to write to the +.Xr mem 4 +devices. +By default, when verified execution is enforced, no process +is allowed to write to the +.Xr mem 4 +devices. +.El +.El +.Pp +There must be only one executable/fingerprint pair per line. +Comments are indicated by the first character of a line being a +.Sq \&# +character. +.Sh FILES +.Bl -tag -width /dev/veriexec -compact +.It Pa /dev/veriexec +verified executable device node +.El +.Sh SEE ALSO +.Xr sysctl 3 +.Sh HISTORY +.Nm +first appeared in +.Nx 2.0 . +.Sh NOTES +.Nm +requires the kernel to have been configured with the +.Dv MAC_VERIEXEC +option and the veriexec pseudo-device. Index: head/sbin/veriexecctl/veriexecctl.c =================================================================== --- head/sbin/veriexecctl/veriexecctl.c +++ head/sbin/veriexecctl/veriexecctl.c @@ -0,0 +1,144 @@ +/*- + * $FreeBSD$ + * + * Copyright (c) 2015, Juniper Networks, Inc. + * All rights reserved. + * + * Copyright (c) 1998-1999 Brett Lymn + * (blymn@baea.com.au, brett_lymn@yahoo.com.au) + * All rights reserved. + * + * Originally derived from: + * $NetBSD: veriexecctl.c,v 1.5 2004/03/06 11:57:14 blymn Exp $ + * + * This code has been donated to The NetBSD Foundation by the Author. + * + * 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. The name of the author may not be used to endorse or promote products + * derived from this software withough specific prior written permission + * + * 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 +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +/* globals */ +int fd; +extern FILE *yyin; +int yyparse(void); + +const char **algorithms; + +static void +parse_algorithms(void) +{ + static char buf[BUFSIZ]; + size_t len = sizeof(buf); + char *bufp; + int count, indx; + + if (sysctlbyname("security.mac.veriexec.algorithms", buf, &len, NULL, + 0) == -1) + err(EXIT_FAILURE, + "Unable to determine any available algorithms"); + if (len >= sizeof(buf)) + err(EXIT_FAILURE, "Too many algorithms"); + + bufp = buf; + count = 0; + while (strsep(&bufp, " ") != NULL) + count++; + + algorithms = malloc(sizeof(const char *) * (count + 1)); + if (algorithms == NULL) + err(EX_SOFTWARE, "memory allocation failed"); + + indx = 0; + for (bufp = buf; *bufp != '\0'; bufp += strlen(bufp) + 1) + algorithms[indx++] = bufp; +} + +int +main(int argc, char *argv[]) +{ + int ctl = 0; + int x = 0; + + if (argv[1] == NULL) { + fprintf(stderr, "usage: veriexecctl signature_file\n"); + return (1); + } + + fd = open(_PATH_DEV_VERIEXEC, O_WRONLY, 0); + if (fd < 0) { + err(EX_UNAVAILABLE, "Open of veriexec device %s failed", + _PATH_DEV_VERIEXEC); + } + + if (strncmp(argv[1], "--", 2) == 0) { + switch (argv[1][2]) { + case 'a': /* --active */ + ctl = VERIEXEC_ACTIVE; + break; + case 'd': /* --debug* */ + ctl = (strstr(argv[1], "off")) ? + VERIEXEC_DEBUG_OFF : VERIEXEC_DEBUG_ON; + if (argc > 2 && ctl == VERIEXEC_DEBUG_ON) { + x = atoi(argv[2]); + } + break; + case 'e': /* --enforce */ + ctl = VERIEXEC_ENFORCE; + break; + case 'l': /* --lock */ + ctl = VERIEXEC_LOCK; + break; + } + if (ctl) { + if (ioctl(fd, ctl, &x)) { + err(EXIT_FAILURE, "Cannot %s veriexec", + argv[1]); + } + if (ctl == VERIEXEC_DEBUG_ON) { + printf("debug is: %d\n", x); + } + return (0); + } + } else if (strcmp(argv[1], "-")) { + if ((yyin = fopen(argv[1], "r")) == NULL) { + err(EXIT_FAILURE, "Opening signature file %s failed", + argv[1]); + } + } + + parse_algorithms(); + + yyparse(); + return (0); +} Index: head/sbin/veriexecctl/veriexecctl_conf.l =================================================================== --- head/sbin/veriexecctl/veriexecctl_conf.l +++ head/sbin/veriexecctl/veriexecctl_conf.l @@ -0,0 +1,54 @@ +%{ +/* + * $FreeBSD$ + * + * Configuration file lexer for Verified exec + * + * + */ + +#include +#include +#include "veriexecctl_parse.h" + +int lineno = 1; + +void yyerror(const char *message); +void warning(const char *message); +int yylex __P((void)); + +%} + +%% + +path { return PATH; } +string { return STRING; } +eol { return EOL; } + +\/[^ ]+ { + yylval.string = strdup(yytext); + return PATH; +} + +[0-9a-zA-Z]+ { + yylval.string = strdup(yytext); + return STRING; +} + +\n { + lineno++; /* for error reporting */ + return EOL; +} + +[ \t\r] ; /* eat white ones */ + +#.* ; /* comment */ + +. yyerror("invalid character"); + +%% + +void yyerror(const char *string) +{ + fprintf(stderr, "%d: %s at %s\n", lineno, string, yytext); +} Index: head/sbin/veriexecctl/veriexecctl_parse.y =================================================================== --- head/sbin/veriexecctl/veriexecctl_parse.y +++ head/sbin/veriexecctl/veriexecctl_parse.y @@ -0,0 +1,184 @@ +%{ +/* + * $FreeBSD$ + * + * Copyright (c) 2015, Juniper Networks, Inc. + * All rights reserved. + * + * Originally derived from: + * $NetBSD: veriexecctl_parse.y,v 1.3 2004/03/06 11:59:30 blymn Exp $ + * + * Parser for verified exec fingerprint file. + * + * 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. The name of the author may not be used to endorse or promote products + * derived from this software withough specific prior written permission + * + * 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 +#include + +#include +#include +#include +#include + +#include + +/* yacc internal function */ +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); + +/* ioctl parameter struct */ +static struct verified_exec_params params; +extern int fd; +extern int lineno; +extern const char **algorithms; + +%} + +%union { + char *string; + int intval; +} + +%token EOL +%token PATH +%token STRING + +%% + +statement: /* empty */ + | statement path type fingerprint flags eol + | statement error eol { + yyclearin; /* discard lookahead */ + yyerrok; /* no more error */ + fprintf(stderr, "skipping to next fingerprint\n"); + } + ; + +path: PATH +{ + if (strlen($1) >= MAXPATHLEN) { + yyerror("Path >= MAXPATHLEN"); + YYERROR; + } + strncpy(params.file, $1, MAXPATHLEN); +}; + +type: STRING +{ + const char **algop; + + for (algop = algorithms; *algop != NULL; algop++) { + if (strcasecmp($1, *algop) == 0) { + strlcpy(params.fp_type, $1, sizeof(params.fp_type)); + break; + } + } + if (*algop == NULL) { + yyerror("bad fingerprint type"); + YYERROR; + } +}; + +fingerprint: STRING +{ + if (convert($1, MAXFINGERPRINTLEN, params.fingerprint) < 0) { + yyerror("bad fingerprint"); + YYERROR; + } +}; + +flags: /* empty */ + | flag_spec flags; + +flag_spec: STRING +{ + if (strcasecmp($1, "indirect") == 0) + params.flags |= VERIEXEC_INDIRECT; + else if (strcasecmp($1, "file") == 0) + params.flags |= VERIEXEC_FILE; + else if (strcasecmp($1, "no_ptrace") == 0) + params.flags |= VERIEXEC_NOTRACE; + else if (strcasecmp($1, "trusted") == 0) + params.flags |= VERIEXEC_TRUSTED; + else { + yyeror("bad flag specification"); + YYERROR; + } +}; + +eol: EOL +{ + if (!YYRECOVERING()) /* Don't do the ioctl if we saw an error */ + do_ioctl(); +}; + +%% + +/* + * 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) +{ + if (ioctl(fd, VERIEXEC_LOAD, ¶ms) < 0) + fprintf(stderr, "Ioctl failed with error `%s' on file %s\n", + strerror(errno), params.file); + bzero(¶ms, sizeof(params)); +}