1 /*- 2 * Copyright (c) 2017-2018, Juniper Networks, Inc. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 14 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 15 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 16 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 17 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 18 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 19 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 /* 26 * Routines to verify files loaded. 27 */ 28 #include <sys/cdefs.h> 29 __FBSDID("$FreeBSD$"); 30 31 #include <sys/param.h> 32 #include <string.h> 33 #include <sys/queue.h> 34 35 #include "libsecureboot.h" 36 #include <verify_file.h> 37 #include <manifests.h> 38 39 #ifdef UNIT_TEST 40 # include <err.h> 41 # define panic warn 42 /* 43 * define MANIFEST_SKIP to Skip - in tests/tvo.c so that 44 * tvo can control the value we use in find_manifest() 45 */ 46 extern char *Skip; 47 # undef MANIFEST_SKIP 48 # define MANIFEST_SKIP Skip 49 # undef VE_DEBUG_LEVEL 50 #endif 51 52 /* 53 * We sometimes need to know if input is verified or not. 54 * The extra slot is for tracking most recently opened. 55 */ 56 static int ve_status[SOPEN_MAX+1]; 57 static int ve_status_state; 58 struct verify_status; 59 struct verify_status *verified_files = NULL; 60 static int loaded_manifests = 0; /* have we loaded anything? */ 61 62 #define VE_STATUS_NONE 1 63 #define VE_STATUS_VALID 2 64 65 /** 66 * @brief set ve status for fd 67 */ 68 static void 69 ve_status_set(int fd, int ves) 70 { 71 if (fd >= 0 && fd < SOPEN_MAX) { 72 ve_status[fd] = ves; 73 ve_status_state = VE_STATUS_VALID; 74 } 75 ve_status[SOPEN_MAX] = ves; 76 } 77 78 /** 79 * @brief get ve status of fd 80 * 81 * What we return depends on ve_status_state. 82 * 83 * @return 84 * @li ve_status[fd] if ve_status_state is valid 85 * @li ve_status[SOPEN_MAX] if ve_status_state is none 86 * @li VE_NOT_CHECKED if ve_status_state uninitialized 87 */ 88 int 89 ve_status_get(int fd) 90 { 91 if (!ve_status_state) { 92 return (VE_NOT_CHECKED); 93 } 94 if (ve_status_state == VE_STATUS_VALID && 95 fd >= 0 && fd < SOPEN_MAX) 96 return (ve_status[fd]); 97 return (ve_status[SOPEN_MAX]); /* most recent */ 98 } 99 100 /** 101 * @brief track verify status 102 * 103 * occasionally loader will make multiple calls 104 * for the same file, we need only check it once. 105 */ 106 struct verify_status { 107 dev_t vs_dev; 108 ino_t vs_ino; 109 int vs_status; 110 struct verify_status *vs_next; 111 }; 112 113 int 114 is_verified(struct stat *stp) 115 { 116 struct verify_status *vsp; 117 118 for (vsp = verified_files; vsp != NULL; vsp = vsp->vs_next) { 119 if (stp->st_dev == vsp->vs_dev && 120 stp->st_ino == vsp->vs_ino) 121 return (vsp->vs_status); 122 } 123 return (VE_NOT_CHECKED); 124 } 125 126 /* most recent first, since most likely to see repeated calls. */ 127 void 128 add_verify_status(struct stat *stp, int status) 129 { 130 struct verify_status *vsp; 131 132 vsp = malloc(sizeof(struct verify_status)); 133 vsp->vs_next = verified_files; 134 vsp->vs_dev = stp->st_dev; 135 vsp->vs_ino = stp->st_ino; 136 vsp->vs_status = status; 137 verified_files = vsp; 138 } 139 140 141 /** 142 * @brief 143 * load specified manifest if verified 144 */ 145 int 146 load_manifest(const char *name, const char *prefix, 147 const char *skip, struct stat *stp) 148 { 149 struct stat st; 150 size_t n; 151 int rc; 152 char *content; 153 154 rc = VE_FINGERPRINT_NONE; 155 n = strlen(name); 156 if (n > 4) { 157 if (!stp) { 158 stp = &st; 159 if (stat(name, &st) < 0 || !S_ISREG(st.st_mode)) 160 return (rc); 161 } 162 rc = is_verified(stp); 163 if (rc != VE_NOT_CHECKED) { 164 return (rc); 165 } 166 /* loader has no sense of time */ 167 ve_utc_set(stp->st_mtime); 168 content = (char *)verify_signed(name, VEF_VERBOSE); 169 if (content) { 170 fingerprint_info_add(name, prefix, skip, content, stp); 171 add_verify_status(stp, VE_VERIFIED); 172 loaded_manifests = 1; /* we are verifying! */ 173 DEBUG_PRINTF(3, ("loaded: %s %s %s\n", 174 name, prefix, skip)); 175 rc = 0; 176 } else { 177 rc = VE_FINGERPRINT_WRONG; 178 add_verify_status(stp, rc); /* remember */ 179 } 180 } 181 return (rc); 182 } 183 184 static int 185 find_manifest(const char *name) 186 { 187 struct stat st; 188 char buf[MAXPATHLEN]; 189 char *prefix; 190 char *skip; 191 const char **tp; 192 int rc; 193 194 strncpy(buf, name, MAXPATHLEN - 1); 195 if (!(prefix = strrchr(buf, '/'))) 196 return (-1); 197 *prefix = '\0'; 198 prefix = strdup(buf); 199 rc = VE_FINGERPRINT_NONE; 200 for (tp = manifest_names; *tp; tp++) { 201 snprintf(buf, sizeof(buf), "%s/%s", prefix, *tp); 202 DEBUG_PRINTF(5, ("looking for %s\n", buf)); 203 if (stat(buf, &st) == 0 && st.st_size > 0) { 204 #ifdef MANIFEST_SKIP_ALWAYS /* very unlikely */ 205 skip = MANIFEST_SKIP_ALWAYS; 206 #else 207 #ifdef MANIFEST_SKIP /* rare */ 208 if (*tp[0] == '.') { 209 skip = MANIFEST_SKIP; 210 } else 211 #endif 212 skip = NULL; 213 #endif 214 rc = load_manifest(buf, skip ? prefix : NULL, 215 skip, &st); 216 break; 217 } 218 } 219 free(prefix); 220 return (rc); 221 } 222 223 224 #ifdef LOADER_VERIEXEC_TESTING 225 # define ACCEPT_NO_FP_DEFAULT VE_MUST + 1 226 #else 227 # define ACCEPT_NO_FP_DEFAULT VE_MUST 228 #endif 229 #ifndef VE_VERBOSE_DEFAULT 230 # define VE_VERBOSE_DEFAULT 0 231 #endif 232 233 static int 234 severity_guess(const char *filename) 235 { 236 const char *cp; 237 238 /* Some files like *.conf and *.hints may be unsigned */ 239 if ((cp = strrchr(filename, '.'))) { 240 if (strcmp(cp, ".conf") == 0 || 241 strcmp(cp, ".cookie") == 0 || 242 strcmp(cp, ".hints") == 0) 243 return (VE_TRY); 244 } 245 return (VE_WANT); 246 } 247 248 static void 249 verify_tweak(int fd, off_t off, struct stat *stp, 250 char *tweak, int *accept_no_fp, 251 int *verbose, int *verifying) 252 { 253 if (strcmp(tweak, "off") == 0) { 254 *verifying = 0; 255 } else if (strcmp(tweak, "strict") == 0) { 256 /* anything caller wants verified must be */ 257 *accept_no_fp = VE_WANT; 258 *verbose = 1; /* warn of anything unverified */ 259 /* treat self test failure as fatal */ 260 if (!ve_self_tests()) { 261 panic("verify self tests failed"); 262 } 263 } else if (strcmp(tweak, "modules") == 0) { 264 /* modules/kernel must be verified */ 265 *accept_no_fp = VE_MUST; 266 } else if (strcmp(tweak, "try") == 0) { 267 /* best effort: always accept no fp */ 268 *accept_no_fp = VE_MUST + 1; 269 } else if (strcmp(tweak, "verbose") == 0) { 270 *verbose = 1; 271 } else if (strcmp(tweak, "quiet") == 0) { 272 *verbose = 0; 273 } else if (strncmp(tweak, "trust", 5) == 0) { 274 /* content is trust anchor to add or revoke */ 275 unsigned char *ucp; 276 size_t num; 277 278 if (off > 0) 279 lseek(fd, 0, SEEK_SET); 280 ucp = read_fd(fd, stp->st_size); 281 if (ucp == NULL) 282 return; 283 if (strstr(tweak, "revoke")) { 284 num = ve_trust_anchors_revoke(ucp, stp->st_size); 285 DEBUG_PRINTF(3, ("revoked %d trust anchors\n", 286 (int) num)); 287 } else { 288 num = ve_trust_anchors_add_buf(ucp, stp->st_size); 289 DEBUG_PRINTF(3, ("added %d trust anchors\n", 290 (int) num)); 291 } 292 } 293 } 294 295 #ifndef VE_DEBUG_LEVEL 296 # define VE_DEBUG_LEVEL 0 297 #endif 298 299 static int 300 getenv_int(const char *var, int def) 301 { 302 const char *cp; 303 char *ep; 304 long val; 305 306 val = def; 307 cp = getenv(var); 308 if (cp && *cp) { 309 val = strtol(cp, &ep, 0); 310 if ((ep && *ep) || val != (int)val) { 311 val = def; 312 } 313 } 314 return (int)val; 315 } 316 317 /** 318 * @brief verify an open file 319 * 320 * @param[in] fd 321 * open descriptor 322 * 323 * @param[in] filename 324 * path we opened and will use to lookup fingerprint 325 * 326 * @param[in] off 327 * current offset in fd, must be restored on return 328 * 329 * @param[in] severity 330 * indicator of how to handle case of missing fingerprint 331 * 332 * We look for a signed manifest relative to the filename 333 * just opened and verify/load it if needed. 334 * 335 * We then use verify_fd() in libve to actually verify that hash for 336 * open file. If it returns < 0 we look at the severity arg to decide 337 * what to do about it. 338 * 339 * If verify_fd() returns VE_FINGERPRINT_NONE we accept it if severity 340 * is < accept_no_fp. 341 * 342 * @return >= 0 on success < 0 on failure 343 */ 344 int 345 verify_file(int fd, const char *filename, off_t off, int severity) 346 { 347 static int verifying = -1; 348 static int accept_no_fp = ACCEPT_NO_FP_DEFAULT; 349 static int verbose = VE_VERBOSE_DEFAULT; 350 struct stat st; 351 char *cp; 352 int rc; 353 354 if (verifying < 0) { 355 verifying = ve_trust_init(); 356 verbose = getenv_int("VE_VERBOSE", VE_VERBOSE_DEFAULT); 357 ve_debug_set(getenv_int("VE_DEBUG_LEVEL", VE_DEBUG_LEVEL)); 358 /* initialize ve_status with default result */ 359 rc = verifying ? VE_NOT_CHECKED : VE_NOT_VERIFYING; 360 ve_status_set(0, rc); 361 ve_status_state = VE_STATUS_NONE; 362 if (verifying) { 363 ve_self_tests(); 364 ve_anchor_verbose_set(1); 365 } 366 } 367 if (!verifying) 368 return (0); 369 370 if (fd < 0 || fstat(fd, &st) < 0 || !S_ISREG(st.st_mode)) 371 return (0); 372 373 DEBUG_PRINTF(3, ("fd=%d,name='%s',off=%lld,dev=%lld,ino=%lld\n", 374 fd, filename, (long long)off, (long long)st.st_dev, 375 (long long)st.st_ino)); 376 377 378 rc = is_verified(&st); 379 if (rc != VE_NOT_CHECKED) { 380 ve_status_set(fd, rc); 381 return (rc); 382 } 383 rc = find_manifest(filename); 384 if (rc != VE_FINGERPRINT_WRONG && loaded_manifests) { 385 if (severity <= VE_GUESS) 386 severity = severity_guess(filename); 387 #ifdef VE_PCR_SUPPORT 388 /* 389 * Only update pcr with things that must verify 390 * these tend to be processed in a more deterministic 391 * order, which makes our pseudo pcr more useful. 392 */ 393 ve_pcr_updating_set((severity == VE_MUST)); 394 #endif 395 if ((rc = verify_fd(fd, filename, off, &st)) >= 0) { 396 if (verbose || severity > VE_WANT) { 397 #if defined(VE_DEBUG_LEVEL) && VE_DEBUG_LEVEL > 0 398 printf("%serified %s %llu,%llu\n", 399 (rc == VE_FINGERPRINT_IGNORE) ? "Unv" : "V", 400 filename, 401 (long long)st.st_dev, (long long)st.st_ino); 402 #else 403 printf("%serified %s\n", 404 (rc == VE_FINGERPRINT_IGNORE) ? "Unv" : "V", 405 filename); 406 #endif 407 } 408 if (severity < VE_MUST) { /* not a kernel or module */ 409 410 if ((cp = strrchr(filename, '/'))) { 411 cp++; 412 if (strncmp(cp, "loader.ve.", 10) == 0) { 413 cp += 10; 414 verify_tweak(fd, off, &st, cp, 415 &accept_no_fp, &verbose, 416 &verifying); 417 } 418 } 419 } 420 add_verify_status(&st, rc); 421 ve_status_set(fd, rc); 422 return (rc); 423 } 424 425 if (severity || verbose || rc == VE_FINGERPRINT_WRONG) 426 printf("Unverified: %s\n", ve_error_get()); 427 if (rc == VE_FINGERPRINT_UNKNOWN && severity < VE_MUST) 428 rc = VE_UNVERIFIED_OK; 429 else if (rc == VE_FINGERPRINT_NONE && severity < accept_no_fp) 430 rc = VE_UNVERIFIED_OK; 431 432 add_verify_status(&st, rc); 433 } 434 #ifdef LOADER_VERIEXEC_TESTING 435 else if (rc != VE_FINGERPRINT_WRONG) { 436 /* 437 * We have not loaded any manifest and 438 * not because of verication failure. 439 * Most likely reason is we have none. 440 * Allow boot to proceed if we are just testing. 441 */ 442 return (VE_UNVERIFIED_OK); 443 } 444 #endif 445 if (rc == VE_FINGERPRINT_WRONG && severity > accept_no_fp) 446 panic("cannot continue"); 447 ve_status_set(fd, rc); 448 return (rc); 449 } 450 451 /** 452 * @brief get hex string for pcr value and export 453 * 454 * In case we are doing measured boot, provide 455 * value of the "pcr" data we have accumulated. 456 */ 457 void 458 verify_pcr_export(void) 459 { 460 #ifdef VE_PCR_SUPPORT 461 char hexbuf[br_sha256_SIZE * 2 + 2]; 462 unsigned char hbuf[br_sha256_SIZE]; 463 char *hex; 464 ssize_t hlen; 465 466 hlen = ve_pcr_get(hbuf, sizeof(hbuf)); 467 if (hlen > 0) { 468 hex = hexdigest(hexbuf, sizeof(hexbuf), hbuf, hlen); 469 if (hex) { 470 hex[hlen*2] = '\0'; /* clobber newline */ 471 setenv("loader.ve.pcr", hex, 1); 472 } 473 } 474 #endif 475 } 476