1 /* 2 * $FreeBSD$ 3 * 4 * Copyright (c) 2011, 2012, 2013, 2015, 2016, 2019, 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 if (ip->label) 142 free(ip->label, M_VERIEXEC); 143 free(ip, M_VERIEXEC); 144 } 145 } 146 } 147 148 /* Release the lock we obtained earlier */ 149 mtx_unlock(&ve_mutex); 150 151 /* Return the meta-data information we found, if anything */ 152 return (ip); 153 } 154 155 /** 156 * @internal 157 * @brief Display the fingerprint for each entry in the device list 158 * 159 * @param sbp sbuf to write output to 160 * @param lp pointer to device list 161 */ 162 static void 163 mac_veriexec_print_db_dev_list(struct sbuf *sbp, struct veriexec_dev_list *lp) 164 { 165 struct mac_veriexec_file_info *ip; 166 167 #define FPB(i) (ip->fingerprint[i]) 168 for (ip = LIST_FIRST(&(lp->file_head)); ip != NULL; 169 ip = LIST_NEXT(ip, entries)) 170 sbuf_printf(sbp, " %ld: %u %ld [%02x %02x %02x %02x %02x " 171 "%02x %02x %02x...]\n", ip->fileid, ip->flags, ip->gen, 172 FPB(0), FPB(1), FPB(2), FPB(3), FPB(4), FPB(5), FPB(6), 173 FPB(7)); 174 } 175 176 /** 177 * @internal 178 * @brief Display the device list 179 * 180 * @param sbp sbuf to write output to 181 * @param head pointer to head of the device list 182 */ 183 static void 184 mac_veriexec_print_db_head(struct sbuf *sbp, struct veriexec_devhead *head) 185 { 186 struct veriexec_dev_list *lp; 187 188 for (lp = LIST_FIRST(head); lp != NULL; lp = LIST_NEXT(lp, entries)) { 189 sbuf_printf(sbp, " FS id: %ju\n", (uintmax_t)lp->fsid); 190 mac_veriexec_print_db_dev_list(sbp, lp); 191 } 192 193 } 194 195 /** 196 * @internal 197 * @brief Generate human-readable output for the current fingerprint database 198 * 199 * @param sbp sbuf to write output to 200 */ 201 void 202 mac_veriexec_metadata_print_db(struct sbuf *sbp) 203 { 204 struct { 205 struct veriexec_devhead *h; 206 const char *name; 207 } fpdbs[] = { 208 { &veriexec_file_dev_head, "regular files" }, 209 { &veriexec_dev_head, "executable files" }, 210 }; 211 int i; 212 213 mtx_lock(&ve_mutex); 214 for (i = 0; i < sizeof(fpdbs)/sizeof(fpdbs[0]); i++) { 215 sbuf_printf(sbp, "%s fingerprint db:\n", fpdbs[i].name); 216 mac_veriexec_print_db_head(sbp, fpdbs[i].h); 217 } 218 mtx_unlock(&ve_mutex); 219 } 220 /** 221 * @brief Determine if the meta-data store has an entry for the specified file. 222 * 223 * @param fsid file system identifier to look for 224 * @param fileid file to look for 225 * @param gen generation of file 226 * 227 * @return 1 if there is an entry in the meta-data store, 0 otherwise. 228 */ 229 int 230 mac_veriexec_metadata_has_file(dev_t fsid, long fileid, unsigned long gen) 231 { 232 233 return (mac_veriexec_metadata_get_file_info(fsid, fileid, gen, NULL, 234 VERIEXEC_FILES_FIRST) != NULL); 235 } 236 237 /** 238 * @brief Search the list of devices looking for the one given, in order to 239 * release the resources used by it. 240 * 241 * If found, free all file entries for it, and remove it from the list. 242 * 243 * @note Called with @a ve_mutex held 244 * 245 * @param fsid file system identifier to look for 246 * @param head meta-data list to search 247 * 248 * @return 0 if the device entry was freed, otherwise an error code 249 */ 250 static int 251 free_veriexec_dev(dev_t fsid, struct veriexec_devhead *head) 252 { 253 struct veriexec_dev_list *lp; 254 struct mac_veriexec_file_info *ip, *nip; 255 256 /* Look for the file system */ 257 for (lp = LIST_FIRST(head); lp != NULL; 258 lp = LIST_NEXT(lp, entries)) 259 if (lp->fsid == fsid) break; 260 261 /* If lp is NULL, we did not find it */ 262 if (lp == NULL) 263 return ENOENT; 264 265 /* Unhook lp, before we free it and its content */ 266 LIST_REMOVE(lp, entries); 267 268 /* Release the lock */ 269 mtx_unlock(&ve_mutex); 270 271 /* Free the file entries in the list */ 272 for (ip = LIST_FIRST(&(lp->file_head)); ip != NULL; ip = nip) { 273 nip = LIST_NEXT(ip, entries); 274 LIST_REMOVE(ip, entries); 275 if (ip->label) 276 free(ip->label, M_VERIEXEC); 277 free(ip, M_VERIEXEC); 278 } 279 280 /* Free the meta-data entry for the device */ 281 free(lp, M_VERIEXEC); 282 283 /* Re-acquire the lock */ 284 mtx_lock(&ve_mutex); 285 return 0; 286 } 287 288 /** 289 * @brief Search the list of devices looking for the one given. 290 * 291 * If it is not in the list then add it. 292 * 293 * @note Called with @a ve_mutex held 294 * 295 * @param fsid file system identifier to look for 296 * @param head meta-data list to search 297 * 298 * @return A pointer to the meta-data entry for the device, if found or added, 299 * otherwise @c NULL 300 */ 301 static struct veriexec_dev_list * 302 find_veriexec_dev(dev_t fsid, struct veriexec_devhead *head) 303 { 304 struct veriexec_dev_list *lp; 305 struct veriexec_dev_list *np = NULL; 306 307 search: 308 /* Look for the file system */ 309 for (lp = LIST_FIRST(head); lp != NULL; 310 lp = LIST_NEXT(lp, entries)) 311 if (lp->fsid == fsid) break; 312 313 if (lp == NULL) { 314 if (np == NULL) { 315 /* 316 * If pointer is null then entry not there, 317 * add a new one, first try to malloc while 318 * we hold mutex - should work most of the time. 319 */ 320 np = malloc(sizeof(struct veriexec_dev_list), 321 M_VERIEXEC, M_NOWAIT); 322 if (np == NULL) { 323 /* 324 * So much for that plan, dop the mutex 325 * and repeat... 326 */ 327 mtx_unlock(&ve_mutex); 328 np = malloc(sizeof(struct veriexec_dev_list), 329 M_VERIEXEC, M_WAITOK); 330 mtx_lock(&ve_mutex); 331 /* 332 * Repeat the seach, in case someone 333 * added this while we slept. 334 */ 335 goto search; 336 } 337 } 338 if (np) { 339 /* Add the entry to the list */ 340 lp = np; 341 LIST_INIT(&(lp->file_head)); 342 lp->fsid = fsid; 343 LIST_INSERT_HEAD(head, lp, entries); 344 } 345 } else if (np) { 346 /* 347 * Someone else did it while we slept. 348 */ 349 mtx_unlock(&ve_mutex); 350 free(np, M_VERIEXEC); 351 mtx_lock(&ve_mutex); 352 } 353 354 return (lp); 355 } 356 357 /** 358 * @internal 359 * @brief Allocate and initialize label record with the provided data. 360 * 361 * @param labelp Location to store the initialized label 362 * @param src Pointer to label string to copy 363 * @param srclen Length of label string to copy 364 * 365 * @return Length of resulting label 366 * 367 * @note Called with ve_mutex locked. 368 */ 369 static size_t 370 mac_veriexec_init_label(char **labelp, size_t labellen, char *src, 371 size_t srclen) 372 { 373 char *label; 374 375 label = *labelp; 376 if (labellen < srclen) { 377 mtx_unlock(&ve_mutex); 378 if (label != NULL) 379 free(label, M_VERIEXEC); 380 label = malloc(srclen, M_VERIEXEC, M_WAITOK); 381 mtx_lock(&ve_mutex); 382 labellen = srclen; 383 *labelp = label; 384 } 385 memcpy(label, src, srclen); 386 return labellen; 387 } 388 389 /** 390 * @brief When a device is unmounted, we want to toss the signatures recorded 391 * against it. 392 * 393 * We are being called from unmount() with the root vnode just before it is 394 * freed. 395 * 396 * @param fsid file system identifier to look for 397 * @param td calling thread 398 * 399 * @return 0 on success, otherwise an error code. 400 */ 401 int 402 mac_veriexec_metadata_unmounted(dev_t fsid, struct thread *td) 403 { 404 int error; 405 406 /* 407 * The device can have entries on both lists. 408 */ 409 mtx_lock(&ve_mutex); 410 error = free_veriexec_dev(fsid, &veriexec_dev_head); 411 if (error && error != ENOENT) { 412 mtx_unlock(&ve_mutex); 413 return error; 414 } 415 error = free_veriexec_dev(fsid, &veriexec_file_dev_head); 416 mtx_unlock(&ve_mutex); 417 if (error && error != ENOENT) { 418 return error; 419 } 420 return 0; 421 } 422 423 /** 424 * @brief Return the flags assigned to the file identified by file system 425 * identifier @p fsid and file identifier @p fileid. 426 * 427 * @param fsid file system identifier 428 * @param fileid file identifier within the file system 429 * @param gen generation of file 430 * @param flags pointer to location to store the flags 431 * @param check_files if 1, check the files list first, otherwise check the 432 * exectuables list first 433 * 434 * @return 0 on success, otherwise an error code. 435 */ 436 int 437 mac_veriexec_metadata_get_file_flags(dev_t fsid, long fileid, unsigned long gen, 438 int *flags, int check_files) 439 { 440 struct mac_veriexec_file_info *ip; 441 int found_dev; 442 443 ip = mac_veriexec_metadata_get_file_info(fsid, fileid, gen, &found_dev, 444 check_files); 445 if (ip == NULL) 446 return (ENOENT); 447 448 *flags = ip->flags; 449 return (0); 450 } 451 452 /** 453 * @brief get the files for the specified process 454 * 455 * @param cred credentials to use 456 * @param p process to get the flags for 457 * @param flags where to store the flags 458 * @param check_files if 1, check the files list first, otherwise check the 459 * exectuables list first 460 * 461 * @return 0 if the process has an entry in the meta-data store, otherwise an 462 * error code 463 */ 464 int 465 mac_veriexec_metadata_get_executable_flags(struct ucred *cred, struct proc *p, 466 int *flags, int check_files) 467 { 468 struct vnode *proc_vn; 469 struct vattr vap; 470 int error; 471 472 /* Get the text vnode for the process */ 473 proc_vn = p->p_textvp; 474 if (proc_vn == NULL) 475 return EINVAL; 476 477 /* Get vnode attributes */ 478 error = VOP_GETATTR(proc_vn, &vap, cred); 479 if (error) 480 return error; 481 482 error = mac_veriexec_metadata_get_file_flags(vap.va_fsid, 483 vap.va_fileid, vap.va_gen, flags, 484 (check_files == VERIEXEC_FILES_FIRST)); 485 486 return (error); 487 } 488 489 /** 490 * @brief Ensure the fingerprint status for the vnode @p vp is assigned to its 491 * MAC label. 492 * 493 * @param vp vnode to check 494 * @param vap vnode attributes to use 495 * @param td calling thread 496 * @param check_files if 1, check the files list first, otherwise check the 497 * exectuables list first 498 * 499 * @return 0 on success, otherwise an error code. 500 */ 501 int 502 mac_veriexec_metadata_fetch_fingerprint_status(struct vnode *vp, 503 struct vattr *vap, struct thread *td, int check_files) 504 { 505 unsigned char digest[MAXFINGERPRINTLEN]; 506 struct mac_veriexec_file_info *ip; 507 int error, found_dev; 508 fingerprint_status_t status; 509 510 error = 0; 511 ip = NULL; 512 513 status = mac_veriexec_get_fingerprint_status(vp); 514 if (status == FINGERPRINT_INVALID || status == FINGERPRINT_NODEV) { 515 found_dev = 0; 516 ip = mac_veriexec_metadata_get_file_info(vap->va_fsid, 517 vap->va_fileid, vap->va_gen, &found_dev, check_files); 518 if (ip == NULL) { 519 status = (found_dev) ? FINGERPRINT_NOENTRY : 520 FINGERPRINT_NODEV; 521 VERIEXEC_DEBUG(3, 522 ("fingerprint status is %d for dev %ju, file " 523 "%ju.%lu\n", status, (uintmax_t)vap->va_fsid, 524 (uintmax_t)vap->va_fileid, vap->va_gen)); 525 } else { 526 /* 527 * evaluate and compare fingerprint 528 */ 529 error = mac_veriexec_fingerprint_check_vnode(vp, ip, 530 td, vap->va_size, digest); 531 switch (error) { 532 case 0: 533 /* Process flags */ 534 if ((ip->flags & VERIEXEC_INDIRECT)) 535 status = FINGERPRINT_INDIRECT; 536 else if ((ip->flags & VERIEXEC_FILE)) 537 status = FINGERPRINT_FILE; 538 else 539 status = FINGERPRINT_VALID; 540 VERIEXEC_DEBUG(2, 541 ("%sfingerprint matches for dev %ju, file " 542 "%ju.%lu\n", 543 (status == FINGERPRINT_INDIRECT) ? 544 "indirect " : 545 (status == FINGERPRINT_FILE) ? 546 "file " : "", (uintmax_t)vap->va_fsid, 547 (uintmax_t)vap->va_fileid, vap->va_gen)); 548 break; 549 550 case EAUTH: 551 #ifdef VERIFIED_EXEC_DEBUG_VERBOSE 552 { 553 char have[MAXFINGERPRINTLEN * 2 + 1]; 554 char want[MAXFINGERPRINTLEN * 2 + 1]; 555 int i, len; 556 557 len = ip->ops->digest_len; 558 for (i = 0; i < len; i++) { 559 sprintf(&want[i * 2], "%02x", 560 ip->fingerprint[i]); 561 sprintf(&have[i * 2], "%02x", 562 digest[i]); 563 } 564 log(LOG_ERR, MAC_VERIEXEC_FULLNAME 565 ": fingerprint for dev %ju, file " 566 "%ju.%lu %s != %s\n", 567 (uintmax_t)vap->va_fsid, 568 (uintmax_t)vap->va_fileid, 569 vap->va_gen, 570 have, want); 571 } 572 #endif 573 status = FINGERPRINT_NOMATCH; 574 break; 575 default: 576 VERIEXEC_DEBUG(2, 577 ("fingerprint status error %d\n", error)); 578 break; 579 } 580 } 581 mac_veriexec_set_fingerprint_status(vp, status); 582 } 583 return (error); 584 } 585 586 /** 587 * Add a file and its fingerprint to the list of files attached 588 * to the device @p fsid. 589 * 590 * Only add the entry if it is not already on the list. 591 * 592 * @note Called with @a ve_mutex held 593 * 594 * @param file_dev if 1, the entry should be added on the file list, 595 * otherwise it should be added on the executable list 596 * @param fsid file system identifier of device 597 * @param fileid file to add 598 * @param gen generation of file 599 * @param fingerprint fingerprint to add to the store 600 * @param flags flags to set in the store 601 * @param fp_type digest type 602 * @param override if 1, override any values already stored 603 * 604 * @return 0 on success, otherwise an error code. 605 */ 606 int 607 mac_veriexec_metadata_add_file(int file_dev, dev_t fsid, long fileid, 608 unsigned long gen, unsigned char fingerprint[MAXFINGERPRINTLEN], 609 char *label, size_t labellen, int flags, const char *fp_type, int override) 610 { 611 struct mac_veriexec_fpops *fpops; 612 struct veriexec_dev_list *lp; 613 struct veriexec_devhead *head; 614 struct mac_veriexec_file_info *ip; 615 struct mac_veriexec_file_info *np = NULL; 616 617 /* Label and labellen must be set if VERIEXEC_LABEL is set */ 618 if ((flags & VERIEXEC_LABEL) != 0 && (label == NULL || labellen == 0)) 619 return (EINVAL); 620 621 /* Look up the device entry */ 622 if (file_dev) 623 head = &veriexec_file_dev_head; 624 else 625 head = &veriexec_dev_head; 626 lp = find_veriexec_dev(fsid, head); 627 628 /* Look up the fingerprint operations for the digest type */ 629 fpops = mac_veriexec_fingerprint_lookup_ops(fp_type); 630 if (fpops == NULL) 631 return (EOPNOTSUPP); 632 633 search: 634 for (ip = LIST_FIRST(&(lp->file_head)); ip != NULL; 635 ip = LIST_NEXT(ip, entries)) { 636 /* check for a dupe file in the list, skip if an entry 637 * exists for this file except for when the flags contains 638 * VERIEXEC_INDIRECT, always set the flags when it is so 639 * we don't get a hole caused by conflicting flags on 640 * hardlinked files. XXX maybe we should validate 641 * fingerprint is same and complain if it is not... 642 */ 643 if (ip->fileid == fileid && ip->gen == gen) { 644 if (override) { 645 /* 646 * for a signed load we allow overrides, 647 * otherwise fingerpints needed for pkg loads 648 * can fail (the files are on temp device). 649 */ 650 ip->flags = flags; 651 ip->ops = fpops; 652 memcpy(ip->fingerprint, fingerprint, 653 fpops->digest_len); 654 if (flags & VERIEXEC_LABEL) { 655 ip->labellen = mac_veriexec_init_label( 656 &ip->label, ip->labellen, label, 657 labellen); 658 } else if (ip->labellen > 0) { 659 free(ip->label, M_VERIEXEC); 660 ip->labellen = 0; 661 ip->label = NULL; 662 } 663 } else if ((flags & (VERIEXEC_INDIRECT|VERIEXEC_FILE))) 664 ip->flags |= flags; 665 666 if (np) { 667 /* unlikely but... we don't need it now. */ 668 mtx_unlock(&ve_mutex); 669 free(np, M_VERIEXEC); 670 mtx_lock(&ve_mutex); 671 } 672 return (0); 673 } 674 } 675 676 /* 677 * We may have been past here before... 678 */ 679 if (np == NULL) { 680 /* 681 * We first try with mutex held and nowait. 682 */ 683 np = malloc(sizeof(struct mac_veriexec_file_info), M_VERIEXEC, 684 M_NOWAIT); 685 if (np == NULL) { 686 /* 687 * It was worth a try, now 688 * drop mutex while we malloc. 689 */ 690 mtx_unlock(&ve_mutex); 691 np = malloc(sizeof(struct mac_veriexec_file_info), 692 M_VERIEXEC, M_WAITOK); 693 mtx_lock(&ve_mutex); 694 /* 695 * We now have to repeat our search! 696 */ 697 goto search; 698 } 699 } 700 701 /* Set up the meta-data entry */ 702 ip = np; 703 ip->flags = flags; 704 ip->ops = fpops; 705 ip->fileid = fileid; 706 ip->gen = gen; 707 memcpy(ip->fingerprint, fingerprint, fpops->digest_len); 708 if (flags & VERIEXEC_LABEL) 709 ip->labellen = mac_veriexec_init_label(&ip->label, 710 ip->labellen, label, labellen); 711 else { 712 ip->label = NULL; 713 ip->labellen = 0; 714 } 715 716 VERIEXEC_DEBUG(3, ("add file %ju.%lu (files=%d)\n", 717 (uintmax_t)ip->fileid, 718 ip->gen, file_dev)); 719 720 /* Add the entry to the list */ 721 LIST_INSERT_HEAD(&(lp->file_head), ip, entries); 722 #ifdef DEBUG_VERIEXEC_FINGERPRINT 723 { 724 off_t offset; 725 726 printf("Stored %s fingerprint:\n", fp_type); 727 for (offset = 0; offset < fpops->digest_len; offset++) 728 printf("%02x", fingerprint[offset]); 729 printf("\n"); 730 } 731 #endif 732 return (0); 733 } 734 735 /** 736 * @brief Search the meta-data store for information on the specified file. 737 * 738 * @param fsid file system identifier to look for 739 * @param fileid file to look for 740 * @param gen generation of file 741 * @param found_dev indicator that an entry for the file system was found 742 * @param check_files if 1, check the files list first, otherwise check the 743 * exectuables list first 744 * 745 * @return A pointer to the meta-data inforation if meta-data exists for 746 * the specified file identifier, otherwise @c NULL 747 */ 748 struct mac_veriexec_file_info * 749 mac_veriexec_metadata_get_file_info(dev_t fsid, long fileid, unsigned long gen, 750 int *found_dev, int check_files) 751 { 752 struct veriexec_devhead *search[3]; 753 struct mac_veriexec_file_info *ip; 754 int x; 755 756 /* Determine the order of the lists to search */ 757 if (check_files) { 758 search[0] = &veriexec_file_dev_head; 759 search[1] = &veriexec_dev_head; 760 } else { 761 search[0] = &veriexec_dev_head; 762 search[1] = &veriexec_file_dev_head; 763 } 764 search[2] = NULL; 765 766 VERIEXEC_DEBUG(3, ("%s: searching for dev %ju, file %lu\n", 767 __func__, (uintmax_t)fsid, fileid)); 768 769 /* Search for the specified file */ 770 for (ip = NULL, x = 0; ip == NULL && search[x]; x++) 771 ip = get_veriexec_file(search[x], fsid, fileid, gen, found_dev); 772 773 return (ip); 774 } 775 776 777 /** 778 * @brief Intialize the meta-data store 779 */ 780 void 781 mac_veriexec_metadata_init(void) 782 { 783 784 mtx_init(&ve_mutex, "veriexec lock", NULL, MTX_DEF); 785 LIST_INIT(&veriexec_dev_head); 786 LIST_INIT(&veriexec_file_dev_head); 787 } 788