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