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