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