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 36 int yylex(void); 37 void yyerror(const char *); 38 39 /* function prototypes */ 40 static int convert(char *fp, unsigned int count, unsigned char *out); 41 static void do_ioctl(void); 42 static int get_fingerprint_type(const char *fp_type); 43 44 /* ioctl parameter struct */ 45 #ifdef MAXLABELLEN 46 static struct verified_exec_label_params lparams; 47 static struct verified_exec_params *params = &lparams.params; 48 #else 49 static struct verified_exec_params oparams; 50 static 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 60 static int fmode; 61 62 extern int lineno; 63 extern int dev_fd; 64 65 struct fingerprint_type { 66 const char *fp_type; 67 int fp_size; 68 }; 69 70 /* static globals */ 71 static 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 */ 86 int 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 102 statement: /* 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 112 attributes: /* empty */ 113 | attributes flag 114 | attributes attr 115 ; 116 117 attr: 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 153 flag: 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 173 path: 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 194 eol: 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 204 void 205 manifest_parser_init(void) 206 { 207 params->fp_type[0] = '\0'; /* invalidate it */ 208 } 209 210 int 211 get_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 */ 227 static int 228 convert(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 */ 258 static void 259 do_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