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