1 /*- 2 * Copyright (c) 1999-2002 Robert N. M. Watson 3 * Copyright (c) 2001 Ilmar S. Habibulin 4 * Copyright (c) 2001-2005 Networks Associates Technology, Inc. 5 * All rights reserved. 6 * 7 * This software was developed by Robert Watson and Ilmar Habibulin for the 8 * TrustedBSD Project. 9 * 10 * This software was developed for the FreeBSD Project in part by Network 11 * Associates Laboratories, the Security Research Division of Network 12 * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), 13 * as part of the DARPA CHATS research program. 14 * 15 * Redistribution and use in source and binary forms, with or without 16 * modification, are permitted provided that the following conditions 17 * are met: 18 * 1. Redistributions of source code must retain the above copyright 19 * notice, this list of conditions and the following disclaimer. 20 * 2. Redistributions in binary form must reproduce the above copyright 21 * notice, this list of conditions and the following disclaimer in the 22 * documentation and/or other materials provided with the distribution. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 */ 36 37 /*- 38 * Framework for extensible kernel access control. This file contains 39 * Kernel and userland interface to the framework, policy registration 40 * and composition. Per-object interfaces, controls, and labeling may be 41 * found in src/sys/security/mac/. Sample policies may be found in 42 * src/sys/security/mac_*. 43 */ 44 45 #include <sys/cdefs.h> 46 __FBSDID("$FreeBSD$"); 47 48 #include "opt_mac.h" 49 #include "opt_devfs.h" 50 51 #include <sys/param.h> 52 #include <sys/condvar.h> 53 #include <sys/extattr.h> 54 #include <sys/imgact.h> 55 #include <sys/kernel.h> 56 #include <sys/lock.h> 57 #include <sys/malloc.h> 58 #include <sys/mutex.h> 59 #include <sys/mac.h> 60 #include <sys/module.h> 61 #include <sys/proc.h> 62 #include <sys/sbuf.h> 63 #include <sys/systm.h> 64 #include <sys/sysproto.h> 65 #include <sys/sysent.h> 66 #include <sys/vnode.h> 67 #include <sys/mount.h> 68 #include <sys/file.h> 69 #include <sys/namei.h> 70 #include <sys/socket.h> 71 #include <sys/pipe.h> 72 #include <sys/socketvar.h> 73 #include <sys/sysctl.h> 74 75 #include <vm/vm.h> 76 #include <vm/pmap.h> 77 #include <vm/vm_map.h> 78 #include <vm/vm_object.h> 79 80 #include <sys/mac_policy.h> 81 82 #include <fs/devfs/devfs.h> 83 84 #include <net/bpfdesc.h> 85 #include <net/if.h> 86 #include <net/if_var.h> 87 88 #include <netinet/in.h> 89 #include <netinet/ip_var.h> 90 91 #include <security/mac/mac_internal.h> 92 93 #ifdef MAC 94 95 /* 96 * Declare that the kernel provides MAC support, version 1. This permits 97 * modules to refuse to be loaded if the necessary support isn't present, 98 * even if it's pre-boot. 99 */ 100 MODULE_VERSION(kernel_mac_support, 2); 101 102 SYSCTL_NODE(_security, OID_AUTO, mac, CTLFLAG_RW, 0, 103 "TrustedBSD MAC policy controls"); 104 105 #if MAC_MAX_SLOTS > 32 106 #error "MAC_MAX_SLOTS too large" 107 #endif 108 109 static unsigned int mac_max_slots = MAC_MAX_SLOTS; 110 static unsigned int mac_slot_offsets_free = (1 << MAC_MAX_SLOTS) - 1; 111 SYSCTL_UINT(_security_mac, OID_AUTO, max_slots, CTLFLAG_RD, 112 &mac_max_slots, 0, ""); 113 114 /* 115 * Has the kernel started generating labeled objects yet? All read/write 116 * access to this variable is serialized during the boot process. Following 117 * the end of serialization, we don't update this flag; no locking. 118 */ 119 int mac_late = 0; 120 121 /* 122 * Flag to indicate whether or not we should allocate label storage for 123 * new mbufs. Since most dynamic policies we currently work with don't 124 * rely on mbuf labeling, try to avoid paying the cost of mtag allocation 125 * unless specifically notified of interest. One result of this is 126 * that if a dynamically loaded policy requests mbuf labels, it must 127 * be able to deal with a NULL label being returned on any mbufs that 128 * were already in flight when the policy was loaded. Since the policy 129 * already has to deal with uninitialized labels, this probably won't 130 * be a problem. Note: currently no locking. Will this be a problem? 131 */ 132 #ifndef MAC_ALWAYS_LABEL_MBUF 133 int mac_labelmbufs = 0; 134 #endif 135 136 #ifdef MAC_DEBUG 137 SYSCTL_NODE(_security_mac, OID_AUTO, debug, CTLFLAG_RW, 0, 138 "TrustedBSD MAC debug info"); 139 SYSCTL_NODE(_security_mac_debug, OID_AUTO, counters, CTLFLAG_RW, 0, 140 "TrustedBSD MAC object counters"); 141 142 static unsigned int nmactemp; 143 SYSCTL_UINT(_security_mac_debug_counters, OID_AUTO, temp, CTLFLAG_RD, 144 &nmactemp, 0, "number of temporary labels in use"); 145 #endif 146 147 static int mac_policy_register(struct mac_policy_conf *mpc); 148 static int mac_policy_unregister(struct mac_policy_conf *mpc); 149 150 MALLOC_DEFINE(M_MACTEMP, "mactemp", "MAC temporary label storage"); 151 152 /* 153 * mac_static_policy_list holds a list of policy modules that are not 154 * loaded while the system is "live", and cannot be unloaded. These 155 * policies can be invoked without holding the busy count. 156 * 157 * mac_policy_list stores the list of dynamic policies. A busy count is 158 * maintained for the list, stored in mac_policy_busy. The busy count 159 * is protected by mac_policy_mtx; the list may be modified only 160 * while the busy count is 0, requiring that the lock be held to 161 * prevent new references to the list from being acquired. For almost 162 * all operations, incrementing the busy count is sufficient to 163 * guarantee consistency, as the list cannot be modified while the 164 * busy count is elevated. For a few special operations involving a 165 * change to the list of active policies, the mtx itself must be held. 166 * A condition variable, mac_policy_cv, is used to signal potential 167 * exclusive consumers that they should try to acquire the lock if a 168 * first attempt at exclusive access fails. 169 */ 170 #ifndef MAC_STATIC 171 static struct mtx mac_policy_mtx; 172 static struct cv mac_policy_cv; 173 static int mac_policy_count; 174 #endif 175 struct mac_policy_list_head mac_policy_list; 176 struct mac_policy_list_head mac_static_policy_list; 177 178 /* 179 * We manually invoke WITNESS_WARN() to allow Witness to generate 180 * warnings even if we don't end up ever triggering the wait at 181 * run-time. The consumer of the exclusive interface must not hold 182 * any locks (other than potentially Giant) since we may sleep for 183 * long (potentially indefinite) periods of time waiting for the 184 * framework to become quiescent so that a policy list change may 185 * be made. 186 */ 187 void 188 mac_policy_grab_exclusive(void) 189 { 190 191 #ifndef MAC_STATIC 192 if (!mac_late) 193 return; 194 195 WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, 196 "mac_policy_grab_exclusive() at %s:%d", __FILE__, __LINE__); 197 mtx_lock(&mac_policy_mtx); 198 while (mac_policy_count != 0) 199 cv_wait(&mac_policy_cv, &mac_policy_mtx); 200 #endif 201 } 202 203 void 204 mac_policy_assert_exclusive(void) 205 { 206 207 #ifndef MAC_STATIC 208 if (!mac_late) 209 return; 210 211 mtx_assert(&mac_policy_mtx, MA_OWNED); 212 KASSERT(mac_policy_count == 0, 213 ("mac_policy_assert_exclusive(): not exclusive")); 214 #endif 215 } 216 217 void 218 mac_policy_release_exclusive(void) 219 { 220 221 #ifndef MAC_STATIC 222 if (!mac_late) 223 return; 224 225 KASSERT(mac_policy_count == 0, 226 ("mac_policy_release_exclusive(): not exclusive")); 227 mtx_unlock(&mac_policy_mtx); 228 cv_signal(&mac_policy_cv); 229 #endif 230 } 231 232 void 233 mac_policy_list_busy(void) 234 { 235 236 #ifndef MAC_STATIC 237 if (!mac_late) 238 return; 239 240 mtx_lock(&mac_policy_mtx); 241 mac_policy_count++; 242 mtx_unlock(&mac_policy_mtx); 243 #endif 244 } 245 246 int 247 mac_policy_list_conditional_busy(void) 248 { 249 #ifndef MAC_STATIC 250 int ret; 251 252 if (!mac_late) 253 return (1); 254 255 mtx_lock(&mac_policy_mtx); 256 if (!LIST_EMPTY(&mac_policy_list)) { 257 mac_policy_count++; 258 ret = 1; 259 } else 260 ret = 0; 261 mtx_unlock(&mac_policy_mtx); 262 return (ret); 263 #else 264 if (!mac_late) 265 return (1); 266 267 return (1); 268 #endif 269 } 270 271 void 272 mac_policy_list_unbusy(void) 273 { 274 275 #ifndef MAC_STATIC 276 if (!mac_late) 277 return; 278 279 mtx_lock(&mac_policy_mtx); 280 mac_policy_count--; 281 KASSERT(mac_policy_count >= 0, ("MAC_POLICY_LIST_LOCK")); 282 if (mac_policy_count == 0) 283 cv_signal(&mac_policy_cv); 284 mtx_unlock(&mac_policy_mtx); 285 #endif 286 } 287 288 /* 289 * Initialize the MAC subsystem, including appropriate SMP locks. 290 */ 291 static void 292 mac_init(void) 293 { 294 295 LIST_INIT(&mac_static_policy_list); 296 LIST_INIT(&mac_policy_list); 297 mac_labelzone_init(); 298 299 #ifndef MAC_STATIC 300 mtx_init(&mac_policy_mtx, "mac_policy_mtx", NULL, MTX_DEF); 301 cv_init(&mac_policy_cv, "mac_policy_cv"); 302 #endif 303 } 304 305 /* 306 * For the purposes of modules that want to know if they were loaded 307 * "early", set the mac_late flag once we've processed modules either 308 * linked into the kernel, or loaded before the kernel startup. 309 */ 310 static void 311 mac_late_init(void) 312 { 313 314 mac_late = 1; 315 } 316 317 /* 318 * After the policy list has changed, walk the list to update any global 319 * flags. Currently, we support only one flag, and it's conditionally 320 * defined; as a result, the entire function is conditional. Eventually, 321 * the #else case might also iterate across the policies. 322 */ 323 static void 324 mac_policy_updateflags(void) 325 { 326 #ifndef MAC_ALWAYS_LABEL_MBUF 327 struct mac_policy_conf *tmpc; 328 int labelmbufs; 329 330 mac_policy_assert_exclusive(); 331 332 labelmbufs = 0; 333 LIST_FOREACH(tmpc, &mac_static_policy_list, mpc_list) { 334 if (tmpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_LABELMBUFS) 335 labelmbufs++; 336 } 337 LIST_FOREACH(tmpc, &mac_policy_list, mpc_list) { 338 if (tmpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_LABELMBUFS) 339 labelmbufs++; 340 } 341 mac_labelmbufs = (labelmbufs != 0); 342 #endif 343 } 344 345 /* 346 * Allow MAC policy modules to register during boot, etc. 347 */ 348 int 349 mac_policy_modevent(module_t mod, int type, void *data) 350 { 351 struct mac_policy_conf *mpc; 352 int error; 353 354 error = 0; 355 mpc = (struct mac_policy_conf *) data; 356 357 #ifdef MAC_STATIC 358 if (mac_late) { 359 printf("mac_policy_modevent: MAC_STATIC and late\n"); 360 return (EBUSY); 361 } 362 #endif 363 364 switch (type) { 365 case MOD_LOAD: 366 if (mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_NOTLATE && 367 mac_late) { 368 printf("mac_policy_modevent: can't load %s policy " 369 "after booting\n", mpc->mpc_name); 370 error = EBUSY; 371 break; 372 } 373 error = mac_policy_register(mpc); 374 break; 375 case MOD_UNLOAD: 376 /* Don't unregister the module if it was never registered. */ 377 if ((mpc->mpc_runtime_flags & MPC_RUNTIME_FLAG_REGISTERED) 378 != 0) 379 error = mac_policy_unregister(mpc); 380 else 381 error = 0; 382 break; 383 default: 384 error = EOPNOTSUPP; 385 break; 386 } 387 388 return (error); 389 } 390 391 static int 392 mac_policy_register(struct mac_policy_conf *mpc) 393 { 394 struct mac_policy_conf *tmpc; 395 int error, slot, static_entry; 396 397 error = 0; 398 399 /* 400 * We don't technically need exclusive access while !mac_late, 401 * but hold it for assertion consistency. 402 */ 403 mac_policy_grab_exclusive(); 404 405 /* 406 * If the module can potentially be unloaded, or we're loading 407 * late, we have to stick it in the non-static list and pay 408 * an extra performance overhead. Otherwise, we can pay a 409 * light locking cost and stick it in the static list. 410 */ 411 static_entry = (!mac_late && 412 !(mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_UNLOADOK)); 413 414 if (static_entry) { 415 LIST_FOREACH(tmpc, &mac_static_policy_list, mpc_list) { 416 if (strcmp(tmpc->mpc_name, mpc->mpc_name) == 0) { 417 error = EEXIST; 418 goto out; 419 } 420 } 421 } else { 422 LIST_FOREACH(tmpc, &mac_policy_list, mpc_list) { 423 if (strcmp(tmpc->mpc_name, mpc->mpc_name) == 0) { 424 error = EEXIST; 425 goto out; 426 } 427 } 428 } 429 if (mpc->mpc_field_off != NULL) { 430 slot = ffs(mac_slot_offsets_free); 431 if (slot == 0) { 432 error = ENOMEM; 433 goto out; 434 } 435 slot--; 436 mac_slot_offsets_free &= ~(1 << slot); 437 *mpc->mpc_field_off = slot; 438 } 439 mpc->mpc_runtime_flags |= MPC_RUNTIME_FLAG_REGISTERED; 440 441 /* 442 * If we're loading a MAC module after the framework has 443 * initialized, it has to go into the dynamic list. If 444 * we're loading it before we've finished initializing, 445 * it can go into the static list with weaker locker 446 * requirements. 447 */ 448 if (static_entry) 449 LIST_INSERT_HEAD(&mac_static_policy_list, mpc, mpc_list); 450 else 451 LIST_INSERT_HEAD(&mac_policy_list, mpc, mpc_list); 452 453 /* Per-policy initialization. */ 454 if (mpc->mpc_ops->mpo_init != NULL) 455 (*(mpc->mpc_ops->mpo_init))(mpc); 456 mac_policy_updateflags(); 457 458 printf("Security policy loaded: %s (%s)\n", mpc->mpc_fullname, 459 mpc->mpc_name); 460 461 out: 462 mac_policy_release_exclusive(); 463 return (error); 464 } 465 466 static int 467 mac_policy_unregister(struct mac_policy_conf *mpc) 468 { 469 470 /* 471 * If we fail the load, we may get a request to unload. Check 472 * to see if we did the run-time registration, and if not, 473 * silently succeed. 474 */ 475 mac_policy_grab_exclusive(); 476 if ((mpc->mpc_runtime_flags & MPC_RUNTIME_FLAG_REGISTERED) == 0) { 477 mac_policy_release_exclusive(); 478 return (0); 479 } 480 #if 0 481 /* 482 * Don't allow unloading modules with private data. 483 */ 484 if (mpc->mpc_field_off != NULL) { 485 MAC_POLICY_LIST_UNLOCK(); 486 return (EBUSY); 487 } 488 #endif 489 /* 490 * Only allow the unload to proceed if the module is unloadable 491 * by its own definition. 492 */ 493 if ((mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_UNLOADOK) == 0) { 494 mac_policy_release_exclusive(); 495 return (EBUSY); 496 } 497 if (mpc->mpc_ops->mpo_destroy != NULL) 498 (*(mpc->mpc_ops->mpo_destroy))(mpc); 499 500 LIST_REMOVE(mpc, mpc_list); 501 mpc->mpc_runtime_flags &= ~MPC_RUNTIME_FLAG_REGISTERED; 502 mac_policy_updateflags(); 503 504 mac_policy_release_exclusive(); 505 506 printf("Security policy unload: %s (%s)\n", mpc->mpc_fullname, 507 mpc->mpc_name); 508 509 return (0); 510 } 511 512 /* 513 * Define an error value precedence, and given two arguments, selects the 514 * value with the higher precedence. 515 */ 516 int 517 mac_error_select(int error1, int error2) 518 { 519 520 /* Certain decision-making errors take top priority. */ 521 if (error1 == EDEADLK || error2 == EDEADLK) 522 return (EDEADLK); 523 524 /* Invalid arguments should be reported where possible. */ 525 if (error1 == EINVAL || error2 == EINVAL) 526 return (EINVAL); 527 528 /* Precedence goes to "visibility", with both process and file. */ 529 if (error1 == ESRCH || error2 == ESRCH) 530 return (ESRCH); 531 532 if (error1 == ENOENT || error2 == ENOENT) 533 return (ENOENT); 534 535 /* Precedence goes to DAC/MAC protections. */ 536 if (error1 == EACCES || error2 == EACCES) 537 return (EACCES); 538 539 /* Precedence goes to privilege. */ 540 if (error1 == EPERM || error2 == EPERM) 541 return (EPERM); 542 543 /* Precedence goes to error over success; otherwise, arbitrary. */ 544 if (error1 != 0) 545 return (error1); 546 return (error2); 547 } 548 549 void 550 mac_init_label(struct label *label) 551 { 552 553 bzero(label, sizeof(*label)); 554 label->l_flags = MAC_FLAG_INITIALIZED; 555 } 556 557 void 558 mac_destroy_label(struct label *label) 559 { 560 561 KASSERT(label->l_flags & MAC_FLAG_INITIALIZED, 562 ("destroying uninitialized label")); 563 564 bzero(label, sizeof(*label)); 565 /* implicit: label->l_flags &= ~MAC_FLAG_INITIALIZED; */ 566 } 567 568 int 569 mac_check_structmac_consistent(struct mac *mac) 570 { 571 572 if (mac->m_buflen < 0 || 573 mac->m_buflen > MAC_MAX_LABEL_BUF_LEN) 574 return (EINVAL); 575 576 return (0); 577 } 578 579 /* 580 * MPSAFE 581 */ 582 int 583 __mac_get_pid(struct thread *td, struct __mac_get_pid_args *uap) 584 { 585 char *elements, *buffer; 586 struct mac mac; 587 struct proc *tproc; 588 struct ucred *tcred; 589 int error; 590 591 error = copyin(uap->mac_p, &mac, sizeof(mac)); 592 if (error) 593 return (error); 594 595 error = mac_check_structmac_consistent(&mac); 596 if (error) 597 return (error); 598 599 tproc = pfind(uap->pid); 600 if (tproc == NULL) 601 return (ESRCH); 602 603 tcred = NULL; /* Satisfy gcc. */ 604 error = p_cansee(td, tproc); 605 if (error == 0) 606 tcred = crhold(tproc->p_ucred); 607 PROC_UNLOCK(tproc); 608 if (error) 609 return (error); 610 611 elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 612 error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL); 613 if (error) { 614 free(elements, M_MACTEMP); 615 crfree(tcred); 616 return (error); 617 } 618 619 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); 620 error = mac_externalize_cred_label(tcred->cr_label, elements, 621 buffer, mac.m_buflen); 622 if (error == 0) 623 error = copyout(buffer, mac.m_string, strlen(buffer)+1); 624 625 free(buffer, M_MACTEMP); 626 free(elements, M_MACTEMP); 627 crfree(tcred); 628 return (error); 629 } 630 631 /* 632 * MPSAFE 633 */ 634 int 635 __mac_get_proc(struct thread *td, struct __mac_get_proc_args *uap) 636 { 637 char *elements, *buffer; 638 struct mac mac; 639 int error; 640 641 error = copyin(uap->mac_p, &mac, sizeof(mac)); 642 if (error) 643 return (error); 644 645 error = mac_check_structmac_consistent(&mac); 646 if (error) 647 return (error); 648 649 elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 650 error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL); 651 if (error) { 652 free(elements, M_MACTEMP); 653 return (error); 654 } 655 656 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); 657 error = mac_externalize_cred_label(td->td_ucred->cr_label, 658 elements, buffer, mac.m_buflen); 659 if (error == 0) 660 error = copyout(buffer, mac.m_string, strlen(buffer)+1); 661 662 free(buffer, M_MACTEMP); 663 free(elements, M_MACTEMP); 664 return (error); 665 } 666 667 /* 668 * MPSAFE 669 */ 670 int 671 __mac_set_proc(struct thread *td, struct __mac_set_proc_args *uap) 672 { 673 struct ucred *newcred, *oldcred; 674 struct label *intlabel; 675 struct proc *p; 676 struct mac mac; 677 char *buffer; 678 int error; 679 680 error = copyin(uap->mac_p, &mac, sizeof(mac)); 681 if (error) 682 return (error); 683 684 error = mac_check_structmac_consistent(&mac); 685 if (error) 686 return (error); 687 688 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 689 error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL); 690 if (error) { 691 free(buffer, M_MACTEMP); 692 return (error); 693 } 694 695 intlabel = mac_cred_label_alloc(); 696 error = mac_internalize_cred_label(intlabel, buffer); 697 free(buffer, M_MACTEMP); 698 if (error) 699 goto out; 700 701 newcred = crget(); 702 703 p = td->td_proc; 704 PROC_LOCK(p); 705 oldcred = p->p_ucred; 706 707 error = mac_check_cred_relabel(oldcred, intlabel); 708 if (error) { 709 PROC_UNLOCK(p); 710 crfree(newcred); 711 goto out; 712 } 713 714 setsugid(p); 715 crcopy(newcred, oldcred); 716 mac_relabel_cred(newcred, intlabel); 717 p->p_ucred = newcred; 718 719 /* 720 * Grab additional reference for use while revoking mmaps, prior 721 * to releasing the proc lock and sharing the cred. 722 */ 723 crhold(newcred); 724 PROC_UNLOCK(p); 725 726 if (mac_enforce_vm) { 727 mtx_lock(&Giant); 728 mac_cred_mmapped_drop_perms(td, newcred); 729 mtx_unlock(&Giant); 730 } 731 732 crfree(newcred); /* Free revocation reference. */ 733 crfree(oldcred); 734 735 out: 736 mac_cred_label_free(intlabel); 737 return (error); 738 } 739 740 /* 741 * MPSAFE 742 */ 743 int 744 __mac_get_fd(struct thread *td, struct __mac_get_fd_args *uap) 745 { 746 char *elements, *buffer; 747 struct label *intlabel; 748 struct file *fp; 749 struct mac mac; 750 struct vnode *vp; 751 struct pipe *pipe; 752 struct socket *so; 753 short label_type; 754 int error; 755 756 error = copyin(uap->mac_p, &mac, sizeof(mac)); 757 if (error) 758 return (error); 759 760 error = mac_check_structmac_consistent(&mac); 761 if (error) 762 return (error); 763 764 elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 765 error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL); 766 if (error) { 767 free(elements, M_MACTEMP); 768 return (error); 769 } 770 771 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); 772 error = fget(td, uap->fd, &fp); 773 if (error) 774 goto out; 775 776 label_type = fp->f_type; 777 switch (fp->f_type) { 778 case DTYPE_FIFO: 779 case DTYPE_VNODE: 780 vp = fp->f_vnode; 781 intlabel = mac_vnode_label_alloc(); 782 mtx_lock(&Giant); /* VFS */ 783 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); 784 mac_copy_vnode_label(vp->v_label, intlabel); 785 VOP_UNLOCK(vp, 0, td); 786 mtx_unlock(&Giant); /* VFS */ 787 error = mac_externalize_vnode_label(intlabel, elements, 788 buffer, mac.m_buflen); 789 mac_vnode_label_free(intlabel); 790 break; 791 792 case DTYPE_PIPE: 793 pipe = fp->f_data; 794 intlabel = mac_pipe_label_alloc(); 795 PIPE_LOCK(pipe); 796 mac_copy_pipe_label(pipe->pipe_pair->pp_label, intlabel); 797 PIPE_UNLOCK(pipe); 798 error = mac_externalize_pipe_label(intlabel, elements, 799 buffer, mac.m_buflen); 800 mac_pipe_label_free(intlabel); 801 break; 802 803 case DTYPE_SOCKET: 804 so = fp->f_data; 805 intlabel = mac_socket_label_alloc(M_WAITOK); 806 NET_LOCK_GIANT(); 807 SOCK_LOCK(so); 808 mac_copy_socket_label(so->so_label, intlabel); 809 SOCK_UNLOCK(so); 810 NET_UNLOCK_GIANT(); 811 error = mac_externalize_socket_label(intlabel, elements, 812 buffer, mac.m_buflen); 813 mac_socket_label_free(intlabel); 814 break; 815 816 default: 817 error = EINVAL; 818 } 819 fdrop(fp, td); 820 if (error == 0) 821 error = copyout(buffer, mac.m_string, strlen(buffer)+1); 822 823 out: 824 free(buffer, M_MACTEMP); 825 free(elements, M_MACTEMP); 826 return (error); 827 } 828 829 /* 830 * MPSAFE 831 */ 832 int 833 __mac_get_file(struct thread *td, struct __mac_get_file_args *uap) 834 { 835 char *elements, *buffer; 836 struct nameidata nd; 837 struct label *intlabel; 838 struct mac mac; 839 int error; 840 841 error = copyin(uap->mac_p, &mac, sizeof(mac)); 842 if (error) 843 return (error); 844 845 error = mac_check_structmac_consistent(&mac); 846 if (error) 847 return (error); 848 849 elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 850 error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL); 851 if (error) { 852 free(elements, M_MACTEMP); 853 return (error); 854 } 855 856 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); 857 mtx_lock(&Giant); /* VFS */ 858 NDINIT(&nd, LOOKUP, LOCKLEAF | FOLLOW, UIO_USERSPACE, uap->path_p, 859 td); 860 error = namei(&nd); 861 if (error) 862 goto out; 863 864 intlabel = mac_vnode_label_alloc(); 865 mac_copy_vnode_label(nd.ni_vp->v_label, intlabel); 866 error = mac_externalize_vnode_label(intlabel, elements, buffer, 867 mac.m_buflen); 868 869 NDFREE(&nd, 0); 870 mac_vnode_label_free(intlabel); 871 872 if (error == 0) 873 error = copyout(buffer, mac.m_string, strlen(buffer)+1); 874 875 out: 876 mtx_unlock(&Giant); /* VFS */ 877 878 free(buffer, M_MACTEMP); 879 free(elements, M_MACTEMP); 880 881 return (error); 882 } 883 884 /* 885 * MPSAFE 886 */ 887 int 888 __mac_get_link(struct thread *td, struct __mac_get_link_args *uap) 889 { 890 char *elements, *buffer; 891 struct nameidata nd; 892 struct label *intlabel; 893 struct mac mac; 894 int error; 895 896 error = copyin(uap->mac_p, &mac, sizeof(mac)); 897 if (error) 898 return (error); 899 900 error = mac_check_structmac_consistent(&mac); 901 if (error) 902 return (error); 903 904 elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 905 error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL); 906 if (error) { 907 free(elements, M_MACTEMP); 908 return (error); 909 } 910 911 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); 912 mtx_lock(&Giant); /* VFS */ 913 NDINIT(&nd, LOOKUP, LOCKLEAF | NOFOLLOW, UIO_USERSPACE, uap->path_p, 914 td); 915 error = namei(&nd); 916 if (error) 917 goto out; 918 919 intlabel = mac_vnode_label_alloc(); 920 mac_copy_vnode_label(nd.ni_vp->v_label, intlabel); 921 error = mac_externalize_vnode_label(intlabel, elements, buffer, 922 mac.m_buflen); 923 NDFREE(&nd, 0); 924 mac_vnode_label_free(intlabel); 925 926 if (error == 0) 927 error = copyout(buffer, mac.m_string, strlen(buffer)+1); 928 929 out: 930 mtx_unlock(&Giant); /* VFS */ 931 932 free(buffer, M_MACTEMP); 933 free(elements, M_MACTEMP); 934 935 return (error); 936 } 937 938 /* 939 * MPSAFE 940 */ 941 int 942 __mac_set_fd(struct thread *td, struct __mac_set_fd_args *uap) 943 { 944 struct label *intlabel; 945 struct pipe *pipe; 946 struct socket *so; 947 struct file *fp; 948 struct mount *mp; 949 struct vnode *vp; 950 struct mac mac; 951 char *buffer; 952 int error; 953 954 error = copyin(uap->mac_p, &mac, sizeof(mac)); 955 if (error) 956 return (error); 957 958 error = mac_check_structmac_consistent(&mac); 959 if (error) 960 return (error); 961 962 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 963 error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL); 964 if (error) { 965 free(buffer, M_MACTEMP); 966 return (error); 967 } 968 969 error = fget(td, uap->fd, &fp); 970 if (error) 971 goto out; 972 973 switch (fp->f_type) { 974 case DTYPE_FIFO: 975 case DTYPE_VNODE: 976 intlabel = mac_vnode_label_alloc(); 977 error = mac_internalize_vnode_label(intlabel, buffer); 978 if (error) { 979 mac_vnode_label_free(intlabel); 980 break; 981 } 982 vp = fp->f_vnode; 983 mtx_lock(&Giant); /* VFS */ 984 error = vn_start_write(vp, &mp, V_WAIT | PCATCH); 985 if (error != 0) { 986 mtx_unlock(&Giant); /* VFS */ 987 mac_vnode_label_free(intlabel); 988 break; 989 } 990 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); 991 error = vn_setlabel(vp, intlabel, td->td_ucred); 992 VOP_UNLOCK(vp, 0, td); 993 vn_finished_write(mp); 994 mtx_unlock(&Giant); /* VFS */ 995 mac_vnode_label_free(intlabel); 996 break; 997 998 case DTYPE_PIPE: 999 intlabel = mac_pipe_label_alloc(); 1000 error = mac_internalize_pipe_label(intlabel, buffer); 1001 if (error == 0) { 1002 pipe = fp->f_data; 1003 PIPE_LOCK(pipe); 1004 error = mac_pipe_label_set(td->td_ucred, 1005 pipe->pipe_pair, intlabel); 1006 PIPE_UNLOCK(pipe); 1007 } 1008 mac_pipe_label_free(intlabel); 1009 break; 1010 1011 case DTYPE_SOCKET: 1012 intlabel = mac_socket_label_alloc(M_WAITOK); 1013 error = mac_internalize_socket_label(intlabel, buffer); 1014 if (error == 0) { 1015 so = fp->f_data; 1016 NET_LOCK_GIANT(); 1017 error = mac_socket_label_set(td->td_ucred, so, 1018 intlabel); 1019 NET_UNLOCK_GIANT(); 1020 } 1021 mac_socket_label_free(intlabel); 1022 break; 1023 1024 default: 1025 error = EINVAL; 1026 } 1027 fdrop(fp, td); 1028 out: 1029 free(buffer, M_MACTEMP); 1030 return (error); 1031 } 1032 1033 /* 1034 * MPSAFE 1035 */ 1036 int 1037 __mac_set_file(struct thread *td, struct __mac_set_file_args *uap) 1038 { 1039 struct label *intlabel; 1040 struct nameidata nd; 1041 struct mount *mp; 1042 struct mac mac; 1043 char *buffer; 1044 int error; 1045 1046 error = copyin(uap->mac_p, &mac, sizeof(mac)); 1047 if (error) 1048 return (error); 1049 1050 error = mac_check_structmac_consistent(&mac); 1051 if (error) 1052 return (error); 1053 1054 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 1055 error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL); 1056 if (error) { 1057 free(buffer, M_MACTEMP); 1058 return (error); 1059 } 1060 1061 intlabel = mac_vnode_label_alloc(); 1062 error = mac_internalize_vnode_label(intlabel, buffer); 1063 free(buffer, M_MACTEMP); 1064 if (error) 1065 goto out; 1066 1067 mtx_lock(&Giant); /* VFS */ 1068 1069 NDINIT(&nd, LOOKUP, LOCKLEAF | FOLLOW, UIO_USERSPACE, uap->path_p, 1070 td); 1071 error = namei(&nd); 1072 if (error == 0) { 1073 error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH); 1074 if (error == 0) 1075 error = vn_setlabel(nd.ni_vp, intlabel, 1076 td->td_ucred); 1077 vn_finished_write(mp); 1078 } 1079 1080 NDFREE(&nd, 0); 1081 mtx_unlock(&Giant); /* VFS */ 1082 out: 1083 mac_vnode_label_free(intlabel); 1084 return (error); 1085 } 1086 1087 /* 1088 * MPSAFE 1089 */ 1090 int 1091 __mac_set_link(struct thread *td, struct __mac_set_link_args *uap) 1092 { 1093 struct label *intlabel; 1094 struct nameidata nd; 1095 struct mount *mp; 1096 struct mac mac; 1097 char *buffer; 1098 int error; 1099 1100 error = copyin(uap->mac_p, &mac, sizeof(mac)); 1101 if (error) 1102 return (error); 1103 1104 error = mac_check_structmac_consistent(&mac); 1105 if (error) 1106 return (error); 1107 1108 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 1109 error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL); 1110 if (error) { 1111 free(buffer, M_MACTEMP); 1112 return (error); 1113 } 1114 1115 intlabel = mac_vnode_label_alloc(); 1116 error = mac_internalize_vnode_label(intlabel, buffer); 1117 free(buffer, M_MACTEMP); 1118 if (error) 1119 goto out; 1120 1121 mtx_lock(&Giant); /* VFS */ 1122 1123 NDINIT(&nd, LOOKUP, LOCKLEAF | NOFOLLOW, UIO_USERSPACE, uap->path_p, 1124 td); 1125 error = namei(&nd); 1126 if (error == 0) { 1127 error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH); 1128 if (error == 0) 1129 error = vn_setlabel(nd.ni_vp, intlabel, 1130 td->td_ucred); 1131 vn_finished_write(mp); 1132 } 1133 1134 NDFREE(&nd, 0); 1135 mtx_unlock(&Giant); /* VFS */ 1136 out: 1137 mac_vnode_label_free(intlabel); 1138 return (error); 1139 } 1140 1141 /* 1142 * MPSAFE 1143 */ 1144 int 1145 mac_syscall(struct thread *td, struct mac_syscall_args *uap) 1146 { 1147 struct mac_policy_conf *mpc; 1148 char target[MAC_MAX_POLICY_NAME]; 1149 int entrycount, error; 1150 1151 error = copyinstr(uap->policy, target, sizeof(target), NULL); 1152 if (error) 1153 return (error); 1154 1155 error = ENOSYS; 1156 LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) { 1157 if (strcmp(mpc->mpc_name, target) == 0 && 1158 mpc->mpc_ops->mpo_syscall != NULL) { 1159 error = mpc->mpc_ops->mpo_syscall(td, 1160 uap->call, uap->arg); 1161 goto out; 1162 } 1163 } 1164 1165 if ((entrycount = mac_policy_list_conditional_busy()) != 0) { 1166 LIST_FOREACH(mpc, &mac_policy_list, mpc_list) { 1167 if (strcmp(mpc->mpc_name, target) == 0 && 1168 mpc->mpc_ops->mpo_syscall != NULL) { 1169 error = mpc->mpc_ops->mpo_syscall(td, 1170 uap->call, uap->arg); 1171 break; 1172 } 1173 } 1174 mac_policy_list_unbusy(); 1175 } 1176 out: 1177 return (error); 1178 } 1179 1180 SYSINIT(mac, SI_SUB_MAC, SI_ORDER_FIRST, mac_init, NULL); 1181 SYSINIT(mac_late, SI_SUB_MAC_LATE, SI_ORDER_FIRST, mac_late_init, NULL); 1182 1183 #else /* !MAC */ 1184 1185 int 1186 __mac_get_pid(struct thread *td, struct __mac_get_pid_args *uap) 1187 { 1188 1189 return (ENOSYS); 1190 } 1191 1192 int 1193 __mac_get_proc(struct thread *td, struct __mac_get_proc_args *uap) 1194 { 1195 1196 return (ENOSYS); 1197 } 1198 1199 int 1200 __mac_set_proc(struct thread *td, struct __mac_set_proc_args *uap) 1201 { 1202 1203 return (ENOSYS); 1204 } 1205 1206 int 1207 __mac_get_fd(struct thread *td, struct __mac_get_fd_args *uap) 1208 { 1209 1210 return (ENOSYS); 1211 } 1212 1213 int 1214 __mac_get_file(struct thread *td, struct __mac_get_file_args *uap) 1215 { 1216 1217 return (ENOSYS); 1218 } 1219 1220 int 1221 __mac_get_link(struct thread *td, struct __mac_get_link_args *uap) 1222 { 1223 1224 return (ENOSYS); 1225 } 1226 1227 int 1228 __mac_set_fd(struct thread *td, struct __mac_set_fd_args *uap) 1229 { 1230 1231 return (ENOSYS); 1232 } 1233 1234 int 1235 __mac_set_file(struct thread *td, struct __mac_set_file_args *uap) 1236 { 1237 1238 return (ENOSYS); 1239 } 1240 1241 int 1242 __mac_set_link(struct thread *td, struct __mac_set_link_args *uap) 1243 { 1244 1245 return (ENOSYS); 1246 } 1247 1248 int 1249 mac_syscall(struct thread *td, struct mac_syscall_args *uap) 1250 { 1251 1252 return (ENOSYS); 1253 } 1254 1255 #endif /* !MAC */ 1256