1 /*- 2 * Copyright (c) 2017-2020, 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 #include <sys/kenv.h> 35 36 #include "libsecureboot.h" 37 #include <verify_file.h> 38 #include <manifests.h> 39 40 #ifdef UNIT_TEST 41 # include <err.h> 42 # define panic warn 43 /* 44 * define MANIFEST_SKIP to Skip - in tests/tvo.c so that 45 * tvo can control the value we use in find_manifest() 46 */ 47 extern char *Destdir; 48 extern size_t DestdirLen; 49 extern char *Skip; 50 # undef MANIFEST_SKIP 51 # define MANIFEST_SKIP Skip 52 # undef VE_DEBUG_LEVEL 53 #endif 54 55 /* 56 * We sometimes need to know if input is verified or not. 57 * The extra slot is for tracking most recently opened. 58 */ 59 static int ve_status[SOPEN_MAX+1]; 60 static int ve_status_state; 61 struct verify_status; 62 struct verify_status *verified_files = NULL; 63 static int loaded_manifests = 0; /* have we loaded anything? */ 64 65 #define VE_STATUS_NONE 1 66 #define VE_STATUS_VALID 2 67 68 /** 69 * @brief set ve status for fd 70 */ 71 static void 72 ve_status_set(int fd, int ves) 73 { 74 if (fd >= 0 && fd < SOPEN_MAX) { 75 ve_status[fd] = ves; 76 ve_status_state = VE_STATUS_VALID; 77 } 78 ve_status[SOPEN_MAX] = ves; 79 } 80 81 /** 82 * @brief get ve status of fd 83 * 84 * What we return depends on ve_status_state. 85 * 86 * @return 87 * @li ve_status[fd] if ve_status_state is valid 88 * @li ve_status[SOPEN_MAX] if ve_status_state is none 89 * @li VE_NOT_CHECKED if ve_status_state uninitialized 90 */ 91 int 92 ve_status_get(int fd) 93 { 94 if (!ve_status_state) { 95 return (VE_NOT_CHECKED); 96 } 97 if (ve_status_state == VE_STATUS_VALID && 98 fd >= 0 && fd < SOPEN_MAX) 99 return (ve_status[fd]); 100 return (ve_status[SOPEN_MAX]); /* most recent */ 101 } 102 103 /** 104 * @brief track verify status 105 * 106 * occasionally loader will make multiple calls 107 * for the same file, we need only check it once. 108 */ 109 struct verify_status { 110 dev_t vs_dev; 111 ino_t vs_ino; 112 int vs_status; 113 struct verify_status *vs_next; 114 }; 115 116 int 117 is_verified(struct stat *stp) 118 { 119 struct verify_status *vsp; 120 121 if (stp->st_ino > 0) { 122 for (vsp = verified_files; vsp != NULL; vsp = vsp->vs_next) { 123 if (stp->st_dev == vsp->vs_dev && 124 stp->st_ino == vsp->vs_ino) 125 return (vsp->vs_status); 126 } 127 } 128 return (VE_NOT_CHECKED); 129 } 130 131 /* most recent first, since most likely to see repeated calls. */ 132 void 133 add_verify_status(struct stat *stp, int status) 134 { 135 struct verify_status *vsp; 136 137 vsp = malloc(sizeof(struct verify_status)); 138 vsp->vs_next = verified_files; 139 vsp->vs_dev = stp->st_dev; 140 vsp->vs_ino = stp->st_ino; 141 vsp->vs_status = status; 142 verified_files = vsp; 143 } 144 145 146 /** 147 * @brief 148 * load specified manifest if verified 149 */ 150 int 151 load_manifest(const char *name, const char *prefix, 152 const char *skip, struct stat *stp) 153 { 154 struct stat st; 155 size_t n; 156 int rc; 157 char *content; 158 159 rc = VE_FINGERPRINT_NONE; 160 n = strlen(name); 161 if (n > 4) { 162 if (!stp) { 163 stp = &st; 164 if (stat(name, &st) < 0 || !S_ISREG(st.st_mode)) 165 return (rc); 166 } 167 rc = is_verified(stp); 168 if (rc != VE_NOT_CHECKED) { 169 return (rc); 170 } 171 /* loader has no sense of time */ 172 ve_utc_set(stp->st_mtime); 173 content = (char *)verify_signed(name, VEF_VERBOSE); 174 if (content) { 175 #ifdef UNIT_TEST 176 if (DestdirLen > 0 && 177 strncmp(name, Destdir, DestdirLen) == 0) { 178 name += DestdirLen; 179 if (prefix && 180 strncmp(prefix, Destdir, DestdirLen) == 0) 181 prefix += DestdirLen; 182 } 183 #endif 184 fingerprint_info_add(name, prefix, skip, content, stp); 185 add_verify_status(stp, VE_VERIFIED); 186 loaded_manifests = 1; /* we are verifying! */ 187 DEBUG_PRINTF(3, ("loaded: %s %s %s\n", 188 name, prefix, skip)); 189 rc = VE_VERIFIED; 190 } else { 191 rc = VE_FINGERPRINT_WRONG; 192 add_verify_status(stp, rc); /* remember */ 193 } 194 } 195 return (rc); 196 } 197 198 static int 199 find_manifest(const char *name) 200 { 201 struct stat st; 202 char buf[MAXPATHLEN]; 203 char *prefix; 204 char *skip; 205 const char **tp; 206 int rc; 207 208 strncpy(buf, name, MAXPATHLEN - 1); 209 if (!(prefix = strrchr(buf, '/'))) 210 return (-1); 211 *prefix = '\0'; 212 prefix = strdup(buf); 213 rc = VE_FINGERPRINT_NONE; 214 for (tp = manifest_names; *tp; tp++) { 215 snprintf(buf, sizeof(buf), "%s/%s", prefix, *tp); 216 DEBUG_PRINTF(5, ("looking for %s\n", buf)); 217 if (stat(buf, &st) == 0 && st.st_size > 0) { 218 #ifdef MANIFEST_SKIP_ALWAYS /* very unlikely */ 219 skip = MANIFEST_SKIP_ALWAYS; 220 #else 221 #ifdef MANIFEST_SKIP /* rare */ 222 if (*tp[0] == '.') { 223 skip = MANIFEST_SKIP; 224 } else 225 #endif 226 skip = NULL; 227 #endif 228 rc = load_manifest(buf, skip ? prefix : NULL, 229 skip, &st); 230 break; 231 } 232 } 233 free(prefix); 234 return (rc); 235 } 236 237 238 #ifdef LOADER_VERIEXEC_TESTING 239 # define ACCEPT_NO_FP_DEFAULT VE_MUST + 1 240 #else 241 # define ACCEPT_NO_FP_DEFAULT VE_MUST 242 #endif 243 #ifndef VE_VERBOSE_DEFAULT 244 # define VE_VERBOSE_DEFAULT 0 245 #endif 246 247 static int 248 severity_guess(const char *filename) 249 { 250 const char *cp; 251 252 /* Some files like *.conf and *.hints may be unsigned */ 253 if ((cp = strrchr(filename, '.'))) { 254 if (strcmp(cp, ".conf") == 0 || 255 strcmp(cp, ".cookie") == 0 || 256 strcmp(cp, ".hints") == 0) 257 return (VE_TRY); 258 if (strcmp(cp, ".4th") == 0 || 259 strcmp(cp, ".lua") == 0 || 260 strcmp(cp, ".rc") == 0) 261 return (VE_MUST); 262 } 263 return (VE_WANT); 264 } 265 266 static int Verifying = -1; /* 0 if not verifying */ 267 268 static void 269 verify_tweak(int fd, off_t off, struct stat *stp, 270 char *tweak, int *accept_no_fp, 271 int *verbose) 272 { 273 if (strcmp(tweak, "off") == 0) { 274 Verifying = 0; 275 } else if (strcmp(tweak, "strict") == 0) { 276 /* anything caller wants verified must be */ 277 *accept_no_fp = VE_WANT; 278 *verbose = 1; /* warn of anything unverified */ 279 /* treat self test failure as fatal */ 280 if (!ve_self_tests()) { 281 panic("verify self tests failed"); 282 } 283 } else if (strcmp(tweak, "modules") == 0) { 284 /* modules/kernel must be verified */ 285 *accept_no_fp = VE_MUST; 286 } else if (strcmp(tweak, "try") == 0) { 287 /* best effort: always accept no fp */ 288 *accept_no_fp = VE_MUST + 1; 289 } else if (strcmp(tweak, "verbose") == 0) { 290 *verbose = 1; 291 } else if (strcmp(tweak, "quiet") == 0) { 292 *verbose = 0; 293 } else if (strncmp(tweak, "trust", 5) == 0) { 294 /* content is trust anchor to add or revoke */ 295 unsigned char *ucp; 296 size_t num; 297 298 if (off > 0) 299 lseek(fd, 0, SEEK_SET); 300 ucp = read_fd(fd, stp->st_size); 301 if (ucp == NULL) 302 return; 303 if (strstr(tweak, "revoke")) { 304 num = ve_trust_anchors_revoke(ucp, stp->st_size); 305 DEBUG_PRINTF(3, ("revoked %d trust anchors\n", 306 (int) num)); 307 } else { 308 num = ve_trust_anchors_add_buf(ucp, stp->st_size); 309 DEBUG_PRINTF(3, ("added %d trust anchors\n", 310 (int) num)); 311 } 312 } 313 } 314 315 #ifndef VE_DEBUG_LEVEL 316 # define VE_DEBUG_LEVEL 0 317 #endif 318 319 static int 320 getenv_int(const char *var, int def) 321 { 322 const char *cp; 323 char *ep; 324 long val; 325 326 val = def; 327 cp = getenv(var); 328 if (cp && *cp) { 329 val = strtol(cp, &ep, 0); 330 if ((ep && *ep) || val != (int)val) { 331 val = def; 332 } 333 } 334 return (int)val; 335 } 336 337 338 /** 339 * @brief prepare to verify an open file 340 * 341 * @param[in] fd 342 * open descriptor 343 * 344 * @param[in] filename 345 * path we opened and will use to lookup fingerprint 346 * 347 * @param[in] stp 348 * stat pointer so we can check file type 349 */ 350 int 351 verify_prep(int fd, const char *filename, off_t off, struct stat *stp, 352 const char *caller) 353 { 354 int rc; 355 356 if (Verifying < 0) { 357 Verifying = ve_trust_init(); 358 #ifndef UNIT_TEST 359 ve_debug_set(getenv_int("VE_DEBUG_LEVEL", VE_DEBUG_LEVEL)); 360 #endif 361 /* initialize ve_status with default result */ 362 rc = Verifying ? VE_NOT_CHECKED : VE_NOT_VERIFYING; 363 ve_status_set(0, rc); 364 ve_status_state = VE_STATUS_NONE; 365 if (Verifying) { 366 ve_self_tests(); 367 ve_anchor_verbose_set(1); 368 } 369 } 370 if (!Verifying || fd < 0) 371 return (0); 372 if (stp) { 373 if (fstat(fd, stp) < 0 || !S_ISREG(stp->st_mode)) 374 return (0); 375 } 376 DEBUG_PRINTF(2, 377 ("verify_prep: caller=%s,fd=%d,name='%s',off=%lld,dev=%lld,ino=%lld\n", 378 caller, fd, filename, (long long)off, (long long)stp->st_dev, 379 (long long)stp->st_ino)); 380 rc = is_verified(stp); 381 DEBUG_PRINTF(4,("verify_prep: is_verified()->%d\n", rc)); 382 if (rc == VE_NOT_CHECKED) { 383 rc = find_manifest(filename); 384 } else { 385 ve_status_set(fd, rc); 386 } 387 return (rc); 388 } 389 390 /** 391 * @brief verify an open file 392 * 393 * @param[in] fd 394 * open descriptor 395 * 396 * @param[in] filename 397 * path we opened and will use to lookup fingerprint 398 * 399 * @param[in] off 400 * current offset in fd, must be restored on return 401 * 402 * @param[in] severity 403 * indicator of how to handle case of missing fingerprint 404 * 405 * We look for a signed manifest relative to the filename 406 * just opened and verify/load it if needed. 407 * 408 * We then use verify_fd() in libve to actually verify that hash for 409 * open file. If it returns < 0 we look at the severity arg to decide 410 * what to do about it. 411 * 412 * If verify_fd() returns VE_FINGERPRINT_NONE we accept it if severity 413 * is < accept_no_fp. 414 * 415 * @return >= 0 on success < 0 on failure 416 */ 417 int 418 verify_file(int fd, const char *filename, off_t off, int severity, 419 const char *caller) 420 { 421 static int once; 422 static int accept_no_fp = ACCEPT_NO_FP_DEFAULT; 423 static int verbose = VE_VERBOSE_DEFAULT; 424 struct stat st; 425 char *cp; 426 int rc; 427 428 rc = verify_prep(fd, filename, off, &st, caller); 429 430 if (!rc) 431 return (0); 432 433 if (!once) { 434 once++; 435 verbose = getenv_int("VE_VERBOSE", VE_VERBOSE_DEFAULT); 436 } 437 438 if (rc != VE_FINGERPRINT_WRONG && loaded_manifests) { 439 if (severity <= VE_GUESS) 440 severity = severity_guess(filename); 441 #ifdef VE_PCR_SUPPORT 442 /* 443 * Only update pcr with things that must verify 444 * these tend to be processed in a more deterministic 445 * order, which makes our pseudo pcr more useful. 446 */ 447 ve_pcr_updating_set((severity == VE_MUST)); 448 #endif 449 #ifdef UNIT_TEST 450 if (DestdirLen > 0 && 451 strncmp(filename, Destdir, DestdirLen) == 0) { 452 filename += DestdirLen; 453 } 454 #endif 455 if ((rc = verify_fd(fd, filename, off, &st)) >= 0) { 456 if (verbose || severity > VE_WANT) { 457 #if defined(VE_DEBUG_LEVEL) && VE_DEBUG_LEVEL > 0 458 printf("%serified %s %llu,%llu\n", 459 (rc == VE_FINGERPRINT_IGNORE) ? "Unv" : "V", 460 filename, 461 (long long)st.st_dev, (long long)st.st_ino); 462 #else 463 printf("%serified %s\n", 464 (rc == VE_FINGERPRINT_IGNORE) ? "Unv" : "V", 465 filename); 466 #endif 467 } 468 if (severity < VE_MUST) { /* not a kernel or module */ 469 if ((cp = strrchr(filename, '/'))) { 470 cp++; 471 if (strncmp(cp, "loader.ve.", 10) == 0) { 472 cp += 10; 473 verify_tweak(fd, off, &st, cp, 474 &accept_no_fp, &verbose); 475 } 476 } 477 } 478 add_verify_status(&st, rc); 479 ve_status_set(fd, rc); 480 return (rc); 481 } 482 483 if (severity || verbose || rc == VE_FINGERPRINT_WRONG) 484 printf("Unverified: %s\n", ve_error_get()); 485 if (rc == VE_FINGERPRINT_UNKNOWN && severity < VE_MUST) 486 rc = VE_UNVERIFIED_OK; 487 else if (rc == VE_FINGERPRINT_NONE && severity < accept_no_fp) 488 rc = VE_UNVERIFIED_OK; 489 490 add_verify_status(&st, rc); 491 } 492 #ifdef LOADER_VERIEXEC_TESTING 493 else if (rc != VE_FINGERPRINT_WRONG) { 494 /* 495 * We have not loaded any manifest and 496 * not because of verication failure. 497 * Most likely reason is we have none. 498 * Allow boot to proceed if we are just testing. 499 */ 500 return (VE_UNVERIFIED_OK); 501 } 502 #endif 503 if (rc == VE_FINGERPRINT_WRONG && severity > accept_no_fp) 504 panic("cannot continue"); 505 ve_status_set(fd, rc); 506 return (rc); 507 } 508 509 /** 510 * @brief get hex string for pcr value and export 511 * 512 * In case we are doing measured boot, provide 513 * value of the "pcr" data we have accumulated. 514 */ 515 void 516 verify_pcr_export(void) 517 { 518 #ifdef VE_PCR_SUPPORT 519 char hexbuf[br_sha256_SIZE * 2 + 2]; 520 unsigned char hbuf[br_sha256_SIZE]; 521 char *hinfo; 522 char *hex; 523 ssize_t hlen; 524 525 hlen = ve_pcr_get(hbuf, sizeof(hbuf)); 526 if (hlen > 0) { 527 hex = hexdigest(hexbuf, sizeof(hexbuf), hbuf, hlen); 528 if (hex) { 529 hex[hlen*2] = '\0'; /* clobber newline */ 530 setenv("loader.ve.pcr", hex, 1); 531 DEBUG_PRINTF(1, 532 ("%s: setenv(loader.ve.pcr, %s\n", __func__, 533 hex)); 534 hinfo = ve_pcr_hashed_get(1); 535 if (hinfo) { 536 setenv("loader.ve.hashed", hinfo, 1); 537 DEBUG_PRINTF(1, 538 ("%s: setenv(loader.ve.hashed, %s\n", 539 __func__, hinfo)); 540 if ((hlen = strlen(hinfo)) > KENV_MVALLEN) { 541 /* 542 * bump kenv_mvallen 543 * roundup to multiple of KENV_MVALLEN 544 */ 545 char mvallen[16]; 546 547 hlen += KENV_MVALLEN - 548 (hlen % KENV_MVALLEN); 549 if (snprintf(mvallen, sizeof(mvallen), 550 "%d", (int) hlen) < sizeof(mvallen)) 551 setenv("kenv_mvallen", mvallen, 1); 552 } 553 free(hinfo); 554 } 555 } 556 } 557 #endif 558 } 559