1 /* 2 * $FreeBSD$ 3 * 4 * Copyright (c) 2011, 2012, 2013, 2015, 2016, 2019 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_metadata_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 %ju for mount %p", 197 (uintmax_t)va.va_fsid, mp); 198 #endif 199 } 200 201 /** 202 * @internal 203 * @brief Event handler called when a virtual file system is unmounted. 204 * 205 * If we recorded a file system identifier in the MAC per-policy slot assigned 206 * to veriexec, then we need to tell the meta-data store to clean up. 207 * 208 * @param arg unused argument 209 * @param mp mount point that is being unmounted 210 * @param td calling thread 211 */ 212 static void 213 mac_veriexec_vfs_unmounted(void *arg __unused, struct mount *mp, 214 struct thread *td) 215 { 216 dev_t fsid; 217 218 fsid = SLOT(mp->mnt_label); 219 if (fsid) { 220 MAC_VERIEXEC_DBG(3, "fsid %ju, cleaning up mount", 221 (uintmax_t)fsid); 222 mac_veriexec_metadata_unmounted(fsid, td); 223 } 224 } 225 226 /** 227 * @internal 228 * @brief The mount point is being initialized, set the value in the MAC 229 * per-policy slot for veriexec to zero. 230 * 231 * @note A value of zero in this slot indicates no file system identifier 232 * is assigned. 233 * 234 * @param label the label that is being initialized 235 */ 236 static void 237 mac_veriexec_mount_init_label(struct label *label) 238 { 239 240 SLOT_SET(label, 0); 241 } 242 243 /** 244 * @internal 245 * @brief The mount-point is being destroyed, reset the value in the MAC 246 * per-policy slot for veriexec back to zero. 247 * 248 * @note A value of zero in this slot indicates no file system identifier 249 * is assigned. 250 * 251 * @param label the label that is being destroyed 252 */ 253 static void 254 mac_veriexec_mount_destroy_label(struct label *label) 255 { 256 257 SLOT_SET(label, 0); 258 } 259 260 /** 261 * @internal 262 * @brief The vnode label is being initialized, set the value in the MAC 263 * per-policy slot for veriexec to @c FINGERPRINT_INVALID 264 * 265 * @note @c FINGERPRINT_INVALID indicates the fingerprint is invalid. 266 * 267 * @param label the label that is being initialized 268 */ 269 static void 270 mac_veriexec_vnode_init_label(struct label *label) 271 { 272 273 SLOT_SET(label, FINGERPRINT_INVALID); 274 } 275 276 /** 277 * @internal 278 * @brief The vnode label is being destroyed, reset the value in the MAC 279 * per-policy slot for veriexec back to @c FINGERPRINT_INVALID 280 * 281 * @note @c FINGERPRINT_INVALID indicates the fingerprint is invalid. 282 * 283 * @param label the label that is being destroyed 284 */ 285 static void 286 mac_veriexec_vnode_destroy_label(struct label *label) 287 { 288 289 SLOT_SET(label, FINGERPRINT_INVALID); 290 } 291 292 /** 293 * @internal 294 * @brief Copy the value in the MAC per-policy slot assigned to veriexec from 295 * the @p src label to the @p dest label 296 */ 297 static void 298 mac_veriexec_copy_label(struct label *src, struct label *dest) 299 { 300 301 SLOT_SET(dest, SLOT(src)); 302 } 303 304 /** 305 * @internal 306 * @brief Check if the requested process can be debugged 307 * 308 * @param cred credentials to use 309 * @param p process to debug 310 * 311 * @return 0 if debugging is allowed, otherwise an error code. 312 */ 313 static int 314 mac_veriexec_proc_check_debug(struct ucred *cred, struct proc *p) 315 { 316 int error, flags; 317 318 /* If we are not enforcing veriexec, nothing for us to check */ 319 if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0) 320 return (0); 321 322 error = mac_veriexec_metadata_get_executable_flags(cred, p, &flags, 0); 323 if (error != 0) 324 return (0); 325 326 return ((flags & VERIEXEC_NOTRACE) ? EACCES : 0); 327 } 328 329 /** 330 * @internal 331 * @brief A KLD load has been requested and needs to be validated. 332 * 333 * @param cred credentials to use 334 * @param vp vnode of the KLD that has been requested 335 * @param vlabel vnode label assigned to the vnode 336 * 337 * @return 0 if the KLD load is allowed, otherwise an error code. 338 */ 339 static int 340 mac_veriexec_kld_check_load(struct ucred *cred, struct vnode *vp, 341 struct label *vlabel) 342 { 343 struct vattr va; 344 struct thread *td = curthread; 345 fingerprint_status_t status; 346 int error; 347 348 /* 349 * If we are not actively enforcing, allow it 350 */ 351 if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0) 352 return (0); 353 354 /* Get vnode attributes */ 355 error = VOP_GETATTR(vp, &va, cred); 356 if (error) 357 return (error); 358 359 /* 360 * Fetch the fingerprint status for the vnode 361 * (starting with files first) 362 */ 363 error = mac_veriexec_metadata_fetch_fingerprint_status(vp, &va, td, 364 VERIEXEC_FILES_FIRST); 365 if (error && error != EAUTH) 366 return (error); 367 368 /* 369 * By now we should have status... 370 */ 371 status = mac_veriexec_get_fingerprint_status(vp); 372 switch (status) { 373 case FINGERPRINT_FILE: 374 case FINGERPRINT_VALID: 375 case FINGERPRINT_INDIRECT: 376 if (error) 377 return (error); 378 break; 379 default: 380 /* 381 * kldload should fail unless there is a valid fingerprint 382 * registered. 383 */ 384 MAC_VERIEXEC_DBG(2, "fingerprint status is %d for dev %ju, " 385 "file %ju.%ju\n", status, (uintmax_t)va.va_fsid, 386 (uintmax_t)va.va_fileid, (uintmax_t)va.va_gen); 387 return (EAUTH); 388 } 389 390 /* Everything is good, allow the KLD to be loaded */ 391 return (0); 392 } 393 394 /** 395 * @internal 396 * @brief Check privileges that veriexec needs to be concerned about. 397 * 398 * The following privileges are checked by this function: 399 * - PRIV_KMEM_WRITE\n 400 * Check if writes to /dev/mem and /dev/kmem are allowed\n 401 * (Only trusted processes are allowed) 402 * 403 * @param cred credentials to use 404 * @param priv privilege to check 405 * 406 * @return 0 if the privilege is allowed, error code otherwise. 407 */ 408 static int 409 mac_veriexec_priv_check(struct ucred *cred, int priv) 410 { 411 412 /* If we are not enforcing veriexec, nothing for us to check */ 413 if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0) 414 return (0); 415 416 switch (priv) { 417 case PRIV_KMEM_WRITE: 418 if (!mac_veriexec_proc_is_trusted(cred, curproc)) 419 return (EPERM); 420 break; 421 default: 422 break; 423 } 424 return (0); 425 } 426 427 static int 428 mac_veriexec_sysctl_check(struct ucred *cred, struct sysctl_oid *oidp, 429 void *arg1, int arg2, struct sysctl_req *req) 430 { 431 struct sysctl_oid *oid; 432 433 /* If we are not enforcing veriexec, nothing for us to check */ 434 if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0) 435 return (0); 436 437 oid = oidp; 438 if (oid->oid_kind & CTLFLAG_SECURE) { 439 return (EPERM); /* XXX call mac_veriexec_priv_check? */ 440 } 441 return 0; 442 } 443 444 /** 445 * @internal 446 * @brief A program is being executed and needs to be validated. 447 * 448 * @param cred credentials to use 449 * @param vp vnode of the program that is being executed 450 * @param label vnode label assigned to the vnode 451 * @param imgp parameters for the image to be executed 452 * @param execlabel optional exec label 453 * 454 * @return 0 if the program should be allowed to execute, otherwise an error 455 * code. 456 */ 457 static int 458 mac_veriexec_vnode_check_exec(struct ucred *cred __unused, 459 struct vnode *vp __unused, struct label *label __unused, 460 struct image_params *imgp, struct label *execlabel __unused) 461 { 462 struct thread *td = curthread; 463 int error; 464 465 error = mac_veriexec_fingerprint_check_image(imgp, 0, td); 466 return (error); 467 } 468 469 /** 470 * @brief Check fingerprint for the specified vnode and validate it 471 * 472 * @param cred credentials to use 473 * @param vp vnode of the file 474 * @param accmode access mode to check (read, write, append, create, 475 * verify, etc.) 476 * 477 * @return 0 if the file validated, otherwise an error code. 478 */ 479 static int 480 mac_veriexec_check_vp(struct ucred *cred, struct vnode *vp, accmode_t accmode) 481 { 482 struct vattr va; 483 struct thread *td = curthread; 484 fingerprint_status_t status; 485 int error; 486 487 /* Get vnode attributes */ 488 error = VOP_GETATTR(vp, &va, cred); 489 if (error) 490 return (error); 491 492 /* Get the fingerprint status for the file */ 493 error = mac_veriexec_metadata_fetch_fingerprint_status(vp, &va, td, 494 VERIEXEC_FILES_FIRST); 495 if (error && error != EAUTH) 496 return (error); 497 498 /* 499 * By now we should have status... 500 */ 501 status = mac_veriexec_get_fingerprint_status(vp); 502 if (accmode & VWRITE) { 503 /* 504 * If file has a fingerprint then deny the write request, 505 * otherwise invalidate the status so we don't keep checking 506 * for the file having a fingerprint. 507 */ 508 switch (status) { 509 case FINGERPRINT_FILE: 510 case FINGERPRINT_VALID: 511 case FINGERPRINT_INDIRECT: 512 MAC_VERIEXEC_DBG(2, 513 "attempted write to fingerprinted file for dev " 514 "%ju, file %ju.%ju\n", (uintmax_t)va.va_fsid, 515 (uintmax_t)va.va_fileid, (uintmax_t)va.va_gen); 516 return (EPERM); 517 default: 518 break; 519 } 520 } 521 if (accmode & VVERIFY) { 522 switch (status) { 523 case FINGERPRINT_FILE: 524 case FINGERPRINT_VALID: 525 case FINGERPRINT_INDIRECT: 526 if (error) 527 return (error); 528 break; 529 default: 530 /* 531 * Caller wants open to fail unless there is a valid 532 * fingerprint registered. 533 */ 534 MAC_VERIEXEC_DBG(2, "fingerprint status is %d for dev " 535 "%ju, file %ju.%ju\n", status, 536 (uintmax_t)va.va_fsid, (uintmax_t)va.va_fileid, 537 (uintmax_t)va.va_gen); 538 return (EAUTH); 539 } 540 } 541 return (0); 542 } 543 544 /** 545 * @brief Opening a file has been requested and may need to be validated. 546 * 547 * @param cred credentials to use 548 * @param vp vnode of the file to open 549 * @param label vnode label assigned to the vnode 550 * @param accmode access mode to use for opening the file (read, write, 551 * append, create, verify, etc.) 552 * 553 * @return 0 if opening the file should be allowed, otherwise an error code. 554 */ 555 static int 556 mac_veriexec_vnode_check_open(struct ucred *cred, struct vnode *vp, 557 struct label *label __unused, accmode_t accmode) 558 { 559 int error; 560 561 /* 562 * Look for the file on the fingerprint lists iff it has not been seen 563 * before. 564 */ 565 if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0) 566 return (0); 567 568 error = mac_veriexec_check_vp(cred, vp, accmode); 569 return (error); 570 } 571 572 /** 573 * @brief Check mode changes on file to ensure they should be allowed. 574 * 575 * We cannot allow chmod of SUID or SGID on verified files. 576 * 577 * @param cred credentials to use 578 * @param vp vnode of the file to open 579 * @param label vnode label assigned to the vnode 580 * @param mode mode flags to set 581 * 582 * @return 0 if the mode change should be allowed, EAUTH otherwise. 583 */ 584 static int 585 mac_veriexec_vnode_check_setmode(struct ucred *cred, struct vnode *vp, 586 struct label *label __unused, mode_t mode) 587 { 588 int error; 589 590 if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0) 591 return (0); 592 593 /* 594 * Do not allow chmod (set-[gu]id) of verified file 595 */ 596 error = mac_veriexec_check_vp(cred, vp, VVERIFY); 597 if (error == EAUTH) /* it isn't verified */ 598 return (0); 599 if (error == 0 && (mode & (S_ISUID|S_ISGID)) != 0) 600 return (EAUTH); 601 return (0); 602 } 603 604 /** 605 * @internal 606 * @brief Initialize the mac_veriexec MAC policy 607 * 608 * @param mpc MAC policy configuration 609 */ 610 static void 611 mac_veriexec_init(struct mac_policy_conf *mpc __unused) 612 { 613 /* Initialize state */ 614 mac_veriexec_state = VERIEXEC_STATE_INACTIVE; 615 616 /* Initialize meta-data storage */ 617 mac_veriexec_metadata_init(); 618 619 /* Initialize fingerprint ops */ 620 mac_veriexec_fingerprint_init(); 621 622 /* Register event handlers */ 623 EVENTHANDLER_REGISTER(vfs_mounted, mac_veriexec_vfs_mounted, NULL, 624 EVENTHANDLER_PRI_FIRST); 625 EVENTHANDLER_REGISTER(vfs_unmounted, mac_veriexec_vfs_unmounted, NULL, 626 EVENTHANDLER_PRI_LAST); 627 } 628 629 /** 630 * @internal 631 * @brief MAC policy-specific syscall for mac_veriexec 632 * 633 * The following syscalls are implemented: 634 * - @c MAC_VERIEXEC_CHECK_SYSCALL 635 * Check if the file referenced by a file descriptor has a fingerprint 636 * registered in the meta-data store. 637 * 638 * @param td calling thread 639 * @param call system call number 640 * @param arg arugments to the syscall 641 * 642 * @return 0 on success, otherwise an error code. 643 */ 644 static int 645 mac_veriexec_syscall(struct thread *td, int call, void *arg) 646 { 647 struct image_params img; 648 struct nameidata nd; 649 cap_rights_t rights; 650 struct vattr va; 651 struct file *fp; 652 int error; 653 654 switch (call) { 655 case MAC_VERIEXEC_CHECK_FD_SYSCALL: 656 /* Get the vnode associated with the file descriptor passed */ 657 error = getvnode(td, (uintptr_t) arg, cap_rights_init(&rights, 658 CAP_READ), &fp); 659 if (error) 660 return (error); 661 if (fp->f_type != DTYPE_VNODE) { 662 MAC_VERIEXEC_DBG(3, "MAC_VERIEXEC_CHECK_SYSCALL: " 663 "file is not vnode type (type=0x%x)", 664 fp->f_type); 665 error = EINVAL; 666 goto cleanup_file; 667 } 668 669 /* 670 * setup the bits of image_params that are used by 671 * mac_veriexec_check_fingerprint(). 672 */ 673 bzero(&img, sizeof(img)); 674 img.proc = td->td_proc; 675 img.vp = fp->f_vnode; 676 img.attr = &va; 677 678 /* 679 * Get vnode attributes 680 * (need to obtain a lock on the vnode first) 681 */ 682 vn_lock(img.vp, LK_EXCLUSIVE | LK_RETRY); 683 error = VOP_GETATTR(fp->f_vnode, &va, td->td_ucred); 684 if (error) 685 goto check_done; 686 687 MAC_VERIEXEC_DBG(2, "mac_veriexec_fingerprint_check_image: " 688 "va_mode=%o, check_files=%d\n", va.va_mode, 689 ((va.va_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0)); 690 error = mac_veriexec_fingerprint_check_image(&img, 691 ((va.va_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0), td); 692 check_done: 693 /* Release the lock we obtained earlier */ 694 VOP_UNLOCK(img.vp); 695 cleanup_file: 696 fdrop(fp, td); 697 break; 698 case MAC_VERIEXEC_CHECK_PATH_SYSCALL: 699 /* Look up the path to get the vnode */ 700 NDINIT(&nd, LOOKUP, 701 FOLLOW | LOCKLEAF | LOCKSHARED | AUDITVNODE1, 702 UIO_USERSPACE, arg, td); 703 error = namei(&nd); 704 if (error != 0) 705 break; 706 NDFREE(&nd, NDF_ONLY_PNBUF); 707 708 /* Check the fingerprint status of the vnode */ 709 error = mac_veriexec_check_vp(td->td_ucred, nd.ni_vp, VVERIFY); 710 vput(nd.ni_vp); 711 break; 712 default: 713 error = EOPNOTSUPP; 714 } 715 return (error); 716 } 717 718 static struct mac_policy_ops mac_veriexec_ops = 719 { 720 .mpo_init = mac_veriexec_init, 721 .mpo_kld_check_load = mac_veriexec_kld_check_load, 722 .mpo_mount_destroy_label = mac_veriexec_mount_destroy_label, 723 .mpo_mount_init_label = mac_veriexec_mount_init_label, 724 .mpo_priv_check = mac_veriexec_priv_check, 725 .mpo_proc_check_debug = mac_veriexec_proc_check_debug, 726 .mpo_syscall = mac_veriexec_syscall, 727 .mpo_system_check_sysctl = mac_veriexec_sysctl_check, 728 .mpo_vnode_check_exec = mac_veriexec_vnode_check_exec, 729 .mpo_vnode_check_open = mac_veriexec_vnode_check_open, 730 .mpo_vnode_check_setmode = mac_veriexec_vnode_check_setmode, 731 .mpo_vnode_copy_label = mac_veriexec_copy_label, 732 .mpo_vnode_destroy_label = mac_veriexec_vnode_destroy_label, 733 .mpo_vnode_init_label = mac_veriexec_vnode_init_label, 734 }; 735 736 MAC_POLICY_SET(&mac_veriexec_ops, mac_veriexec, MAC_VERIEXEC_FULLNAME, 737 MPC_LOADTIME_FLAG_NOTLATE, &mac_veriexec_slot); 738 MODULE_VERSION(mac_veriexec, 1); 739 740 static struct vnode * 741 mac_veriexec_bottom_vnode(struct vnode *vp) 742 { 743 struct vnode *ldvp = NULL; 744 745 /* 746 * XXX This code is bogus. nullfs is not the only stacking 747 * filesystem. Less bogus code would add a VOP to reach bottom 748 * vnode and would not make assumptions how to get there. 749 */ 750 if (vp->v_mount != NULL && 751 strcmp(vp->v_mount->mnt_vfc->vfc_name, "nullfs") == 0) 752 ldvp = NULLVPTOLOWERVP(vp); 753 return (ldvp); 754 } 755 756 /** 757 * @brief Get the fingerprint status set on a vnode. 758 * 759 * @param vp vnode to obtain fingerprint status from 760 * 761 * @return Fingerprint status assigned to the vnode. 762 */ 763 fingerprint_status_t 764 mac_veriexec_get_fingerprint_status(struct vnode *vp) 765 { 766 fingerprint_status_t fps; 767 struct vnode *ldvp; 768 769 fps = SLOT(vp->v_label); 770 switch (fps) { 771 case FINGERPRINT_VALID: 772 case FINGERPRINT_INDIRECT: 773 case FINGERPRINT_FILE: 774 break; 775 default: 776 /* we may need to recurse */ 777 ldvp = mac_veriexec_bottom_vnode(vp); 778 if (ldvp != NULL) 779 return mac_veriexec_get_fingerprint_status(ldvp); 780 break; 781 } 782 return fps; 783 } 784 785 /** 786 * @brief Get the current verified execution subsystem state. 787 * 788 * @return Current set of verified execution subsystem state flags. 789 */ 790 int 791 mac_veriexec_get_state(void) 792 { 793 794 return (mac_veriexec_state); 795 } 796 797 /** 798 * @brief Determine if the verified execution subsystem state has specific 799 * flags set. 800 * 801 * @param state mask of flags to check 802 * 803 * @return State flags set within the masked bits 804 */ 805 int 806 mac_veriexec_in_state(int state) 807 { 808 809 return (mac_veriexec_state & state); 810 } 811 812 /** 813 * @brief Set the fingerprint status for a vnode 814 * 815 * Fingerprint status is stored in the MAC per-policy slot assigned to 816 * mac_veriexec. 817 * 818 * @param vp vnode to store the fingerprint status on 819 * @param fp_status fingerprint status to store 820 */ 821 void 822 mac_veriexec_set_fingerprint_status(struct vnode *vp, 823 fingerprint_status_t fp_status) 824 { 825 struct vnode *ldvp; 826 827 /* recurse until we find the real storage */ 828 ldvp = mac_veriexec_bottom_vnode(vp); 829 if (ldvp != NULL) { 830 mac_veriexec_set_fingerprint_status(ldvp, fp_status); 831 return; 832 } 833 SLOT_SET(vp->v_label, fp_status); 834 } 835 836 /** 837 * @brief Set verified execution subsystem state flags 838 * 839 * @note Flags can only be added to the current state, not removed. 840 * 841 * @param state state flags to add to the current state 842 */ 843 void 844 mac_veriexec_set_state(int state) 845 { 846 847 mac_veriexec_state |= state; 848 } 849 850 /** 851 * @brief Determine if the process is trusted 852 * 853 * @param cred credentials to use 854 * @param p the process in question 855 * 856 * @return 1 if the process is trusted, otherwise 0. 857 */ 858 int 859 mac_veriexec_proc_is_trusted(struct ucred *cred, struct proc *p) 860 { 861 int already_locked, error, flags; 862 863 /* Make sure we lock the process if we do not already have the lock */ 864 already_locked = PROC_LOCKED(p); 865 if (!already_locked) 866 PROC_LOCK(p); 867 868 error = mac_veriexec_metadata_get_executable_flags(cred, p, &flags, 0); 869 870 /* Unlock the process if we locked it previously */ 871 if (!already_locked) 872 PROC_UNLOCK(p); 873 874 /* Any errors, deny access */ 875 if (error != 0) 876 return (0); 877 878 /* Check that the trusted flag is set */ 879 return ((flags & VERIEXEC_TRUSTED) == VERIEXEC_TRUSTED); 880 } 881