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