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