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