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