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