1 /*- 2 * Copyright (c) 1999-2002, 2006, 2009 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 * Copyright (c) 2008 Apple Inc. 7 * All rights reserved. 8 * 9 * This software was developed by Robert Watson and Ilmar Habibulin for the 10 * TrustedBSD Project. 11 * 12 * This software was developed for the FreeBSD Project in part by Network 13 * Associates Laboratories, the Security Research Division of Network 14 * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), 15 * as part of the DARPA CHATS research program. 16 * 17 * This software was enhanced by SPARTA ISSO under SPAWAR contract 18 * N66001-04-C-6019 ("SEFOS"). 19 * 20 * This software was developed at the University of Cambridge Computer 21 * Laboratory with support from a grant from Google, Inc. 22 * 23 * Redistribution and use in source and binary forms, with or without 24 * modification, are permitted provided that the following conditions 25 * are met: 26 * 1. Redistributions of source code must retain the above copyright 27 * notice, this list of conditions and the following disclaimer. 28 * 2. Redistributions in binary form must reproduce the above copyright 29 * notice, this list of conditions and the following disclaimer in the 30 * documentation and/or other materials provided with the distribution. 31 * 32 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 33 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 34 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 35 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 36 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 37 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 38 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 39 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 40 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 41 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 42 * SUCH DAMAGE. 43 */ 44 45 #include <sys/cdefs.h> 46 #include "opt_mac.h" 47 48 #include <sys/param.h> 49 #include <sys/abi_compat.h> 50 #include <sys/capsicum.h> 51 #include <sys/fcntl.h> 52 #include <sys/jail.h> 53 #include <sys/jaildesc.h> 54 #include <sys/kernel.h> 55 #include <sys/lock.h> 56 #include <sys/malloc.h> 57 #include <sys/mutex.h> 58 #include <sys/mac.h> 59 #include <sys/proc.h> 60 #include <sys/systm.h> 61 #include <sys/sysctl.h> 62 #include <sys/sysent.h> 63 #include <sys/sysproto.h> 64 #include <sys/vnode.h> 65 #include <sys/mount.h> 66 #include <sys/file.h> 67 #include <sys/namei.h> 68 #include <sys/socket.h> 69 #include <sys/pipe.h> 70 #include <sys/socketvar.h> 71 72 #include <security/mac/mac_framework.h> 73 #include <security/mac/mac_internal.h> 74 #include <security/mac/mac_policy.h> 75 #include <security/mac/mac_syscalls.h> 76 77 #ifdef MAC 78 79 FEATURE(security_mac, "Mandatory Access Control Framework support"); 80 81 static int kern___mac_get_path(struct thread *td, const char *path_p, 82 struct mac *mac_p, int follow); 83 static int kern___mac_set_path(struct thread *td, const char *path_p, 84 struct mac *mac_p, int follow); 85 86 #ifdef COMPAT_FREEBSD32 87 struct mac32 { 88 uint32_t m_buflen; /* size_t */ 89 uint32_t m_string; /* char * */ 90 }; 91 #endif 92 93 static int 94 mac_label_copyin_string(struct mac *const mac, char **const u_string, 95 int flag) 96 { 97 char *buffer; 98 int error; 99 100 error = mac_check_structmac_consistent(mac); 101 if (error != 0) 102 return (error); 103 104 /* 'm_buflen' not too big checked by function call above. */ 105 buffer = malloc(mac->m_buflen, M_MACTEMP, flag); 106 if (buffer == NULL) 107 return (ENOMEM); 108 109 error = copyinstr(mac->m_string, buffer, mac->m_buflen, NULL); 110 if (error != 0) { 111 free(buffer, M_MACTEMP); 112 return (error); 113 } 114 115 MPASS(error == 0); 116 if (u_string != NULL) 117 *u_string = mac->m_string; 118 mac->m_string = buffer; 119 return (0); 120 } 121 122 /* 123 * Copyin a 'struct mac', including the string pointed to by 'm_string'. 124 * 125 * On success (0 returned), fills '*mac', whose associated storage must be freed 126 * after use by calling free_copied_label() (which see). On success, 'u_string' 127 * if not NULL is filled with the userspace address for 'u_mac->m_string'. 128 */ 129 int 130 mac_label_copyin(const void *const u_mac, struct mac *const mac, 131 char **const u_string) 132 { 133 int error; 134 135 #ifdef COMPAT_FREEBSD32 136 if (SV_CURPROC_FLAG(SV_ILP32)) { 137 struct mac32 mac32; 138 139 error = copyin(u_mac, &mac32, sizeof(mac32)); 140 if (error != 0) 141 return (error); 142 143 CP(mac32, *mac, m_buflen); 144 PTRIN_CP(mac32, *mac, m_string); 145 } else 146 #endif 147 { 148 error = copyin(u_mac, mac, sizeof(*mac)); 149 if (error != 0) 150 return (error); 151 } 152 153 return (mac_label_copyin_string(mac, u_string, M_WAITOK)); 154 } 155 156 void 157 free_copied_label(const struct mac *const mac) 158 { 159 free(mac->m_string, M_MACTEMP); 160 } 161 162 int 163 sys___mac_get_pid(struct thread *td, struct __mac_get_pid_args *uap) 164 { 165 char *buffer, *u_buffer; 166 struct mac mac; 167 struct proc *tproc; 168 struct ucred *tcred; 169 int error; 170 171 error = mac_label_copyin(uap->mac_p, &mac, &u_buffer); 172 if (error) 173 return (error); 174 175 tproc = pfind(uap->pid); 176 if (tproc == NULL) { 177 error = ESRCH; 178 goto free_mac_and_exit; 179 } 180 181 tcred = NULL; /* Satisfy gcc. */ 182 error = p_cansee(td, tproc); 183 if (error == 0) 184 tcred = crhold(tproc->p_ucred); 185 PROC_UNLOCK(tproc); 186 if (error) 187 goto free_mac_and_exit; 188 189 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); 190 error = mac_cred_externalize_label(tcred->cr_label, mac.m_string, 191 buffer, mac.m_buflen); 192 if (error == 0) 193 error = copyout(buffer, u_buffer, strlen(buffer)+1); 194 free(buffer, M_MACTEMP); 195 crfree(tcred); 196 197 free_mac_and_exit: 198 free_copied_label(&mac); 199 return (error); 200 } 201 202 int 203 sys___mac_get_proc(struct thread *td, struct __mac_get_proc_args *uap) 204 { 205 char *buffer, *u_buffer; 206 struct mac mac; 207 int error; 208 209 error = mac_label_copyin(uap->mac_p, &mac, &u_buffer); 210 if (error) 211 return (error); 212 213 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); 214 error = mac_cred_externalize_label(td->td_ucred->cr_label, 215 mac.m_string, buffer, mac.m_buflen); 216 if (error == 0) 217 error = copyout(buffer, u_buffer, strlen(buffer)+1); 218 219 free(buffer, M_MACTEMP); 220 free_copied_label(&mac); 221 return (error); 222 } 223 224 /* 225 * Performs preparation (including allocations) for mac_set_proc(). 226 * 227 * No lock should be held while calling this function. On success, 228 * mac_set_proc_finish() must be called to free the data associated to 229 * 'mac_set_proc_data', even if mac_set_proc_core() fails. 'mac_set_proc_data' 230 * is not set in case of error, and is set to a non-NULL value on success. 231 */ 232 int 233 mac_set_proc_prepare(struct thread *const td, const struct mac *const mac, 234 void **const mac_set_proc_data) 235 { 236 struct label *intlabel; 237 int error; 238 239 PROC_LOCK_ASSERT(td->td_proc, MA_NOTOWNED); 240 241 if (!(mac_labeled & MPC_OBJECT_CRED)) 242 return (EINVAL); 243 244 intlabel = mac_cred_label_alloc(); 245 error = mac_cred_internalize_label(intlabel, mac->m_string); 246 if (error) { 247 mac_cred_label_free(intlabel); 248 return (error); 249 } 250 251 *mac_set_proc_data = intlabel; 252 return (0); 253 } 254 255 /* 256 * Actually sets the MAC label on 'newcred'. 257 * 258 * The current process' lock *must* be held. This function only sets the label 259 * on 'newcred', but does not put 'newcred' in place on the current process' 260 * (consequently, it also does not call setsugid()). 'mac_set_proc_data' must 261 * be the pointer returned by mac_set_proc_prepare(). If called, this function 262 * must be so between a successful call to mac_set_proc_prepare() and 263 * mac_set_proc_finish(), but calling it is not mandatory (e.g., if some other 264 * error occured under the process lock that obsoletes setting the MAC label). 265 */ 266 int 267 mac_set_proc_core(struct thread *const td, struct ucred *const newcred, 268 void *const mac_set_proc_data) 269 { 270 struct label *const intlabel = mac_set_proc_data; 271 struct proc *const p = td->td_proc; 272 int error; 273 274 MPASS(td == curthread); 275 PROC_LOCK_ASSERT(p, MA_OWNED); 276 277 error = mac_cred_check_relabel(p->p_ucred, intlabel); 278 if (error) 279 return (error); 280 281 mac_cred_relabel(newcred, intlabel); 282 return (0); 283 } 284 285 /* 286 * Performs mac_set_proc() last operations, without the process lock. 287 * 288 * 'proc_label_set' indicates whether the label was actually set by a call to 289 * mac_set_proc_core() that succeeded. 'mac_set_proc_data' must be the pointer 290 * returned by mac_set_proc_prepare(), and its associated data will be freed. 291 */ 292 void 293 mac_set_proc_finish(struct thread *const td, bool proc_label_set, 294 void *const mac_set_proc_data) 295 { 296 struct label *const intlabel = mac_set_proc_data; 297 298 PROC_LOCK_ASSERT(td->td_proc, MA_NOTOWNED); 299 300 if (proc_label_set) 301 mac_proc_vm_revoke(td); 302 mac_cred_label_free(intlabel); 303 } 304 305 int 306 mac_get_prison(struct thread *const td, struct prison *pr, 307 struct vfsoptlist *opts) 308 { 309 char *buffer = NULL, *u_buffer; 310 struct label *intlabel = NULL; 311 struct mac mac; 312 int error; 313 bool locked = true; 314 315 mtx_assert(&pr->pr_mtx, MA_OWNED); 316 #ifdef COMPAT_FREEBSD32 317 if (SV_PROC_FLAG(td->td_proc, SV_ILP32)) { 318 struct mac32 mac32; 319 320 error = vfs_copyopt(opts, "mac.label", &mac32, sizeof(mac32)); 321 if (error == 0) { 322 CP(mac32, mac, m_buflen); 323 PTRIN_CP(mac32, mac, m_string); 324 } 325 } else 326 #endif 327 error = vfs_copyopt(opts, "mac.label", &mac, sizeof(mac)); 328 if (error) { 329 if (error != ENOENT) 330 vfs_opterror(opts, "bad mac.label"); 331 goto out_nomac; 332 } 333 334 intlabel = mac_prison_label_alloc(M_NOWAIT); 335 if (intlabel == NULL) { 336 error = ENOMEM; 337 goto out; 338 } 339 340 if ((mac_labeled & MPC_OBJECT_PRISON) != 0) 341 mac_prison_copy_label(pr->pr_label, intlabel); 342 343 /* 344 * Externalization may want to acquire an rmlock. We already tapped out 345 * a copy of the label from when the jail_get(2) operation started and 346 * we're expected to be called near the end of jail_get(2) when the lock 347 * is about to be dropped anyways, so this is safe. 348 */ 349 mtx_unlock(&pr->pr_mtx); 350 locked = false; 351 352 error = mac_label_copyin_string(&mac, &u_buffer, M_WAITOK); 353 if (error) { 354 vfs_opterror(opts, "mac.label: string copy failure"); 355 goto out; 356 } 357 358 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); 359 if (buffer == NULL) { 360 error = ENOMEM; 361 goto out; 362 } 363 364 error = mac_prison_externalize_label(intlabel, mac.m_string, 365 buffer, mac.m_buflen); 366 367 if (error == 0) 368 error = copyout(buffer, u_buffer, strlen(buffer)+1); 369 370 out: 371 mac_prison_label_free(intlabel); 372 free_copied_label(&mac); 373 free(buffer, M_MACTEMP); 374 375 out_nomac: 376 if (locked) { 377 MPASS(error != 0); 378 mtx_unlock(&pr->pr_mtx); 379 } 380 381 return (error); 382 } 383 384 int 385 mac_set_prison_prepare(struct thread *const td, struct vfsoptlist *opts, 386 void **const mac_set_prison_data) 387 { 388 struct mac mac; 389 struct label *intlabel; 390 int error; 391 392 #ifdef COMPAT_FREEBSD32 393 if (SV_PROC_FLAG(td->td_proc, SV_ILP32)) { 394 struct mac32 mac32; 395 396 error = vfs_copyopt(opts, "mac.label", &mac32, sizeof(mac32)); 397 if (error == 0) { 398 CP(mac32, mac, m_buflen); 399 PTRIN_CP(mac32, mac, m_string); 400 } 401 } else 402 #endif 403 error = vfs_copyopt(opts, "mac.label", &mac, sizeof(mac)); 404 if (error) { 405 if (error != ENOENT) 406 vfs_opterror(opts, "bad mac.label"); 407 return (error); 408 } 409 410 error = mac_label_copyin_string(&mac, NULL, M_WAITOK); 411 if (error) { 412 vfs_opterror(opts, "mac.label: string copy failure"); 413 return (error); 414 } 415 416 /* 417 * If the option wasn't set, then we return ENOENT above. If we don't 418 * have any policies applicable to prisons, we can return EINVAL early. 419 */ 420 if (!(mac_labeled & MPC_OBJECT_PRISON)) { 421 vfs_opterror(opts, "no labelled jail policies"); 422 return (EINVAL); 423 } 424 425 intlabel = mac_prison_label_alloc(M_WAITOK); 426 error = mac_prison_internalize_label(intlabel, mac.m_string); 427 if (error) { 428 mac_prison_label_free(intlabel); 429 vfs_opterror(opts, "internalize_label error"); 430 return (error); 431 } 432 433 *mac_set_prison_data = intlabel; 434 return (0); 435 } 436 437 int 438 mac_set_prison_core(struct thread *const td, struct prison *pr, 439 void *const mac_set_prison_data) 440 { 441 struct label *const intlabel = mac_set_prison_data; 442 443 return (mac_prison_label_set(td->td_ucred, pr, intlabel)); 444 } 445 446 void 447 mac_set_prison_finish(struct thread *const td, bool prison_label_set __unused, 448 void *const mac_set_prison_data) 449 { 450 struct label *const intlabel = mac_set_prison_data; 451 452 mac_prison_label_free(intlabel); 453 } 454 455 int 456 sys___mac_set_proc(struct thread *td, struct __mac_set_proc_args *uap) 457 { 458 struct ucred *newcred, *oldcred; 459 void *intlabel; 460 struct proc *const p = td->td_proc; 461 struct mac mac; 462 int error; 463 464 error = mac_label_copyin(uap->mac_p, &mac, NULL); 465 if (error) 466 return (error); 467 468 error = mac_set_proc_prepare(td, &mac, &intlabel); 469 if (error) 470 goto free_label; 471 472 newcred = crget(); 473 474 PROC_LOCK(p); 475 oldcred = p->p_ucred; 476 crcopy(newcred, oldcred); 477 478 error = mac_set_proc_core(td, newcred, intlabel); 479 if (error) { 480 PROC_UNLOCK(p); 481 crfree(newcred); 482 goto finish; 483 } 484 485 setsugid(p); 486 proc_set_cred(p, newcred); 487 PROC_UNLOCK(p); 488 489 crfree(oldcred); 490 finish: 491 mac_set_proc_finish(td, error == 0, intlabel); 492 free_label: 493 free_copied_label(&mac); 494 return (error); 495 } 496 497 int 498 sys___mac_get_fd(struct thread *td, struct __mac_get_fd_args *uap) 499 { 500 char *u_buffer, *buffer; 501 struct label *intlabel; 502 struct file *fp; 503 struct mac mac; 504 struct vnode *vp; 505 struct pipe *pipe; 506 struct prison *pr; 507 struct socket *so; 508 cap_rights_t rights; 509 int error; 510 511 error = mac_label_copyin(uap->mac_p, &mac, &u_buffer); 512 if (error) 513 return (error); 514 515 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); 516 error = fget(td, uap->fd, cap_rights_init_one(&rights, CAP_MAC_GET), 517 &fp); 518 if (error) 519 goto out; 520 521 switch (fp->f_type) { 522 case DTYPE_FIFO: 523 case DTYPE_VNODE: 524 if (!(mac_labeled & MPC_OBJECT_VNODE)) { 525 error = EINVAL; 526 goto out_fdrop; 527 } 528 vp = fp->f_vnode; 529 intlabel = mac_vnode_label_alloc(); 530 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 531 mac_vnode_copy_label(vp->v_label, intlabel); 532 VOP_UNLOCK(vp); 533 error = mac_vnode_externalize_label(intlabel, mac.m_string, 534 buffer, mac.m_buflen); 535 mac_vnode_label_free(intlabel); 536 break; 537 538 case DTYPE_PIPE: 539 if (!(mac_labeled & MPC_OBJECT_PIPE)) { 540 error = EINVAL; 541 goto out_fdrop; 542 } 543 pipe = fp->f_data; 544 intlabel = mac_pipe_label_alloc(); 545 PIPE_LOCK(pipe); 546 mac_pipe_copy_label(pipe->pipe_pair->pp_label, intlabel); 547 PIPE_UNLOCK(pipe); 548 error = mac_pipe_externalize_label(intlabel, mac.m_string, 549 buffer, mac.m_buflen); 550 mac_pipe_label_free(intlabel); 551 break; 552 553 case DTYPE_SOCKET: 554 if (!(mac_labeled & MPC_OBJECT_SOCKET)) { 555 error = EINVAL; 556 goto out_fdrop; 557 } 558 so = fp->f_data; 559 intlabel = mac_socket_label_alloc(M_WAITOK); 560 SOCK_LOCK(so); 561 mac_socket_copy_label(so->so_label, intlabel); 562 SOCK_UNLOCK(so); 563 error = mac_socket_externalize_label(intlabel, mac.m_string, 564 buffer, mac.m_buflen); 565 mac_socket_label_free(intlabel); 566 break; 567 568 case DTYPE_JAILDESC: 569 if (!(mac_labeled & MPC_OBJECT_PRISON)) { 570 error = EINVAL; 571 goto out_fdrop; 572 } 573 574 error = jaildesc_get_prison(fp, &pr); 575 if (error != 0) 576 goto out_fdrop; 577 578 intlabel = mac_prison_label_alloc(M_WAITOK); 579 mac_prison_copy_label(pr->pr_label, intlabel); 580 prison_free(pr); 581 582 error = mac_prison_externalize_label(intlabel, mac.m_string, 583 buffer, mac.m_buflen); 584 mac_prison_label_free(intlabel); 585 break; 586 587 default: 588 error = EINVAL; 589 } 590 if (error == 0) 591 error = copyout(buffer, u_buffer, strlen(buffer)+1); 592 out_fdrop: 593 fdrop(fp, td); 594 out: 595 free(buffer, M_MACTEMP); 596 free_copied_label(&mac); 597 return (error); 598 } 599 600 int 601 sys___mac_get_file(struct thread *td, struct __mac_get_file_args *uap) 602 { 603 604 return (kern___mac_get_path(td, uap->path_p, uap->mac_p, FOLLOW)); 605 } 606 607 int 608 sys___mac_get_link(struct thread *td, struct __mac_get_link_args *uap) 609 { 610 611 return (kern___mac_get_path(td, uap->path_p, uap->mac_p, NOFOLLOW)); 612 } 613 614 static int 615 kern___mac_get_path(struct thread *td, const char *path_p, struct mac *mac_p, 616 int follow) 617 { 618 char *u_buffer, *buffer; 619 struct nameidata nd; 620 struct label *intlabel; 621 struct mac mac; 622 int error; 623 624 if (!(mac_labeled & MPC_OBJECT_VNODE)) 625 return (EINVAL); 626 627 error = mac_label_copyin(mac_p, &mac, &u_buffer); 628 if (error) 629 return (error); 630 631 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); 632 NDINIT(&nd, LOOKUP, LOCKLEAF | follow, UIO_USERSPACE, path_p); 633 error = namei(&nd); 634 if (error) 635 goto out; 636 637 intlabel = mac_vnode_label_alloc(); 638 mac_vnode_copy_label(nd.ni_vp->v_label, intlabel); 639 error = mac_vnode_externalize_label(intlabel, mac.m_string, buffer, 640 mac.m_buflen); 641 vput(nd.ni_vp); 642 NDFREE_PNBUF(&nd); 643 mac_vnode_label_free(intlabel); 644 645 if (error == 0) 646 error = copyout(buffer, u_buffer, strlen(buffer)+1); 647 648 out: 649 free(buffer, M_MACTEMP); 650 free_copied_label(&mac); 651 652 return (error); 653 } 654 655 int 656 sys___mac_set_fd(struct thread *td, struct __mac_set_fd_args *uap) 657 { 658 struct label *intlabel; 659 struct pipe *pipe; 660 struct prison *pr; 661 struct socket *so; 662 struct file *fp; 663 struct mount *mp; 664 struct vnode *vp; 665 struct mac mac; 666 cap_rights_t rights; 667 int error; 668 669 error = mac_label_copyin(uap->mac_p, &mac, NULL); 670 if (error) 671 return (error); 672 673 error = fget(td, uap->fd, cap_rights_init_one(&rights, CAP_MAC_SET), 674 &fp); 675 if (error) 676 goto out; 677 678 switch (fp->f_type) { 679 case DTYPE_FIFO: 680 case DTYPE_VNODE: 681 if (!(mac_labeled & MPC_OBJECT_VNODE)) { 682 error = EINVAL; 683 goto out_fdrop; 684 } 685 intlabel = mac_vnode_label_alloc(); 686 error = mac_vnode_internalize_label(intlabel, mac.m_string); 687 if (error) { 688 mac_vnode_label_free(intlabel); 689 break; 690 } 691 vp = fp->f_vnode; 692 error = vn_start_write(vp, &mp, V_WAIT | V_PCATCH); 693 if (error != 0) { 694 mac_vnode_label_free(intlabel); 695 break; 696 } 697 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 698 error = vn_setlabel(vp, intlabel, td->td_ucred); 699 VOP_UNLOCK(vp); 700 vn_finished_write(mp); 701 mac_vnode_label_free(intlabel); 702 break; 703 704 case DTYPE_PIPE: 705 if (!(mac_labeled & MPC_OBJECT_PIPE)) { 706 error = EINVAL; 707 goto out_fdrop; 708 } 709 intlabel = mac_pipe_label_alloc(); 710 error = mac_pipe_internalize_label(intlabel, mac.m_string); 711 if (error == 0) { 712 pipe = fp->f_data; 713 PIPE_LOCK(pipe); 714 error = mac_pipe_label_set(td->td_ucred, 715 pipe->pipe_pair, intlabel); 716 PIPE_UNLOCK(pipe); 717 } 718 mac_pipe_label_free(intlabel); 719 break; 720 721 case DTYPE_SOCKET: 722 if (!(mac_labeled & MPC_OBJECT_SOCKET)) { 723 error = EINVAL; 724 goto out_fdrop; 725 } 726 intlabel = mac_socket_label_alloc(M_WAITOK); 727 error = mac_socket_internalize_label(intlabel, mac.m_string); 728 if (error == 0) { 729 so = fp->f_data; 730 error = mac_socket_label_set(td->td_ucred, so, 731 intlabel); 732 } 733 mac_socket_label_free(intlabel); 734 break; 735 736 case DTYPE_JAILDESC: 737 if (!(mac_labeled & MPC_OBJECT_PRISON)) { 738 error = EINVAL; 739 goto out_fdrop; 740 } 741 742 pr = NULL; 743 intlabel = mac_prison_label_alloc(M_WAITOK); 744 error = mac_prison_internalize_label(intlabel, mac.m_string); 745 if (error == 0) 746 error = jaildesc_get_prison(fp, &pr); 747 if (error == 0) { 748 prison_lock(pr); 749 error = mac_prison_label_set(td->td_ucred, pr, 750 intlabel); 751 prison_free_locked(pr); 752 } 753 754 mac_prison_label_free(intlabel); 755 break; 756 757 default: 758 error = EINVAL; 759 } 760 out_fdrop: 761 fdrop(fp, td); 762 out: 763 free_copied_label(&mac); 764 return (error); 765 } 766 767 int 768 sys___mac_set_file(struct thread *td, struct __mac_set_file_args *uap) 769 { 770 771 return (kern___mac_set_path(td, uap->path_p, uap->mac_p, FOLLOW)); 772 } 773 774 int 775 sys___mac_set_link(struct thread *td, struct __mac_set_link_args *uap) 776 { 777 778 return (kern___mac_set_path(td, uap->path_p, uap->mac_p, NOFOLLOW)); 779 } 780 781 static int 782 kern___mac_set_path(struct thread *td, const char *path_p, struct mac *mac_p, 783 int follow) 784 { 785 struct label *intlabel; 786 struct nameidata nd; 787 struct mount *mp; 788 struct mac mac; 789 int error; 790 791 if (!(mac_labeled & MPC_OBJECT_VNODE)) 792 return (EINVAL); 793 794 error = mac_label_copyin(mac_p, &mac, NULL); 795 if (error) 796 return (error); 797 798 intlabel = mac_vnode_label_alloc(); 799 error = mac_vnode_internalize_label(intlabel, mac.m_string); 800 free_copied_label(&mac); 801 if (error) 802 goto out; 803 804 NDINIT(&nd, LOOKUP, LOCKLEAF | follow, UIO_USERSPACE, path_p); 805 error = namei(&nd); 806 if (error == 0) { 807 error = vn_start_write(nd.ni_vp, &mp, V_WAIT | V_PCATCH); 808 if (error == 0) { 809 error = vn_setlabel(nd.ni_vp, intlabel, 810 td->td_ucred); 811 vn_finished_write(mp); 812 } 813 vput(nd.ni_vp); 814 NDFREE_PNBUF(&nd); 815 } 816 out: 817 mac_vnode_label_free(intlabel); 818 return (error); 819 } 820 821 int 822 sys_mac_syscall(struct thread *td, struct mac_syscall_args *uap) 823 { 824 struct mac_policy_conf *mpc; 825 char target[MAC_MAX_POLICY_NAME]; 826 int error; 827 828 error = copyinstr(uap->policy, target, sizeof(target), NULL); 829 if (error) 830 return (error); 831 832 error = ENOSYS; 833 LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) { 834 if (strcmp(mpc->mpc_name, target) == 0 && 835 mpc->mpc_ops->mpo_syscall != NULL) { 836 error = mpc->mpc_ops->mpo_syscall(td, 837 uap->call, uap->arg); 838 goto out; 839 } 840 } 841 842 if (!LIST_EMPTY(&mac_policy_list)) { 843 mac_policy_slock_sleep(); 844 LIST_FOREACH(mpc, &mac_policy_list, mpc_list) { 845 if (strcmp(mpc->mpc_name, target) == 0 && 846 mpc->mpc_ops->mpo_syscall != NULL) { 847 error = mpc->mpc_ops->mpo_syscall(td, 848 uap->call, uap->arg); 849 break; 850 } 851 } 852 mac_policy_sunlock_sleep(); 853 } 854 out: 855 return (error); 856 } 857 858 #else /* !MAC */ 859 860 int 861 sys___mac_get_pid(struct thread *td, struct __mac_get_pid_args *uap) 862 { 863 864 return (ENOSYS); 865 } 866 867 int 868 sys___mac_get_proc(struct thread *td, struct __mac_get_proc_args *uap) 869 { 870 871 return (ENOSYS); 872 } 873 874 int 875 sys___mac_set_proc(struct thread *td, struct __mac_set_proc_args *uap) 876 { 877 878 return (ENOSYS); 879 } 880 881 int 882 sys___mac_get_fd(struct thread *td, struct __mac_get_fd_args *uap) 883 { 884 885 return (ENOSYS); 886 } 887 888 int 889 sys___mac_get_file(struct thread *td, struct __mac_get_file_args *uap) 890 { 891 892 return (ENOSYS); 893 } 894 895 int 896 sys___mac_get_link(struct thread *td, struct __mac_get_link_args *uap) 897 { 898 899 return (ENOSYS); 900 } 901 902 int 903 sys___mac_set_fd(struct thread *td, struct __mac_set_fd_args *uap) 904 { 905 906 return (ENOSYS); 907 } 908 909 int 910 sys___mac_set_file(struct thread *td, struct __mac_set_file_args *uap) 911 { 912 913 return (ENOSYS); 914 } 915 916 int 917 sys___mac_set_link(struct thread *td, struct __mac_set_link_args *uap) 918 { 919 920 return (ENOSYS); 921 } 922 923 int 924 sys_mac_syscall(struct thread *td, struct mac_syscall_args *uap) 925 { 926 927 return (ENOSYS); 928 } 929 930 #endif /* !MAC */ 931