1 /* 2 * $FreeBSD$ 3 * 4 * Copyright (c) 2011, 2012, 2013, 2015, 2016, Juniper Networks, Inc. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 31 #include "opt_capsicum.h" 32 #include "opt_mac.h" 33 34 #include <sys/param.h> 35 #include <sys/systm.h> 36 #include <sys/capsicum.h> 37 #include <sys/eventhandler.h> 38 #include <sys/fcntl.h> 39 #include <sys/file.h> 40 #include <sys/filedesc.h> 41 #include <sys/imgact.h> 42 #include <sys/jail.h> 43 #include <sys/kernel.h> 44 #include <sys/mac.h> 45 #include <sys/mount.h> 46 #include <sys/namei.h> 47 #include <sys/priv.h> 48 #include <sys/proc.h> 49 #include <sys/sbuf.h> 50 #include <sys/stat.h> 51 #include <sys/sysctl.h> 52 #include <sys/vnode.h> 53 #include <fs/nullfs/null.h> 54 #include <security/mac/mac_policy.h> 55 56 #include "mac_veriexec.h" 57 #include "mac_veriexec_internal.h" 58 59 #define SLOT(l) \ 60 mac_label_get((l), mac_veriexec_slot) 61 #define SLOT_SET(l, v) \ 62 mac_label_set((l), mac_veriexec_slot, (v)) 63 64 #ifdef MAC_DEBUG 65 #define MAC_VERIEXEC_DBG(_lvl, _fmt, ...) \ 66 do { \ 67 VERIEXEC_DEBUG((_lvl), (MAC_VERIEXEC_FULLNAME ": " _fmt \ 68 "\n", ##__VA_ARGS__)); \ 69 } while(0) 70 #else 71 #define MAC_VERIEXEC_DBG(_lvl, _fmt, ...) 72 #endif 73 74 static int sysctl_mac_veriexec_state(SYSCTL_HANDLER_ARGS); 75 static int sysctl_mac_veriexec_db(SYSCTL_HANDLER_ARGS); 76 77 SYSCTL_DECL(_security_mac); 78 79 SYSCTL_NODE(_security_mac, OID_AUTO, veriexec, CTLFLAG_RW, 0, 80 "MAC/veriexec policy controls"); 81 82 int mac_veriexec_debug; 83 SYSCTL_INT(_security_mac_veriexec, OID_AUTO, debug, CTLFLAG_RW, 84 &mac_veriexec_debug, 0, "Debug level"); 85 86 static int mac_veriexec_state; 87 SYSCTL_PROC(_security_mac_veriexec, OID_AUTO, state, 88 CTLTYPE_STRING | CTLFLAG_RD, 0, 0, sysctl_mac_veriexec_state, "A", 89 "Verified execution subsystem state"); 90 91 SYSCTL_PROC(_security_mac_veriexec, OID_AUTO, db, 92 CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_SKIP, 0, 0, sysctl_mac_veriexec_db, 93 "A", "Verified execution fingerprint database"); 94 95 static int mac_veriexec_slot; 96 97 MALLOC_DEFINE(M_VERIEXEC, "veriexec", "Verified execution data"); 98 99 /** 100 * @internal 101 * @brief Handler for security.mac.veriexec.db sysctl 102 * 103 * Display a human-readable form of the current fingerprint database. 104 */ 105 static int 106 sysctl_mac_veriexec_db(SYSCTL_HANDLER_ARGS) 107 { 108 struct sbuf sb; 109 int error; 110 111 error = sysctl_wire_old_buffer(req, 0); 112 if (error != 0) 113 return (error); 114 115 sbuf_new_for_sysctl(&sb, NULL, 1024, req); 116 mac_veriexec_print_db(&sb); 117 error = sbuf_finish(&sb); 118 sbuf_delete(&sb); 119 120 return (error); 121 } 122 123 /** 124 * @internal 125 * @brief Generate human-readable output about the current verified execution 126 * state. 127 * 128 * @param sbp sbuf to write output to 129 */ 130 static void 131 mac_veriexec_print_state(struct sbuf *sbp) 132 { 133 134 if (mac_veriexec_state & VERIEXEC_STATE_INACTIVE) 135 sbuf_printf(sbp, "inactive "); 136 if (mac_veriexec_state & VERIEXEC_STATE_LOADED) 137 sbuf_printf(sbp, "loaded "); 138 if (mac_veriexec_state & VERIEXEC_STATE_ACTIVE) 139 sbuf_printf(sbp, "active "); 140 if (mac_veriexec_state & VERIEXEC_STATE_ENFORCE) 141 sbuf_printf(sbp, "enforce "); 142 if (mac_veriexec_state & VERIEXEC_STATE_LOCKED) 143 sbuf_printf(sbp, "locked "); 144 if (mac_veriexec_state != 0) 145 sbuf_trim(sbp); 146 } 147 148 /** 149 * @internal 150 * @brief Handler for security.mac.veriexec.state sysctl 151 * 152 * Display a human-readable form of the current verified execution subsystem 153 * state. 154 */ 155 static int 156 sysctl_mac_veriexec_state(SYSCTL_HANDLER_ARGS) 157 { 158 struct sbuf sb; 159 int error; 160 161 sbuf_new(&sb, NULL, 128, SBUF_AUTOEXTEND); 162 mac_veriexec_print_state(&sb); 163 sbuf_finish(&sb); 164 165 error = SYSCTL_OUT(req, sbuf_data(&sb), sbuf_len(&sb)); 166 sbuf_delete(&sb); 167 return (error); 168 } 169 170 /** 171 * @internal 172 * @brief Event handler called when a virtual file system is mounted. 173 * 174 * We need to record the file system identifier in the MAC per-policy slot 175 * assigned to veriexec, so we have a key to use in order to reference the 176 * mount point in the meta-data store. 177 * 178 * @param arg unused argument 179 * @param mp mount point that is being mounted 180 * @param fsrootvp vnode of the file system root 181 * @param td calling thread 182 */ 183 static void 184 mac_veriexec_vfs_mounted(void *arg __unused, struct mount *mp, 185 struct vnode *fsrootvp, struct thread *td) 186 { 187 struct vattr va; 188 int error; 189 190 error = VOP_GETATTR(fsrootvp, &va, td->td_ucred); 191 if (error) 192 return; 193 194 SLOT_SET(mp->mnt_label, va.va_fsid); 195 #ifdef MAC_DEBUG 196 MAC_VERIEXEC_DBG(3, "set fsid to %u for mount %p", va.va_fsid, mp); 197 #endif 198 } 199 200 /** 201 * @internal 202 * @brief Event handler called when a virtual file system is unmounted. 203 * 204 * If we recorded a file system identifier in the MAC per-policy slot assigned 205 * to veriexec, then we need to tell the meta-data store to clean up. 206 * 207 * @param arg unused argument 208 * @param mp mount point that is being unmounted 209 * @param td calling thread 210 */ 211 static void 212 mac_veriexec_vfs_unmounted(void *arg __unused, struct mount *mp, 213 struct thread *td) 214 { 215 dev_t fsid; 216 217 fsid = SLOT(mp->mnt_label); 218 if (fsid) { 219 MAC_VERIEXEC_DBG(3, "fsid %u, cleaning up mount", fsid); 220 mac_veriexec_metadata_unmounted(fsid, td); 221 } 222 } 223 224 /** 225 * @internal 226 * @brief The mount point is being initialized, set the value in the MAC 227 * per-policy slot for veriexec to zero. 228 * 229 * @note A value of zero in this slot indicates no file system identifier 230 * is assigned. 231 * 232 * @param label the label that is being initialized 233 */ 234 static void 235 mac_veriexec_mount_init_label(struct label *label) 236 { 237 238 SLOT_SET(label, 0); 239 } 240 241 /** 242 * @internal 243 * @brief The mount-point is being destroyed, reset the value in the MAC 244 * per-policy slot for veriexec back to zero. 245 * 246 * @note A value of zero in this slot indicates no file system identifier 247 * is assigned. 248 * 249 * @param label the label that is being destroyed 250 */ 251 static void 252 mac_veriexec_mount_destroy_label(struct label *label) 253 { 254 255 SLOT_SET(label, 0); 256 } 257 258 /** 259 * @internal 260 * @brief The vnode label is being initialized, set the value in the MAC 261 * per-policy slot for veriexec to @c FINGERPRINT_INVALID 262 * 263 * @note @c FINGERPRINT_INVALID indicates the fingerprint is invalid. 264 * 265 * @param label the label that is being initialized 266 */ 267 static void 268 mac_veriexec_vnode_init_label(struct label *label) 269 { 270 271 SLOT_SET(label, FINGERPRINT_INVALID); 272 } 273 274 /** 275 * @internal 276 * @brief The vnode label is being destroyed, reset the value in the MAC 277 * per-policy slot for veriexec back to @c FINGERPRINT_INVALID 278 * 279 * @note @c FINGERPRINT_INVALID indicates the fingerprint is invalid. 280 * 281 * @param label the label that is being destroyed 282 */ 283 static void 284 mac_veriexec_vnode_destroy_label(struct label *label) 285 { 286 287 SLOT_SET(label, FINGERPRINT_INVALID); 288 } 289 290 /** 291 * @internal 292 * @brief Copy the value in the MAC per-policy slot assigned to veriexec from 293 * the @p src label to the @p dest label 294 */ 295 static void 296 mac_veriexec_copy_label(struct label *src, struct label *dest) 297 { 298 299 SLOT_SET(dest, SLOT(src)); 300 } 301 302 /** 303 * @internal 304 * @brief Check if the requested process can be debugged 305 * 306 * @param cred credentials to use 307 * @param p process to debug 308 * 309 * @return 0 if debugging is allowed, otherwise an error code. 310 */ 311 static int 312 mac_veriexec_proc_check_debug(struct ucred *cred, struct proc *p) 313 { 314 int error, flags; 315 316 /* If we are not enforcing veriexec, nothing for us to check */ 317 if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0) 318 return (0); 319 320 error = mac_veriexec_metadata_get_executable_flags(cred, p, &flags, 0); 321 if (error != 0) 322 return (0); 323 324 return ((flags & VERIEXEC_NOTRACE) ? EACCES : 0); 325 } 326 327 /** 328 * @internal 329 * @brief A KLD load has been requested and needs to be validated. 330 * 331 * @param cred credentials to use 332 * @param vp vnode of the KLD that has been requested 333 * @param vlabel vnode label assigned to the vnode 334 * 335 * @return 0 if the KLD load is allowed, otherwise an error code. 336 */ 337 static int 338 mac_veriexec_kld_check_load(struct ucred *cred, struct vnode *vp, 339 struct label *vlabel) 340 { 341 struct vattr va; 342 struct thread *td = curthread; 343 fingerprint_status_t status; 344 int error; 345 346 /* 347 * If we are not actively enforcing, allow it 348 */ 349 if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0) 350 return (0); 351 352 /* Get vnode attributes */ 353 error = VOP_GETATTR(vp, &va, cred); 354 if (error) 355 return (error); 356 357 /* 358 * Fetch the fingerprint status for the vnode 359 * (starting with files first) 360 */ 361 error = mac_veriexec_metadata_fetch_fingerprint_status(vp, &va, td, 362 VERIEXEC_FILES_FIRST); 363 if (error && error != EAUTH) 364 return (error); 365 366 /* 367 * By now we should have status... 368 */ 369 status = mac_veriexec_get_fingerprint_status(vp); 370 switch (status) { 371 case FINGERPRINT_FILE: 372 case FINGERPRINT_VALID: 373 case FINGERPRINT_INDIRECT: 374 if (error) 375 return (error); 376 break; 377 default: 378 /* 379 * kldload should fail unless there is a valid fingerprint 380 * registered. 381 */ 382 MAC_VERIEXEC_DBG(2, "fingerprint status is %d for dev %u, " 383 "file %lu.%lu\n", status, va.va_fsid, va.va_fileid, 384 va.va_gen); 385 return (EAUTH); 386 } 387 388 /* Everything is good, allow the KLD to be loaded */ 389 return (0); 390 } 391 392 /** 393 * @internal 394 * @brief Check privileges that veriexec needs to be concerned about. 395 * 396 * The following privileges are checked by this function: 397 * - PRIV_KMEM_WRITE\n 398 * Check if writes to /dev/mem and /dev/kmem are allowed\n 399 * (Only trusted processes are allowed) 400 * 401 * @param cred credentials to use 402 * @param priv privilege to check 403 * 404 * @return 0 if the privilege is allowed, error code otherwise. 405 */ 406 static int 407 mac_veriexec_priv_check(struct ucred *cred, int priv) 408 { 409 410 /* If we are not enforcing veriexec, nothing for us to check */ 411 if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0) 412 return (0); 413 414 switch (priv) { 415 case PRIV_KMEM_WRITE: 416 if (!mac_veriexec_proc_is_trusted(cred, curproc)) 417 return (EPERM); 418 break; 419 default: 420 break; 421 } 422 return (0); 423 } 424 425 /** 426 * @internal 427 * @brief A program is being executed and needs to be validated. 428 * 429 * @param cred credentials to use 430 * @param vp vnode of the program that is being executed 431 * @param label vnode label assigned to the vnode 432 * @param imgp parameters for the image to be executed 433 * @param execlabel optional exec label 434 * 435 * @return 0 if the program should be allowed to execute, otherwise an error 436 * code. 437 */ 438 static int 439 mac_veriexec_vnode_check_exec(struct ucred *cred __unused, 440 struct vnode *vp __unused, struct label *label __unused, 441 struct image_params *imgp, struct label *execlabel __unused) 442 { 443 struct thread *td = curthread; 444 int error; 445 446 error = mac_veriexec_fingerprint_check_image(imgp, 0, td); 447 return (error); 448 } 449 450 /** 451 * @brief Check fingerprint for the specified vnode and validate it 452 * 453 * @param cred credentials to use 454 * @param vp vnode of the file 455 * @param accmode access mode to check (read, write, append, create, 456 * verify, etc.) 457 * 458 * @return 0 if the file validated, otherwise an error code. 459 */ 460 static int 461 mac_veriexec_check_vp(struct ucred *cred, struct vnode *vp, accmode_t accmode) 462 { 463 struct vattr va; 464 struct thread *td = curthread; 465 fingerprint_status_t status; 466 int error; 467 468 /* Get vnode attributes */ 469 error = VOP_GETATTR(vp, &va, cred); 470 if (error) 471 return (error); 472 473 /* Get the fingerprint status for the file */ 474 error = mac_veriexec_metadata_fetch_fingerprint_status(vp, &va, td, 475 VERIEXEC_FILES_FIRST); 476 if (error && error != EAUTH) 477 return (error); 478 479 /* 480 * By now we should have status... 481 */ 482 status = mac_veriexec_get_fingerprint_status(vp); 483 if (accmode & VWRITE) { 484 /* 485 * If file has a fingerprint then deny the write request, 486 * otherwise invalidate the status so we don't keep checking 487 * for the file having a fingerprint. 488 */ 489 switch (status) { 490 case FINGERPRINT_FILE: 491 case FINGERPRINT_VALID: 492 case FINGERPRINT_INDIRECT: 493 MAC_VERIEXEC_DBG(2, 494 "attempted write to fingerprinted file for dev " 495 "%u, file %lu.%lu\n", va.va_fsid, 496 va.va_fileid, va.va_gen); 497 return (EPERM); 498 default: 499 break; 500 } 501 } 502 if (accmode & VVERIFY) { 503 switch (status) { 504 case FINGERPRINT_FILE: 505 case FINGERPRINT_VALID: 506 case FINGERPRINT_INDIRECT: 507 if (error) 508 return (error); 509 break; 510 default: 511 /* 512 * Caller wants open to fail unless there is a valid 513 * fingerprint registered. 514 */ 515 MAC_VERIEXEC_DBG(2, "fingerprint status is %d for dev " 516 "%u, file %lu.%lu\n", status, va.va_fsid, 517 va.va_fileid, va.va_gen); 518 return (EAUTH); 519 } 520 } 521 return (0); 522 } 523 524 /** 525 * @brief Opening a file has been requested and may need to be validated. 526 * 527 * @param cred credentials to use 528 * @param vp vnode of the file to open 529 * @param label vnode label assigned to the vnode 530 * @param accmode access mode to use for opening the file (read, write, 531 * append, create, verify, etc.) 532 * 533 * @return 0 if opening the file should be allowed, otherwise an error code. 534 */ 535 static int 536 mac_veriexec_vnode_check_open(struct ucred *cred, struct vnode *vp, 537 struct label *label __unused, accmode_t accmode) 538 { 539 int error; 540 541 /* 542 * Look for the file on the fingerprint lists iff it has not been seen 543 * before. 544 */ 545 if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0) 546 return (0); 547 548 error = mac_veriexec_check_vp(cred, vp, accmode); 549 return (error); 550 } 551 552 /** 553 * @internal 554 * @brief Initialize the mac_veriexec MAC policy 555 * 556 * @param mpc MAC policy configuration 557 */ 558 static void 559 mac_veriexec_init(struct mac_policy_conf *mpc __unused) 560 { 561 /* Initialize state */ 562 mac_veriexec_state = VERIEXEC_STATE_INACTIVE; 563 564 /* Initialize meta-data storage */ 565 mac_veriexec_metadata_init(); 566 567 /* Initialize fingerprint ops */ 568 mac_veriexec_fingerprint_init(); 569 570 /* Register event handlers */ 571 EVENTHANDLER_REGISTER(vfs_mounted, mac_veriexec_vfs_mounted, NULL, 572 EVENTHANDLER_PRI_FIRST); 573 EVENTHANDLER_REGISTER(vfs_unmounted, mac_veriexec_vfs_unmounted, NULL, 574 EVENTHANDLER_PRI_LAST); 575 } 576 577 /** 578 * @internal 579 * @brief MAC policy-specific syscall for mac_veriexec 580 * 581 * The following syscalls are implemented: 582 * - @c MAC_VERIEXEC_CHECK_SYSCALL 583 * Check if the file referenced by a file descriptor has a fingerprint 584 * registered in the meta-data store. 585 * 586 * @param td calling thread 587 * @param call system call number 588 * @param arg arugments to the syscall 589 * 590 * @return 0 on success, otherwise an error code. 591 */ 592 static int 593 mac_veriexec_syscall(struct thread *td, int call, void *arg) 594 { 595 struct image_params img; 596 struct nameidata nd; 597 cap_rights_t rights; 598 struct vattr va; 599 struct file *fp; 600 int error; 601 602 switch (call) { 603 case MAC_VERIEXEC_CHECK_FD_SYSCALL: 604 /* Get the vnode associated with the file descriptor passed */ 605 error = getvnode(td, (uintptr_t) arg, cap_rights_init(&rights, 606 CAP_READ), &fp); 607 if (error) 608 return (error); 609 if (fp->f_type != DTYPE_VNODE) { 610 MAC_VERIEXEC_DBG(3, "MAC_VERIEXEC_CHECK_SYSCALL: " 611 "file is not vnode type (type=0x%x)", 612 fp->f_type); 613 error = EINVAL; 614 goto cleanup_file; 615 } 616 617 /* 618 * setup the bits of image_params that are used by 619 * mac_veriexec_check_fingerprint(). 620 */ 621 bzero(&img, sizeof(img)); 622 img.proc = td->td_proc; 623 img.vp = fp->f_vnode; 624 img.attr = &va; 625 626 /* 627 * Get vnode attributes 628 * (need to obtain a lock on the vnode first) 629 */ 630 vn_lock(img.vp, LK_EXCLUSIVE | LK_RETRY); 631 error = VOP_GETATTR(fp->f_vnode, &va, td->td_ucred); 632 if (error) 633 goto check_done; 634 635 MAC_VERIEXEC_DBG(2, "mac_veriexec_fingerprint_check_image: " 636 "va_mode=%o, check_files=%d\n", va.va_mode, 637 ((va.va_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0)); 638 error = mac_veriexec_fingerprint_check_image(&img, 639 ((va.va_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0), td); 640 check_done: 641 /* Release the lock we obtained earlier */ 642 VOP_UNLOCK(img.vp, 0); 643 cleanup_file: 644 fdrop(fp, td); 645 break; 646 case MAC_VERIEXEC_CHECK_PATH_SYSCALL: 647 /* Look up the path to get the vnode */ 648 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | AUDITVNODE1, 649 UIO_USERSPACE, arg, td); 650 error = namei(&nd); 651 if (error != 0) 652 break; 653 NDFREE(&nd, NDF_ONLY_PNBUF); 654 655 /* Check the fingerprint status of the vnode */ 656 error = mac_veriexec_check_vp(td->td_ucred, nd.ni_vp, VVERIFY); 657 vput(nd.ni_vp); 658 break; 659 default: 660 error = EOPNOTSUPP; 661 } 662 return (error); 663 } 664 665 static struct mac_policy_ops mac_veriexec_ops = 666 { 667 .mpo_init = mac_veriexec_init, 668 .mpo_syscall = mac_veriexec_syscall, 669 .mpo_kld_check_load = mac_veriexec_kld_check_load, 670 .mpo_mount_destroy_label = mac_veriexec_mount_destroy_label, 671 .mpo_mount_init_label = mac_veriexec_mount_init_label, 672 .mpo_priv_check = mac_veriexec_priv_check, 673 .mpo_proc_check_debug = mac_veriexec_proc_check_debug, 674 .mpo_vnode_check_exec = mac_veriexec_vnode_check_exec, 675 .mpo_vnode_check_open = mac_veriexec_vnode_check_open, 676 .mpo_vnode_copy_label = mac_veriexec_copy_label, 677 .mpo_vnode_destroy_label = mac_veriexec_vnode_destroy_label, 678 .mpo_vnode_init_label = mac_veriexec_vnode_init_label, 679 }; 680 681 MAC_POLICY_SET(&mac_veriexec_ops, mac_veriexec, MAC_VERIEXEC_FULLNAME, 682 MPC_LOADTIME_FLAG_NOTLATE, &mac_veriexec_slot); 683 MODULE_VERSION(mac_veriexec, 1); 684 685 /** 686 * @brief Get the fingerprint status set on a vnode. 687 * 688 * @param vp vnode to obtain fingerprint status from 689 * 690 * @return Fingerprint status assigned to the vnode. 691 */ 692 fingerprint_status_t 693 mac_veriexec_get_fingerprint_status(struct vnode *vp) 694 { 695 fingerprint_status_t fps; 696 697 fps = SLOT(vp->v_label); 698 switch (fps) { 699 case FINGERPRINT_VALID: 700 case FINGERPRINT_INDIRECT: 701 case FINGERPRINT_FILE: 702 break; 703 default: 704 /* we may need to recurse */ 705 if (strcmp(vp->v_tag, "null") == 0) { 706 struct vnode *ldvp; 707 708 ldvp = NULLVPTOLOWERVP(vp); 709 return mac_veriexec_get_fingerprint_status(ldvp); 710 } 711 break; 712 } 713 return fps; 714 } 715 716 /** 717 * @brief Get the current verified execution subsystem state. 718 * 719 * @return Current set of verified execution subsystem state flags. 720 */ 721 int 722 mac_veriexec_get_state(void) 723 { 724 725 return (mac_veriexec_state); 726 } 727 728 /** 729 * @brief Determine if the verified execution subsystem state has specific 730 * flags set. 731 * 732 * @param state mask of flags to check 733 * 734 * @return State flags set within the masked bits 735 */ 736 int 737 mac_veriexec_in_state(int state) 738 { 739 740 return (mac_veriexec_state & state); 741 } 742 743 /** 744 * @brief Set the fingerprint status for a vnode 745 * 746 * Fingerprint status is stored in the MAC per-policy slot assigned to 747 * mac_veriexec. 748 * 749 * @param vp vnode to store the fingerprint status on 750 * @param fp_status fingerprint status to store 751 */ 752 void 753 mac_veriexec_set_fingerprint_status(struct vnode *vp, 754 fingerprint_status_t fp_status) 755 { 756 757 /* recurse until we find the real storage */ 758 if (strcmp(vp->v_tag, "null") == 0) { 759 struct vnode *ldvp; 760 761 ldvp = NULLVPTOLOWERVP(vp); 762 mac_veriexec_set_fingerprint_status(ldvp, fp_status); 763 return; 764 } 765 SLOT_SET(vp->v_label, fp_status); 766 } 767 768 /** 769 * @brief Set verified execution subsystem state flags 770 * 771 * @note Flags can only be added to the current state, not removed. 772 * 773 * @param state state flags to add to the current state 774 */ 775 void 776 mac_veriexec_set_state(int state) 777 { 778 779 mac_veriexec_state |= state; 780 } 781 782 /** 783 * @brief Determine if the process is trusted 784 * 785 * @param cred credentials to use 786 * @param p the process in question 787 * 788 * @return 1 if the process is trusted, otherwise 0. 789 */ 790 int 791 mac_veriexec_proc_is_trusted(struct ucred *cred, struct proc *p) 792 { 793 int error, flags; 794 795 error = mac_veriexec_metadata_get_executable_flags(cred, p, &flags, 0); 796 797 /* Any errors, deny access */ 798 if (error != 0) 799 return (0); 800 801 /* Check that the trusted flag is set */ 802 return ((flags & VERIEXEC_TRUSTED) == VERIEXEC_TRUSTED); 803 } 804