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