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 __FBSDID("$FreeBSD$"); 47 48 #include "opt_mac.h" 49 50 #include <sys/param.h> 51 #include <sys/capsicum.h> 52 #include <sys/fcntl.h> 53 #include <sys/kernel.h> 54 #include <sys/lock.h> 55 #include <sys/malloc.h> 56 #include <sys/mutex.h> 57 #include <sys/mac.h> 58 #include <sys/proc.h> 59 #include <sys/systm.h> 60 #include <sys/sysctl.h> 61 #include <sys/sysproto.h> 62 #include <sys/sysent.h> 63 #include <sys/vnode.h> 64 #include <sys/mount.h> 65 #include <sys/file.h> 66 #include <sys/namei.h> 67 #include <sys/socket.h> 68 #include <sys/pipe.h> 69 #include <sys/socketvar.h> 70 71 #include <security/mac/mac_framework.h> 72 #include <security/mac/mac_internal.h> 73 #include <security/mac/mac_policy.h> 74 75 #ifdef MAC 76 77 FEATURE(security_mac, "Mandatory Access Control Framework support"); 78 79 int 80 sys___mac_get_pid(struct thread *td, struct __mac_get_pid_args *uap) 81 { 82 char *elements, *buffer; 83 struct mac mac; 84 struct proc *tproc; 85 struct ucred *tcred; 86 int error; 87 88 error = copyin(uap->mac_p, &mac, sizeof(mac)); 89 if (error) 90 return (error); 91 92 error = mac_check_structmac_consistent(&mac); 93 if (error) 94 return (error); 95 96 tproc = pfind(uap->pid); 97 if (tproc == NULL) 98 return (ESRCH); 99 100 tcred = NULL; /* Satisfy gcc. */ 101 error = p_cansee(td, tproc); 102 if (error == 0) 103 tcred = crhold(tproc->p_ucred); 104 PROC_UNLOCK(tproc); 105 if (error) 106 return (error); 107 108 elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 109 error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL); 110 if (error) { 111 free(elements, M_MACTEMP); 112 crfree(tcred); 113 return (error); 114 } 115 116 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); 117 error = mac_cred_externalize_label(tcred->cr_label, elements, 118 buffer, mac.m_buflen); 119 if (error == 0) 120 error = copyout(buffer, mac.m_string, strlen(buffer)+1); 121 122 free(buffer, M_MACTEMP); 123 free(elements, M_MACTEMP); 124 crfree(tcred); 125 return (error); 126 } 127 128 int 129 sys___mac_get_proc(struct thread *td, struct __mac_get_proc_args *uap) 130 { 131 char *elements, *buffer; 132 struct mac mac; 133 int error; 134 135 error = copyin(uap->mac_p, &mac, sizeof(mac)); 136 if (error) 137 return (error); 138 139 error = mac_check_structmac_consistent(&mac); 140 if (error) 141 return (error); 142 143 elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 144 error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL); 145 if (error) { 146 free(elements, M_MACTEMP); 147 return (error); 148 } 149 150 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); 151 error = mac_cred_externalize_label(td->td_ucred->cr_label, 152 elements, buffer, mac.m_buflen); 153 if (error == 0) 154 error = copyout(buffer, mac.m_string, strlen(buffer)+1); 155 156 free(buffer, M_MACTEMP); 157 free(elements, M_MACTEMP); 158 return (error); 159 } 160 161 int 162 sys___mac_set_proc(struct thread *td, struct __mac_set_proc_args *uap) 163 { 164 struct ucred *newcred, *oldcred; 165 struct label *intlabel; 166 struct proc *p; 167 struct mac mac; 168 char *buffer; 169 int error; 170 171 if (!(mac_labeled & MPC_OBJECT_CRED)) 172 return (EINVAL); 173 174 error = copyin(uap->mac_p, &mac, sizeof(mac)); 175 if (error) 176 return (error); 177 178 error = mac_check_structmac_consistent(&mac); 179 if (error) 180 return (error); 181 182 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 183 error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL); 184 if (error) { 185 free(buffer, M_MACTEMP); 186 return (error); 187 } 188 189 intlabel = mac_cred_label_alloc(); 190 error = mac_cred_internalize_label(intlabel, buffer); 191 free(buffer, M_MACTEMP); 192 if (error) 193 goto out; 194 195 newcred = crget(); 196 197 p = td->td_proc; 198 PROC_LOCK(p); 199 oldcred = p->p_ucred; 200 201 error = mac_cred_check_relabel(oldcred, intlabel); 202 if (error) { 203 PROC_UNLOCK(p); 204 crfree(newcred); 205 goto out; 206 } 207 208 setsugid(p); 209 crcopy(newcred, oldcred); 210 mac_cred_relabel(newcred, intlabel); 211 proc_set_cred(p, newcred); 212 213 PROC_UNLOCK(p); 214 crfree(oldcred); 215 mac_proc_vm_revoke(td); 216 217 out: 218 mac_cred_label_free(intlabel); 219 return (error); 220 } 221 222 int 223 sys___mac_get_fd(struct thread *td, struct __mac_get_fd_args *uap) 224 { 225 char *elements, *buffer; 226 struct label *intlabel; 227 struct file *fp; 228 struct mac mac; 229 struct vnode *vp; 230 struct pipe *pipe; 231 struct socket *so; 232 cap_rights_t rights; 233 short label_type; 234 int error; 235 236 error = copyin(uap->mac_p, &mac, sizeof(mac)); 237 if (error) 238 return (error); 239 240 error = mac_check_structmac_consistent(&mac); 241 if (error) 242 return (error); 243 244 elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 245 error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL); 246 if (error) { 247 free(elements, M_MACTEMP); 248 return (error); 249 } 250 251 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); 252 error = fget(td, uap->fd, cap_rights_init(&rights, CAP_MAC_GET), &fp); 253 if (error) 254 goto out; 255 256 label_type = fp->f_type; 257 switch (fp->f_type) { 258 case DTYPE_FIFO: 259 case DTYPE_VNODE: 260 if (!(mac_labeled & MPC_OBJECT_VNODE)) { 261 error = EINVAL; 262 goto out_fdrop; 263 } 264 vp = fp->f_vnode; 265 intlabel = mac_vnode_label_alloc(); 266 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 267 mac_vnode_copy_label(vp->v_label, intlabel); 268 VOP_UNLOCK(vp, 0); 269 error = mac_vnode_externalize_label(intlabel, elements, 270 buffer, mac.m_buflen); 271 mac_vnode_label_free(intlabel); 272 break; 273 274 case DTYPE_PIPE: 275 if (!(mac_labeled & MPC_OBJECT_PIPE)) { 276 error = EINVAL; 277 goto out_fdrop; 278 } 279 pipe = fp->f_data; 280 intlabel = mac_pipe_label_alloc(); 281 PIPE_LOCK(pipe); 282 mac_pipe_copy_label(pipe->pipe_pair->pp_label, intlabel); 283 PIPE_UNLOCK(pipe); 284 error = mac_pipe_externalize_label(intlabel, elements, 285 buffer, mac.m_buflen); 286 mac_pipe_label_free(intlabel); 287 break; 288 289 case DTYPE_SOCKET: 290 if (!(mac_labeled & MPC_OBJECT_SOCKET)) { 291 error = EINVAL; 292 goto out_fdrop; 293 } 294 so = fp->f_data; 295 intlabel = mac_socket_label_alloc(M_WAITOK); 296 SOCK_LOCK(so); 297 mac_socket_copy_label(so->so_label, intlabel); 298 SOCK_UNLOCK(so); 299 error = mac_socket_externalize_label(intlabel, elements, 300 buffer, mac.m_buflen); 301 mac_socket_label_free(intlabel); 302 break; 303 304 default: 305 error = EINVAL; 306 } 307 if (error == 0) 308 error = copyout(buffer, mac.m_string, strlen(buffer)+1); 309 out_fdrop: 310 fdrop(fp, td); 311 out: 312 free(buffer, M_MACTEMP); 313 free(elements, M_MACTEMP); 314 return (error); 315 } 316 317 int 318 sys___mac_get_file(struct thread *td, struct __mac_get_file_args *uap) 319 { 320 char *elements, *buffer; 321 struct nameidata nd; 322 struct label *intlabel; 323 struct mac mac; 324 int error; 325 326 if (!(mac_labeled & MPC_OBJECT_VNODE)) 327 return (EINVAL); 328 329 error = copyin(uap->mac_p, &mac, sizeof(mac)); 330 if (error) 331 return (error); 332 333 error = mac_check_structmac_consistent(&mac); 334 if (error) 335 return (error); 336 337 elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 338 error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL); 339 if (error) { 340 free(elements, M_MACTEMP); 341 return (error); 342 } 343 344 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); 345 NDINIT(&nd, LOOKUP, LOCKLEAF | FOLLOW, UIO_USERSPACE, 346 uap->path_p, td); 347 error = namei(&nd); 348 if (error) 349 goto out; 350 351 intlabel = mac_vnode_label_alloc(); 352 mac_vnode_copy_label(nd.ni_vp->v_label, intlabel); 353 error = mac_vnode_externalize_label(intlabel, elements, buffer, 354 mac.m_buflen); 355 356 NDFREE(&nd, 0); 357 mac_vnode_label_free(intlabel); 358 if (error == 0) 359 error = copyout(buffer, mac.m_string, strlen(buffer)+1); 360 361 out: 362 free(buffer, M_MACTEMP); 363 free(elements, M_MACTEMP); 364 365 return (error); 366 } 367 368 int 369 sys___mac_get_link(struct thread *td, struct __mac_get_link_args *uap) 370 { 371 char *elements, *buffer; 372 struct nameidata nd; 373 struct label *intlabel; 374 struct mac mac; 375 int error; 376 377 if (!(mac_labeled & MPC_OBJECT_VNODE)) 378 return (EINVAL); 379 380 error = copyin(uap->mac_p, &mac, sizeof(mac)); 381 if (error) 382 return (error); 383 384 error = mac_check_structmac_consistent(&mac); 385 if (error) 386 return (error); 387 388 elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 389 error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL); 390 if (error) { 391 free(elements, M_MACTEMP); 392 return (error); 393 } 394 395 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); 396 NDINIT(&nd, LOOKUP, LOCKLEAF | NOFOLLOW, UIO_USERSPACE, 397 uap->path_p, td); 398 error = namei(&nd); 399 if (error) 400 goto out; 401 402 intlabel = mac_vnode_label_alloc(); 403 mac_vnode_copy_label(nd.ni_vp->v_label, intlabel); 404 error = mac_vnode_externalize_label(intlabel, elements, buffer, 405 mac.m_buflen); 406 NDFREE(&nd, 0); 407 mac_vnode_label_free(intlabel); 408 409 if (error == 0) 410 error = copyout(buffer, mac.m_string, strlen(buffer)+1); 411 412 out: 413 free(buffer, M_MACTEMP); 414 free(elements, M_MACTEMP); 415 416 return (error); 417 } 418 419 int 420 sys___mac_set_fd(struct thread *td, struct __mac_set_fd_args *uap) 421 { 422 struct label *intlabel; 423 struct pipe *pipe; 424 struct socket *so; 425 struct file *fp; 426 struct mount *mp; 427 struct vnode *vp; 428 struct mac mac; 429 cap_rights_t rights; 430 char *buffer; 431 int error; 432 433 error = copyin(uap->mac_p, &mac, sizeof(mac)); 434 if (error) 435 return (error); 436 437 error = mac_check_structmac_consistent(&mac); 438 if (error) 439 return (error); 440 441 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 442 error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL); 443 if (error) { 444 free(buffer, M_MACTEMP); 445 return (error); 446 } 447 448 error = fget(td, uap->fd, cap_rights_init(&rights, CAP_MAC_SET), &fp); 449 if (error) 450 goto out; 451 452 switch (fp->f_type) { 453 case DTYPE_FIFO: 454 case DTYPE_VNODE: 455 if (!(mac_labeled & MPC_OBJECT_VNODE)) { 456 error = EINVAL; 457 goto out_fdrop; 458 } 459 intlabel = mac_vnode_label_alloc(); 460 error = mac_vnode_internalize_label(intlabel, buffer); 461 if (error) { 462 mac_vnode_label_free(intlabel); 463 break; 464 } 465 vp = fp->f_vnode; 466 error = vn_start_write(vp, &mp, V_WAIT | PCATCH); 467 if (error != 0) { 468 mac_vnode_label_free(intlabel); 469 break; 470 } 471 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 472 error = vn_setlabel(vp, intlabel, td->td_ucred); 473 VOP_UNLOCK(vp, 0); 474 vn_finished_write(mp); 475 mac_vnode_label_free(intlabel); 476 break; 477 478 case DTYPE_PIPE: 479 if (!(mac_labeled & MPC_OBJECT_PIPE)) { 480 error = EINVAL; 481 goto out_fdrop; 482 } 483 intlabel = mac_pipe_label_alloc(); 484 error = mac_pipe_internalize_label(intlabel, buffer); 485 if (error == 0) { 486 pipe = fp->f_data; 487 PIPE_LOCK(pipe); 488 error = mac_pipe_label_set(td->td_ucred, 489 pipe->pipe_pair, intlabel); 490 PIPE_UNLOCK(pipe); 491 } 492 mac_pipe_label_free(intlabel); 493 break; 494 495 case DTYPE_SOCKET: 496 if (!(mac_labeled & MPC_OBJECT_SOCKET)) { 497 error = EINVAL; 498 goto out_fdrop; 499 } 500 intlabel = mac_socket_label_alloc(M_WAITOK); 501 error = mac_socket_internalize_label(intlabel, buffer); 502 if (error == 0) { 503 so = fp->f_data; 504 error = mac_socket_label_set(td->td_ucred, so, 505 intlabel); 506 } 507 mac_socket_label_free(intlabel); 508 break; 509 510 default: 511 error = EINVAL; 512 } 513 out_fdrop: 514 fdrop(fp, td); 515 out: 516 free(buffer, M_MACTEMP); 517 return (error); 518 } 519 520 int 521 sys___mac_set_file(struct thread *td, struct __mac_set_file_args *uap) 522 { 523 struct label *intlabel; 524 struct nameidata nd; 525 struct mount *mp; 526 struct mac mac; 527 char *buffer; 528 int error; 529 530 if (!(mac_labeled & MPC_OBJECT_VNODE)) 531 return (EINVAL); 532 533 error = copyin(uap->mac_p, &mac, sizeof(mac)); 534 if (error) 535 return (error); 536 537 error = mac_check_structmac_consistent(&mac); 538 if (error) 539 return (error); 540 541 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 542 error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL); 543 if (error) { 544 free(buffer, M_MACTEMP); 545 return (error); 546 } 547 548 intlabel = mac_vnode_label_alloc(); 549 error = mac_vnode_internalize_label(intlabel, buffer); 550 free(buffer, M_MACTEMP); 551 if (error) 552 goto out; 553 554 NDINIT(&nd, LOOKUP, LOCKLEAF | FOLLOW, UIO_USERSPACE, 555 uap->path_p, td); 556 error = namei(&nd); 557 if (error == 0) { 558 error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH); 559 if (error == 0) { 560 error = vn_setlabel(nd.ni_vp, intlabel, 561 td->td_ucred); 562 vn_finished_write(mp); 563 } 564 } 565 566 NDFREE(&nd, 0); 567 out: 568 mac_vnode_label_free(intlabel); 569 return (error); 570 } 571 572 int 573 sys___mac_set_link(struct thread *td, struct __mac_set_link_args *uap) 574 { 575 struct label *intlabel; 576 struct nameidata nd; 577 struct mount *mp; 578 struct mac mac; 579 char *buffer; 580 int error; 581 582 if (!(mac_labeled & MPC_OBJECT_VNODE)) 583 return (EINVAL); 584 585 error = copyin(uap->mac_p, &mac, sizeof(mac)); 586 if (error) 587 return (error); 588 589 error = mac_check_structmac_consistent(&mac); 590 if (error) 591 return (error); 592 593 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 594 error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL); 595 if (error) { 596 free(buffer, M_MACTEMP); 597 return (error); 598 } 599 600 intlabel = mac_vnode_label_alloc(); 601 error = mac_vnode_internalize_label(intlabel, buffer); 602 free(buffer, M_MACTEMP); 603 if (error) 604 goto out; 605 606 NDINIT(&nd, LOOKUP, LOCKLEAF | NOFOLLOW, UIO_USERSPACE, 607 uap->path_p, td); 608 error = namei(&nd); 609 if (error == 0) { 610 error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH); 611 if (error == 0) { 612 error = vn_setlabel(nd.ni_vp, intlabel, 613 td->td_ucred); 614 vn_finished_write(mp); 615 } 616 } 617 618 NDFREE(&nd, 0); 619 out: 620 mac_vnode_label_free(intlabel); 621 return (error); 622 } 623 624 int 625 sys_mac_syscall(struct thread *td, struct mac_syscall_args *uap) 626 { 627 struct mac_policy_conf *mpc; 628 char target[MAC_MAX_POLICY_NAME]; 629 int error; 630 631 error = copyinstr(uap->policy, target, sizeof(target), NULL); 632 if (error) 633 return (error); 634 635 error = ENOSYS; 636 LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) { 637 if (strcmp(mpc->mpc_name, target) == 0 && 638 mpc->mpc_ops->mpo_syscall != NULL) { 639 error = mpc->mpc_ops->mpo_syscall(td, 640 uap->call, uap->arg); 641 goto out; 642 } 643 } 644 645 if (!LIST_EMPTY(&mac_policy_list)) { 646 mac_policy_slock_sleep(); 647 LIST_FOREACH(mpc, &mac_policy_list, mpc_list) { 648 if (strcmp(mpc->mpc_name, target) == 0 && 649 mpc->mpc_ops->mpo_syscall != NULL) { 650 error = mpc->mpc_ops->mpo_syscall(td, 651 uap->call, uap->arg); 652 break; 653 } 654 } 655 mac_policy_sunlock_sleep(); 656 } 657 out: 658 return (error); 659 } 660 661 #else /* !MAC */ 662 663 int 664 sys___mac_get_pid(struct thread *td, struct __mac_get_pid_args *uap) 665 { 666 667 return (ENOSYS); 668 } 669 670 int 671 sys___mac_get_proc(struct thread *td, struct __mac_get_proc_args *uap) 672 { 673 674 return (ENOSYS); 675 } 676 677 int 678 sys___mac_set_proc(struct thread *td, struct __mac_set_proc_args *uap) 679 { 680 681 return (ENOSYS); 682 } 683 684 int 685 sys___mac_get_fd(struct thread *td, struct __mac_get_fd_args *uap) 686 { 687 688 return (ENOSYS); 689 } 690 691 int 692 sys___mac_get_file(struct thread *td, struct __mac_get_file_args *uap) 693 { 694 695 return (ENOSYS); 696 } 697 698 int 699 sys___mac_get_link(struct thread *td, struct __mac_get_link_args *uap) 700 { 701 702 return (ENOSYS); 703 } 704 705 int 706 sys___mac_set_fd(struct thread *td, struct __mac_set_fd_args *uap) 707 { 708 709 return (ENOSYS); 710 } 711 712 int 713 sys___mac_set_file(struct thread *td, struct __mac_set_file_args *uap) 714 { 715 716 return (ENOSYS); 717 } 718 719 int 720 sys___mac_set_link(struct thread *td, struct __mac_set_link_args *uap) 721 { 722 723 return (ENOSYS); 724 } 725 726 int 727 sys_mac_syscall(struct thread *td, struct mac_syscall_args *uap) 728 { 729 730 return (ENOSYS); 731 } 732 733 #endif /* !MAC */ 734