1%{ 2/*- 3 * Copyright (c) 2004-2018, Juniper Networks, Inc. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 15 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 16 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 17 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 18 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 20 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27#include <sys/stat.h> 28#include <stdio.h> 29#include <ctype.h> 30#include <err.h> 31#include <sysexits.h> 32#include <libsecureboot.h> 33 34#include "veriexec.h" 35 36int yylex(void); 37void yyerror(const char *); 38 39/* function prototypes */ 40static int convert(char *fp, unsigned int count, unsigned char *out); 41static void do_ioctl(void); 42static int get_fingerprint_type(const char *fp_type); 43 44/* ioctl parameter struct */ 45#ifdef MAXLABELLEN 46static struct verified_exec_label_params lparams; 47static struct verified_exec_params *params = &lparams.params; 48#else 49static struct verified_exec_params oparams; 50static struct verified_exec_params *params = &oparams; 51#endif 52 53#ifndef SHA256_DIGEST_LENGTH 54# define SHA_DIGEST_LENGTH br_sha1_SIZE 55# define SHA256_DIGEST_LENGTH br_sha256_SIZE 56# define SHA384_DIGEST_LENGTH br_sha384_SIZE 57# define SHA512_DIGEST_LENGTH br_sha512_SIZE 58#endif 59 60static int fmode; 61 62extern int lineno; 63extern int dev_fd; 64 65struct fingerprint_type { 66 const char *fp_type; 67 int fp_size; 68}; 69 70/* static globals */ 71static const struct fingerprint_type fingerprint_table[] = { 72 { "sha1", SHA_DIGEST_LENGTH }, 73 { "sha256", SHA256_DIGEST_LENGTH }, 74 { "sha384", SHA384_DIGEST_LENGTH }, 75 { "sha512", SHA512_DIGEST_LENGTH }, 76 { NULL, 0 } 77}; 78 79/* 80 * Indicate to lexer our version. 81 * A token #>NUMBER will be consumed (and discared) 82 * by lexer if parser_version > NUMBER 83 * Otherwise the rest of the line will be discared 84 * as for a comment. 85 */ 86int parser_version = 1; 87 88%} 89 90%union { 91 char *string; 92 int intval; 93} 94 95%token EOL 96%token <string> EQ 97%token <string> PATH 98%token <string> STRING 99 100%% 101 102statement: /* empty */ 103 | statement path attributes eol 104 | statement error eol { 105 yyclearin; /* discard lookahead */ 106 yyerrok; /* no more error */ 107 fprintf(stderr, 108 "skipping to next fingerprint\n"); 109 } 110 ; 111 112attributes: /* empty */ 113 | attributes flag 114 | attributes attr 115 ; 116 117attr: STRING EQ STRING 118{ 119 int fptype; 120 121 fptype = get_fingerprint_type($1); 122 123 /* 124 * There's only one attribute we care about 125 */ 126 if (fingerprint_table[fptype].fp_size) { 127 strlcpy(params->fp_type, $1, sizeof(params->fp_type)); 128 if (convert($3, fingerprint_table[fptype].fp_size, 129 params->fingerprint) < 0) { 130 yyerror("bad fingerprint"); 131 YYERROR; 132 } 133 } else if (strcmp($1, "label") == 0) { 134 static int warned_labels = 0; 135 136#ifdef VERIEXEC_LABEL 137 strlcpy(lparams.label, $3, sizeof(lparams.label)); 138 VERBOSE(3, ("version=%d label=%s\n", VeriexecVersion, 139 lparams.label)); 140 if (VeriexecVersion > 1) { 141 params->flags |= VERIEXEC_LABEL; 142 } else 143#endif 144 if (!warned_labels) { 145 warnx("ignoring labels"); 146 warned_labels = 1; 147 } 148 } else if (strcmp($1, "mode") == 0) { 149 fmode = (int)strtol($3, NULL, 8); 150 } 151}; 152 153flag: STRING 154{ 155 /* 156 * indirect only matters if the interpreter itself is not 157 * executable. 158 */ 159 if (!strcmp($1, "indirect")) { 160 params->flags |= VERIEXEC_INDIRECT; 161 } else if (!strcmp($1, "no_ptrace")) { 162 params->flags |= VERIEXEC_NOTRACE; 163 } else if (!strcmp($1, "trusted")) { 164 params->flags |= VERIEXEC_TRUSTED; 165 } else if (!strcmp($1, "no_fips")) { 166#ifdef VERIEXEC_NOFIPS 167 params->flags |= VERIEXEC_NOFIPS; 168#endif 169 } 170} 171; 172 173path: PATH 174{ 175 if (strlen($1) >= MAXPATHLEN) { 176 yyerror("Path >= MAXPATHLEN"); 177 YYERROR; 178 } 179 /* 180 * The majority of files in the manifest are relative 181 * to the package mount point, but we want absolute paths. 182 * Prepending '/' is actually all we need. 183 */ 184 if (snprintf(params->file, sizeof(params->file), "%s%s%s", 185 Cdir ? Cdir : "", 186 ($1[0] == '/') ? "" : "/", 187 $1) >= (int)sizeof(params->file)) { 188 errx(EX_DATAERR, "cannot form pathname"); 189 } 190 params->flags = 0; 191 fmode = -1; /* unknown */ 192}; 193 194eol: EOL 195{ 196 if (!YYRECOVERING()) { /* Don't do the ioctl if we saw an error */ 197 do_ioctl(); 198 } 199 params->fp_type[0] = '\0'; /* invalidate it */ 200}; 201 202%% 203 204void 205manifest_parser_init(void) 206{ 207 params->fp_type[0] = '\0'; /* invalidate it */ 208} 209 210int 211get_fingerprint_type(const char *fp_type) 212{ 213 int i; 214 215 for (i = 0; fingerprint_table[i].fp_type; i++) 216 if (!strcmp(fp_type, fingerprint_table[i].fp_type)) 217 break; 218 219 return (i); 220} 221 222/* 223 * Convert: takes the hexadecimal string pointed to by fp and converts 224 * it to a "count" byte binary number which is stored in the array pointed to 225 * by out. Returns -1 if the conversion fails. 226 */ 227static int 228convert(char *fp, unsigned int count, unsigned char *out) 229{ 230 unsigned int i; 231 int value; 232 233 for (i = 0; i < count; i++) { 234 value = 0; 235 if (isdigit(fp[i * 2])) 236 value += fp[i * 2] - '0'; 237 else if (isxdigit(fp[i * 2])) 238 value += 10 + tolower(fp[i * 2]) - 'a'; 239 else 240 return (-1); 241 value <<= 4; 242 if (isdigit(fp[i * 2 + 1])) 243 value += fp[i * 2 + 1] - '0'; 244 else if (isxdigit(fp[i * 2 + 1])) 245 value += 10 + tolower(fp[i * 2 + 1]) - 'a'; 246 else 247 return (-1); 248 out[i] = value; 249 } 250 251 return (i); 252} 253 254/* 255 * Perform the load of the fingerprint. Assumes that the fingerprint 256 * pseudo-device is opened and the file handle is in fd. 257 */ 258static void 259do_ioctl(void) 260{ 261 struct stat st; 262 263 if (params->fp_type[0] == '\0') { 264 VERBOSE(1,("skipping %s\n", params->file)); 265 return; 266 } 267 268 /* 269 * See if the path is executable, if not put it on the FILE list. 270 */ 271 if (fmode > 0) { 272 if (!(fmode & (S_IXUSR|S_IXGRP|S_IXOTH))) { 273 params->flags |= VERIEXEC_FILE; 274 } 275 } else if (stat(params->file, &st) == 0) { 276 if (!(st.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH))) { 277 params->flags |= VERIEXEC_FILE; 278 } 279 } 280 /* 281 * We may be forcing some flags... 282 */ 283 params->flags |= ForceFlags; 284 VERBOSE(1, ("loading %s for %s %s flags=%#x\n", 285 params->fp_type, 286 (params->flags == VERIEXEC_FILE) ? "file" : "executable", 287 params->file, params->flags)); 288 289#ifdef VERIEXEC_LABEL 290 if (params->flags & VERIEXEC_LABEL) { 291 if (ioctl(dev_fd, VERIEXEC_LABEL_LOAD, &lparams) < 0) 292 warn("cannot update veriexec label for %s", 293 params->file); 294 } else 295#endif 296 if (ioctl(dev_fd, VERIEXEC_SIGNED_LOAD, params) < 0) 297 warn("cannot update veriexec for %s", params->file); 298 params->fp_type[0] = '\0'; 299} 300