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