1 /* 2 * $FreeBSD$ 3 * 4 * Copyright (c) 2011, 2012, 2013, 2015, 2016, Juniper Networks, Inc. 5 * All rights reserved. 6 * 7 * Originally derived from: 8 * $NetBSD: kern_verifiedexec.c,v 1.7 2003/11/18 13:13:03 martin Exp $ 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 24 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 26 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 34 #include "opt_mac.h" 35 36 #include <sys/param.h> 37 #include <sys/systm.h> 38 #include <sys/exec.h> 39 #include <sys/lock.h> 40 #include <sys/malloc.h> 41 #include <sys/mutex.h> 42 #include <sys/proc.h> 43 #include <sys/sbuf.h> 44 #include <sys/vnode.h> 45 46 #include "mac_veriexec.h" 47 #include "mac_veriexec_internal.h" 48 49 /** 50 * @brief per-device meta-data storage 51 */ 52 struct veriexec_dev_list { 53 dev_t fsid; /**< file system identifier of the mount point */ 54 LIST_HEAD(filehead, mac_veriexec_file_info) file_head; 55 /**< list of per-file meta-data information */ 56 LIST_ENTRY(veriexec_dev_list) entries; 57 /**< next entries in the device list */ 58 }; 59 60 typedef LIST_HEAD(veriexec_devhead, veriexec_dev_list) veriexec_devhead_t; 61 62 /** 63 * @brief Mutex to protect the meta-data store lists 64 */ 65 struct mtx ve_mutex; 66 67 /** 68 * @brief Executables meta-data storage 69 * 70 * This is used to store the fingerprints for potentially-executable files. 71 */ 72 veriexec_devhead_t veriexec_dev_head; 73 74 /** 75 * @brief Plain file meta-data storage 76 * 77 * This is used for files that are not allowed to be executed, but should 78 * have fingerprint validation available. 79 */ 80 veriexec_devhead_t veriexec_file_dev_head; 81 82 /** 83 * @internal 84 * @brief Search the @p head meta-data list for the specified file identifier 85 * @p fileid in the file system identified by @p fsid 86 * 87 * If meta-data exists for file system identified by @p fsid, it has a 88 * fingerprint list, and @p found_dev is not @c NULL then store true in the 89 * location pointed to by @p found_dev 90 * 91 * @param head meta-data list to search 92 * @param fsid file system identifier to look for 93 * @param fileid file to look for 94 * @param gen generation of file 95 * @param found_dev indicator that an entry for the file system was found 96 * 97 * @return A pointer to the meta-data inforation if meta-data exists for 98 * the specified file identifier, otherwise @c NULL 99 */ 100 static struct mac_veriexec_file_info * 101 get_veriexec_file(struct veriexec_devhead *head, dev_t fsid, long fileid, 102 unsigned long gen, int *found_dev) 103 { 104 struct veriexec_dev_list *lp; 105 struct mac_veriexec_file_info *ip, *tip; 106 107 ip = NULL; 108 109 /* Initialize the value found_dev, if non-NULL */ 110 if (found_dev != NULL) 111 *found_dev = 0; 112 113 VERIEXEC_DEBUG(3, ("searching for file %ju.%lu on device %ju," 114 " files=%d\n", (uintmax_t)fileid, gen, (uintmax_t)fsid, 115 (head == &veriexec_file_dev_head))); 116 117 /* Get a lock to access the list */ 118 mtx_lock(&ve_mutex); 119 120 /* First, look for the file system */ 121 for (lp = LIST_FIRST(head); lp != NULL; lp = LIST_NEXT(lp, entries)) 122 if (lp->fsid == fsid) 123 break; 124 125 /* We found the file system in the list */ 126 if (lp != NULL) { 127 VERIEXEC_DEBUG(3, ("found matching dev number %ju\n", 128 (uintmax_t)lp->fsid)); 129 130 /* If found_dev is non-NULL, store true there */ 131 if (found_dev != NULL) 132 *found_dev = 1; 133 134 /* Next, look for the meta-data information for the file */ 135 LIST_FOREACH_SAFE(ip, &(lp->file_head), entries, tip) { 136 if (ip->fileid == fileid) { 137 if (ip->gen == gen) 138 break; 139 /* we need to garbage collect */ 140 LIST_REMOVE(ip, entries); 141 free(ip, M_VERIEXEC); 142 } 143 } 144 } 145 146 /* Release the lock we obtained earlier */ 147 mtx_unlock(&ve_mutex); 148 149 /* Return the meta-data information we found, if anything */ 150 return (ip); 151 } 152 153 /** 154 * @internal 155 * @brief Search the meta-data store for information on the specified file. 156 * 157 * @param fsid file system identifier to look for 158 * @param fileid file to look for 159 * @param gen generation of file 160 * @param found_dev indicator that an entry for the file system was found 161 * @param check_files if 1, check the files list first, otherwise check the 162 * exectuables list first 163 * 164 * @return A pointer to the meta-data inforation if meta-data exists for 165 * the specified file identifier, otherwise @c NULL 166 */ 167 static struct mac_veriexec_file_info * 168 find_veriexec_file(dev_t fsid, long fileid, unsigned long gen, int *found_dev, 169 int check_files) 170 { 171 struct veriexec_devhead *search[3]; 172 struct mac_veriexec_file_info *ip; 173 int x; 174 175 /* Determine the order of the lists to search */ 176 if (check_files) { 177 search[0] = &veriexec_file_dev_head; 178 search[1] = &veriexec_dev_head; 179 } else { 180 search[0] = &veriexec_dev_head; 181 search[1] = &veriexec_file_dev_head; 182 } 183 search[2] = NULL; 184 185 VERIEXEC_DEBUG(3, ("%s: searching for dev %ju, file %lu\n", 186 __func__, (uintmax_t)fsid, fileid)); 187 188 /* Search for the specified file */ 189 for (ip = NULL, x = 0; ip == NULL && search[x]; x++) 190 ip = get_veriexec_file(search[x], fsid, fileid, gen, found_dev); 191 192 return (ip); 193 } 194 195 /** 196 * @internal 197 * @brief Display the fingerprint for each entry in the device list 198 * 199 * @param sbp sbuf to write output to 200 * @param lp pointer to device list 201 */ 202 static void 203 mac_veriexec_print_db_dev_list(struct sbuf *sbp, struct veriexec_dev_list *lp) 204 { 205 struct mac_veriexec_file_info *ip; 206 207 #define FPB(i) (ip->fingerprint[i]) 208 for (ip = LIST_FIRST(&(lp->file_head)); ip != NULL; 209 ip = LIST_NEXT(ip, entries)) 210 sbuf_printf(sbp, " %ld: %u %ld [%02x %02x %02x %02x %02x " 211 "%02x %02x %02x...]\n", ip->fileid, ip->flags, ip->gen, 212 FPB(0), FPB(1), FPB(2), FPB(3), FPB(4), FPB(5), FPB(6), 213 FPB(7)); 214 } 215 216 /** 217 * @internal 218 * @brief Display the device list 219 * 220 * @param sbp sbuf to write output to 221 * @param head pointer to head of the device list 222 */ 223 static void 224 mac_veriexec_print_db_head(struct sbuf *sbp, struct veriexec_devhead *head) 225 { 226 struct veriexec_dev_list *lp; 227 228 for (lp = LIST_FIRST(head); lp != NULL; lp = LIST_NEXT(lp, entries)) { 229 sbuf_printf(sbp, " FS id: %ju\n", (uintmax_t)lp->fsid); 230 mac_veriexec_print_db_dev_list(sbp, lp); 231 } 232 233 } 234 235 /** 236 * @internal 237 * @brief Generate human-readable output for the current fingerprint database 238 * 239 * @param sbp sbuf to write output to 240 */ 241 void 242 mac_veriexec_metadata_print_db(struct sbuf *sbp) 243 { 244 struct { 245 struct veriexec_devhead *h; 246 const char *name; 247 } fpdbs[] = { 248 { &veriexec_file_dev_head, "regular files" }, 249 { &veriexec_dev_head, "executable files" }, 250 }; 251 int i; 252 253 mtx_lock(&ve_mutex); 254 for (i = 0; i < sizeof(fpdbs)/sizeof(fpdbs[0]); i++) { 255 sbuf_printf(sbp, "%s fingerprint db:\n", fpdbs[i].name); 256 mac_veriexec_print_db_head(sbp, fpdbs[i].h); 257 } 258 mtx_unlock(&ve_mutex); 259 } 260 /** 261 * @brief Determine if the meta-data store has an entry for the specified file. 262 * 263 * @param fsid file system identifier to look for 264 * @param fileid file to look for 265 * @param gen generation of file 266 * 267 * @return 1 if there is an entry in the meta-data store, 0 otherwise. 268 */ 269 int 270 mac_veriexec_metadata_has_file(dev_t fsid, long fileid, unsigned long gen) 271 { 272 273 return (find_veriexec_file(fsid, fileid, gen, NULL, 274 VERIEXEC_FILES_FIRST) != NULL); 275 } 276 277 /** 278 * @brief Search the list of devices looking for the one given, in order to 279 * release the resources used by it. 280 * 281 * If found, free all file entries for it, and remove it from the list. 282 * 283 * @note Called with @a ve_mutex held 284 * 285 * @param fsid file system identifier to look for 286 * @param head meta-data list to search 287 * 288 * @return 0 if the device entry was freed, otherwise an error code 289 */ 290 static int 291 free_veriexec_dev(dev_t fsid, struct veriexec_devhead *head) 292 { 293 struct veriexec_dev_list *lp; 294 struct mac_veriexec_file_info *ip, *nip; 295 296 /* Look for the file system */ 297 for (lp = LIST_FIRST(head); lp != NULL; 298 lp = LIST_NEXT(lp, entries)) 299 if (lp->fsid == fsid) break; 300 301 /* If lp is NULL, we did not find it */ 302 if (lp == NULL) 303 return ENOENT; 304 305 /* Unhook lp, before we free it and its content */ 306 LIST_REMOVE(lp, entries); 307 308 /* Release the lock */ 309 mtx_unlock(&ve_mutex); 310 311 /* Free the file entries in the list */ 312 for (ip = LIST_FIRST(&(lp->file_head)); ip != NULL; ip = nip) { 313 nip = LIST_NEXT(ip, entries); 314 LIST_REMOVE(ip, entries); 315 free(ip, M_VERIEXEC); 316 } 317 318 /* Free the meta-data entry for the device */ 319 free(lp, M_VERIEXEC); 320 321 /* Re-acquire the lock */ 322 mtx_lock(&ve_mutex); 323 return 0; 324 } 325 326 /** 327 * @brief Search the list of devices looking for the one given. 328 * 329 * If it is not in the list then add it. 330 * 331 * @note Called with @a ve_mutex held 332 * 333 * @param fsid file system identifier to look for 334 * @param head meta-data list to search 335 * 336 * @return A pointer to the meta-data entry for the device, if found or added, 337 * otherwise @c NULL 338 */ 339 static struct veriexec_dev_list * 340 find_veriexec_dev(dev_t fsid, struct veriexec_devhead *head) 341 { 342 struct veriexec_dev_list *lp; 343 struct veriexec_dev_list *np = NULL; 344 345 search: 346 /* Look for the file system */ 347 for (lp = LIST_FIRST(head); lp != NULL; 348 lp = LIST_NEXT(lp, entries)) 349 if (lp->fsid == fsid) break; 350 351 if (lp == NULL) { 352 if (np == NULL) { 353 /* 354 * If pointer is null then entry not there, 355 * add a new one, first try to malloc while 356 * we hold mutex - should work most of the time. 357 */ 358 np = malloc(sizeof(struct veriexec_dev_list), 359 M_VERIEXEC, M_NOWAIT); 360 if (np == NULL) { 361 /* 362 * So much for that plan, dop the mutex 363 * and repeat... 364 */ 365 mtx_unlock(&ve_mutex); 366 np = malloc(sizeof(struct veriexec_dev_list), 367 M_VERIEXEC, M_WAITOK); 368 mtx_lock(&ve_mutex); 369 /* 370 * Repeat the seach, in case someone 371 * added this while we slept. 372 */ 373 goto search; 374 } 375 } 376 if (np) { 377 /* Add the entry to the list */ 378 lp = np; 379 LIST_INIT(&(lp->file_head)); 380 lp->fsid = fsid; 381 LIST_INSERT_HEAD(head, lp, entries); 382 } 383 } else if (np) { 384 /* 385 * Someone else did it while we slept. 386 */ 387 mtx_unlock(&ve_mutex); 388 free(np, M_VERIEXEC); 389 mtx_lock(&ve_mutex); 390 } 391 392 return (lp); 393 } 394 395 /** 396 * @brief When a device is unmounted, we want to toss the signatures recorded 397 * against it. 398 * 399 * We are being called from unmount() with the root vnode just before it is 400 * freed. 401 * 402 * @param fsid file system identifier to look for 403 * @param td calling thread 404 * 405 * @return 0 on success, otherwise an error code. 406 */ 407 int 408 mac_veriexec_metadata_unmounted(dev_t fsid, struct thread *td) 409 { 410 int error; 411 412 /* 413 * The device can have entries on both lists. 414 */ 415 mtx_lock(&ve_mutex); 416 error = free_veriexec_dev(fsid, &veriexec_dev_head); 417 if (error && error != ENOENT) { 418 mtx_unlock(&ve_mutex); 419 return error; 420 } 421 error = free_veriexec_dev(fsid, &veriexec_file_dev_head); 422 mtx_unlock(&ve_mutex); 423 if (error && error != ENOENT) { 424 return error; 425 } 426 return 0; 427 } 428 429 /** 430 * @brief Return the flags assigned to the file identified by file system 431 * identifier @p fsid and file identifier @p fileid. 432 * 433 * @param fsid file system identifier 434 * @param fileid file identifier within the file system 435 * @param gen generation of file 436 * @param flags pointer to location to store the flags 437 * @param check_files if 1, check the files list first, otherwise check the 438 * exectuables list first 439 * 440 * @return 0 on success, otherwise an error code. 441 */ 442 int 443 mac_veriexec_metadata_get_file_flags(dev_t fsid, long fileid, unsigned long gen, 444 int *flags, int check_files) 445 { 446 struct mac_veriexec_file_info *ip; 447 int found_dev; 448 449 ip = find_veriexec_file(fsid, fileid, gen, &found_dev, check_files); 450 if (ip == NULL) 451 return (ENOENT); 452 453 *flags = ip->flags; 454 return (0); 455 } 456 457 /** 458 * @brief get the files for the specified process 459 * 460 * @param cred credentials to use 461 * @param p process to get the flags for 462 * @param flags where to store the flags 463 * @param check_files if 1, check the files list first, otherwise check the 464 * exectuables list first 465 * 466 * @return 0 if the process has an entry in the meta-data store, otherwise an 467 * error code 468 */ 469 int 470 mac_veriexec_metadata_get_executable_flags(struct ucred *cred, struct proc *p, 471 int *flags, int check_files) 472 { 473 struct vnode *proc_vn; 474 struct vattr vap; 475 int error; 476 477 /* Get the text vnode for the process */ 478 proc_vn = p->p_textvp; 479 if (proc_vn == NULL) 480 return EINVAL; 481 482 /* Get vnode attributes */ 483 error = VOP_GETATTR(proc_vn, &vap, cred); 484 if (error) 485 return error; 486 487 error = mac_veriexec_metadata_get_file_flags(vap.va_fsid, 488 vap.va_fileid, vap.va_gen, flags, 489 (check_files == VERIEXEC_FILES_FIRST)); 490 491 return (error); 492 } 493 494 /** 495 * @brief Ensure the fingerprint status for the vnode @p vp is assigned to its 496 * MAC label. 497 * 498 * @param vp vnode to check 499 * @param vap vnode attributes to use 500 * @param td calling thread 501 * @param check_files if 1, check the files list first, otherwise check the 502 * exectuables list first 503 * 504 * @return 0 on success, otherwise an error code. 505 */ 506 int 507 mac_veriexec_metadata_fetch_fingerprint_status(struct vnode *vp, 508 struct vattr *vap, struct thread *td, int check_files) 509 { 510 unsigned char digest[MAXFINGERPRINTLEN]; 511 struct mac_veriexec_file_info *ip; 512 int error, found_dev; 513 fingerprint_status_t status; 514 515 error = 0; 516 ip = NULL; 517 518 status = mac_veriexec_get_fingerprint_status(vp); 519 if (status == FINGERPRINT_INVALID || status == FINGERPRINT_NODEV) { 520 found_dev = 0; 521 ip = find_veriexec_file(vap->va_fsid, vap->va_fileid, 522 vap->va_gen, &found_dev, check_files); 523 if (ip == NULL) { 524 status = (found_dev) ? FINGERPRINT_NOENTRY : 525 FINGERPRINT_NODEV; 526 VERIEXEC_DEBUG(3, 527 ("fingerprint status is %d for dev %ju, file " 528 "%ju.%lu\n", status, (uintmax_t)vap->va_fsid, 529 (uintmax_t)vap->va_fileid, vap->va_gen)); 530 } else { 531 /* 532 * evaluate and compare fingerprint 533 */ 534 error = mac_veriexec_fingerprint_check_vnode(vp, ip, 535 td, vap->va_size, digest); 536 switch (error) { 537 case 0: 538 /* Process flags */ 539 if ((ip->flags & VERIEXEC_INDIRECT)) 540 status = FINGERPRINT_INDIRECT; 541 else if ((ip->flags & VERIEXEC_FILE)) 542 status = FINGERPRINT_FILE; 543 else 544 status = FINGERPRINT_VALID; 545 VERIEXEC_DEBUG(2, 546 ("%sfingerprint matches for dev %ju, file " 547 "%ju.%lu\n", 548 (status == FINGERPRINT_INDIRECT) ? 549 "indirect " : 550 (status == FINGERPRINT_FILE) ? 551 "file " : "", (uintmax_t)vap->va_fsid, 552 (uintmax_t)vap->va_fileid, vap->va_gen)); 553 break; 554 555 case EAUTH: 556 #ifdef VERIFIED_EXEC_DEBUG_VERBOSE 557 { 558 char have[MAXFINGERPRINTLEN * 2 + 1]; 559 char want[MAXFINGERPRINTLEN * 2 + 1]; 560 int i, len; 561 562 len = ip->ops->digest_len; 563 for (i = 0; i < len; i++) { 564 sprintf(&want[i * 2], "%02x", 565 ip->fingerprint[i]); 566 sprintf(&have[i * 2], "%02x", 567 digest[i]); 568 } 569 log(LOG_ERR, MAC_VERIEXEC_FULLNAME 570 ": fingerprint for dev %ju, file " 571 "%ju.%lu %s != %s\n", 572 (uintmax_t)vap->va_fsid, 573 (uintmax_t)vap->va_fileid, 574 vap->va_gen, 575 have, want); 576 } 577 #endif 578 status = FINGERPRINT_NOMATCH; 579 break; 580 default: 581 VERIEXEC_DEBUG(2, 582 ("fingerprint status error %d\n", error)); 583 break; 584 } 585 } 586 mac_veriexec_set_fingerprint_status(vp, status); 587 } 588 return (error); 589 } 590 591 /** 592 * Add a file and its fingerprint to the list of files attached 593 * to the device @p fsid. 594 * 595 * Only add the entry if it is not already on the list. 596 * 597 * @note Called with @a ve_mutex held 598 * 599 * @param file_dev if 1, the entry should be added on the file list, 600 * otherwise it should be added on the executable list 601 * @param fsid file system identifier of device 602 * @param fileid file to add 603 * @param gen generation of file 604 * @param fingerprint fingerprint to add to the store 605 * @param flags flags to set in the store 606 * @param fp_type digest type 607 * @param override if 1, override any values already stored 608 * 609 * @return 0 on success, otherwise an error code. 610 */ 611 int 612 mac_veriexec_metadata_add_file(int file_dev, dev_t fsid, long fileid, 613 unsigned long gen, unsigned char fingerprint[MAXFINGERPRINTLEN], 614 int flags, const char *fp_type, int override) 615 { 616 struct mac_veriexec_fpops *fpops; 617 struct veriexec_dev_list *lp; 618 struct veriexec_devhead *head; 619 struct mac_veriexec_file_info *ip; 620 struct mac_veriexec_file_info *np = NULL; 621 622 /* Look up the device entry */ 623 if (file_dev) 624 head = &veriexec_file_dev_head; 625 else 626 head = &veriexec_dev_head; 627 lp = find_veriexec_dev(fsid, head); 628 629 /* Look up the fingerprint operations for the digest type */ 630 fpops = mac_veriexec_fingerprint_lookup_ops(fp_type); 631 if (fpops == NULL) 632 return (EOPNOTSUPP); 633 634 search: 635 for (ip = LIST_FIRST(&(lp->file_head)); ip != NULL; 636 ip = LIST_NEXT(ip, entries)) { 637 /* check for a dupe file in the list, skip if an entry 638 * exists for this file except for when the flags contains 639 * VERIEXEC_INDIRECT, always set the flags when it is so 640 * we don't get a hole caused by conflicting flags on 641 * hardlinked files. XXX maybe we should validate 642 * fingerprint is same and complain if it is not... 643 */ 644 if (ip->fileid == fileid && ip->gen == gen) { 645 if (override) { 646 /* 647 * for a signed load we allow overrides, 648 * otherwise fingerpints needed for pkg loads 649 * can fail (the files are on temp device). 650 */ 651 ip->flags = flags; 652 ip->ops = fpops; 653 memcpy(ip->fingerprint, fingerprint, 654 fpops->digest_len); 655 } else if ((flags & (VERIEXEC_INDIRECT|VERIEXEC_FILE))) 656 ip->flags |= flags; 657 658 if (np) { 659 /* unlikely but... we don't need it now. */ 660 mtx_unlock(&ve_mutex); 661 free(np, M_VERIEXEC); 662 mtx_lock(&ve_mutex); 663 } 664 return (0); 665 } 666 } 667 668 /* 669 * We may have been past here before... 670 */ 671 if (np == NULL) { 672 /* 673 * We first try with mutex held and nowait. 674 */ 675 np = malloc(sizeof(struct mac_veriexec_file_info), M_VERIEXEC, 676 M_NOWAIT); 677 if (np == NULL) { 678 /* 679 * It was worth a try, now 680 * drop mutex while we malloc. 681 */ 682 mtx_unlock(&ve_mutex); 683 np = malloc(sizeof(struct mac_veriexec_file_info), 684 M_VERIEXEC, M_WAITOK); 685 mtx_lock(&ve_mutex); 686 /* 687 * We now have to repeat our search! 688 */ 689 goto search; 690 } 691 } 692 693 /* Set up the meta-data entry */ 694 ip = np; 695 ip->flags = flags; 696 ip->ops = fpops; 697 ip->fileid = fileid; 698 ip->gen = gen; 699 memcpy(ip->fingerprint, fingerprint, fpops->digest_len); 700 701 VERIEXEC_DEBUG(3, ("add file %ju.%lu (files=%d)\n", 702 (uintmax_t)ip->fileid, 703 ip->gen, file_dev)); 704 705 /* Add the entry to the list */ 706 LIST_INSERT_HEAD(&(lp->file_head), ip, entries); 707 #ifdef DEBUG_VERIEXEC_FINGERPRINT 708 { 709 off_t offset; 710 711 printf("Stored %s fingerprint:\n", fp_type); 712 for (offset = 0; offset < fpops->digest_len; offset++) 713 printf("%02x", fingerprint[offset]); 714 printf("\n"); 715 } 716 #endif 717 return (0); 718 } 719 720 /** 721 * @brief Intialize the meta-data store 722 */ 723 void 724 mac_veriexec_metadata_init(void) 725 { 726 727 mtx_init(&ve_mutex, "veriexec lock", NULL, MTX_DEF); 728 LIST_INIT(&veriexec_dev_head); 729 LIST_INIT(&veriexec_file_dev_head); 730 } 731