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