1 /*- 2 * Copyright (c) 1999-2002, 2006 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 * Redistribution and use in source and binary forms, with or without 21 * modification, are permitted provided that the following conditions 22 * are met: 23 * 1. Redistributions of source code must retain the above copyright 24 * notice, this list of conditions and the following disclaimer. 25 * 2. Redistributions in binary form must reproduce the above copyright 26 * notice, this list of conditions and the following disclaimer in the 27 * documentation and/or other materials provided with the distribution. 28 * 29 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 30 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 31 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 32 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 33 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 34 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 35 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 36 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 37 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 38 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 39 * SUCH DAMAGE. 40 */ 41 42 #include <sys/cdefs.h> 43 __FBSDID("$FreeBSD$"); 44 45 #include "opt_mac.h" 46 47 #include <sys/param.h> 48 #include <sys/fcntl.h> 49 #include <sys/kernel.h> 50 #include <sys/lock.h> 51 #include <sys/malloc.h> 52 #include <sys/mutex.h> 53 #include <sys/mac.h> 54 #include <sys/proc.h> 55 #include <sys/systm.h> 56 #include <sys/sysproto.h> 57 #include <sys/sysent.h> 58 #include <sys/vnode.h> 59 #include <sys/mount.h> 60 #include <sys/file.h> 61 #include <sys/namei.h> 62 #include <sys/socket.h> 63 #include <sys/pipe.h> 64 #include <sys/socketvar.h> 65 66 #include <security/mac/mac_framework.h> 67 #include <security/mac/mac_internal.h> 68 #include <security/mac/mac_policy.h> 69 70 #ifdef MAC 71 72 int 73 __mac_get_pid(struct thread *td, struct __mac_get_pid_args *uap) 74 { 75 char *elements, *buffer; 76 struct mac mac; 77 struct proc *tproc; 78 struct ucred *tcred; 79 int error; 80 81 error = copyin(uap->mac_p, &mac, sizeof(mac)); 82 if (error) 83 return (error); 84 85 error = mac_check_structmac_consistent(&mac); 86 if (error) 87 return (error); 88 89 tproc = pfind(uap->pid); 90 if (tproc == NULL) 91 return (ESRCH); 92 93 tcred = NULL; /* Satisfy gcc. */ 94 error = p_cansee(td, tproc); 95 if (error == 0) 96 tcred = crhold(tproc->p_ucred); 97 PROC_UNLOCK(tproc); 98 if (error) 99 return (error); 100 101 elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 102 error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL); 103 if (error) { 104 free(elements, M_MACTEMP); 105 crfree(tcred); 106 return (error); 107 } 108 109 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); 110 error = mac_cred_externalize_label(tcred->cr_label, elements, 111 buffer, mac.m_buflen); 112 if (error == 0) 113 error = copyout(buffer, mac.m_string, strlen(buffer)+1); 114 115 free(buffer, M_MACTEMP); 116 free(elements, M_MACTEMP); 117 crfree(tcred); 118 return (error); 119 } 120 121 int 122 __mac_get_proc(struct thread *td, struct __mac_get_proc_args *uap) 123 { 124 char *elements, *buffer; 125 struct mac mac; 126 int error; 127 128 error = copyin(uap->mac_p, &mac, sizeof(mac)); 129 if (error) 130 return (error); 131 132 error = mac_check_structmac_consistent(&mac); 133 if (error) 134 return (error); 135 136 elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 137 error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL); 138 if (error) { 139 free(elements, M_MACTEMP); 140 return (error); 141 } 142 143 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); 144 error = mac_cred_externalize_label(td->td_ucred->cr_label, 145 elements, buffer, mac.m_buflen); 146 if (error == 0) 147 error = copyout(buffer, mac.m_string, strlen(buffer)+1); 148 149 free(buffer, M_MACTEMP); 150 free(elements, M_MACTEMP); 151 return (error); 152 } 153 154 int 155 __mac_set_proc(struct thread *td, struct __mac_set_proc_args *uap) 156 { 157 struct ucred *newcred, *oldcred; 158 struct label *intlabel; 159 struct proc *p; 160 struct mac mac; 161 char *buffer; 162 int error; 163 164 if (!(mac_labeled & MPC_OBJECT_CRED)) 165 return (EINVAL); 166 167 error = copyin(uap->mac_p, &mac, sizeof(mac)); 168 if (error) 169 return (error); 170 171 error = mac_check_structmac_consistent(&mac); 172 if (error) 173 return (error); 174 175 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 176 error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL); 177 if (error) { 178 free(buffer, M_MACTEMP); 179 return (error); 180 } 181 182 intlabel = mac_cred_label_alloc(); 183 error = mac_cred_internalize_label(intlabel, buffer); 184 free(buffer, M_MACTEMP); 185 if (error) 186 goto out; 187 188 newcred = crget(); 189 190 p = td->td_proc; 191 PROC_LOCK(p); 192 oldcred = p->p_ucred; 193 194 error = mac_cred_check_relabel(oldcred, intlabel); 195 if (error) { 196 PROC_UNLOCK(p); 197 crfree(newcred); 198 goto out; 199 } 200 201 setsugid(p); 202 crcopy(newcred, oldcred); 203 mac_cred_relabel(newcred, intlabel); 204 p->p_ucred = newcred; 205 206 /* 207 * Grab additional reference for use while revoking mmaps, prior to 208 * releasing the proc lock and sharing the cred. 209 */ 210 crhold(newcred); 211 PROC_UNLOCK(p); 212 213 mac_cred_mmapped_drop_perms(td, newcred); 214 215 crfree(newcred); /* Free revocation reference. */ 216 crfree(oldcred); 217 218 out: 219 mac_cred_label_free(intlabel); 220 return (error); 221 } 222 223 int 224 __mac_get_fd(struct thread *td, struct __mac_get_fd_args *uap) 225 { 226 char *elements, *buffer; 227 struct label *intlabel; 228 struct file *fp; 229 struct mac mac; 230 struct vnode *vp; 231 struct pipe *pipe; 232 struct socket *so; 233 short label_type; 234 int vfslocked, 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, &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 return (EINVAL); 262 vp = fp->f_vnode; 263 intlabel = mac_vnode_label_alloc(); 264 vfslocked = VFS_LOCK_GIANT(vp->v_mount); 265 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 266 mac_vnode_copy_label(vp->v_label, intlabel); 267 VOP_UNLOCK(vp, 0); 268 VFS_UNLOCK_GIANT(vfslocked); 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 return (EINVAL); 277 pipe = fp->f_data; 278 intlabel = mac_pipe_label_alloc(); 279 PIPE_LOCK(pipe); 280 mac_pipe_copy_label(pipe->pipe_pair->pp_label, intlabel); 281 PIPE_UNLOCK(pipe); 282 error = mac_pipe_externalize_label(intlabel, elements, 283 buffer, mac.m_buflen); 284 mac_pipe_label_free(intlabel); 285 break; 286 287 case DTYPE_SOCKET: 288 if (!(mac_labeled & MPC_OBJECT_SOCKET)) 289 return (EINVAL); 290 so = fp->f_data; 291 intlabel = mac_socket_label_alloc(M_WAITOK); 292 SOCK_LOCK(so); 293 mac_socket_copy_label(so->so_label, intlabel); 294 SOCK_UNLOCK(so); 295 error = mac_socket_externalize_label(intlabel, elements, 296 buffer, mac.m_buflen); 297 mac_socket_label_free(intlabel); 298 break; 299 300 default: 301 error = EINVAL; 302 } 303 fdrop(fp, td); 304 if (error == 0) 305 error = copyout(buffer, mac.m_string, strlen(buffer)+1); 306 307 out: 308 free(buffer, M_MACTEMP); 309 free(elements, M_MACTEMP); 310 return (error); 311 } 312 313 int 314 __mac_get_file(struct thread *td, struct __mac_get_file_args *uap) 315 { 316 char *elements, *buffer; 317 struct nameidata nd; 318 struct label *intlabel; 319 struct mac mac; 320 int vfslocked, error; 321 322 if (!(mac_labeled & MPC_OBJECT_VNODE)) 323 return (EINVAL); 324 325 error = copyin(uap->mac_p, &mac, sizeof(mac)); 326 if (error) 327 return (error); 328 329 error = mac_check_structmac_consistent(&mac); 330 if (error) 331 return (error); 332 333 elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 334 error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL); 335 if (error) { 336 free(elements, M_MACTEMP); 337 return (error); 338 } 339 340 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); 341 NDINIT(&nd, LOOKUP, MPSAFE | LOCKLEAF | FOLLOW, UIO_USERSPACE, 342 uap->path_p, td); 343 error = namei(&nd); 344 if (error) 345 goto out; 346 347 intlabel = mac_vnode_label_alloc(); 348 vfslocked = NDHASGIANT(&nd); 349 mac_vnode_copy_label(nd.ni_vp->v_label, intlabel); 350 error = mac_vnode_externalize_label(intlabel, elements, buffer, 351 mac.m_buflen); 352 353 NDFREE(&nd, 0); 354 VFS_UNLOCK_GIANT(vfslocked); 355 mac_vnode_label_free(intlabel); 356 if (error == 0) 357 error = copyout(buffer, mac.m_string, strlen(buffer)+1); 358 359 out: 360 free(buffer, M_MACTEMP); 361 free(elements, M_MACTEMP); 362 363 return (error); 364 } 365 366 int 367 __mac_get_link(struct thread *td, struct __mac_get_link_args *uap) 368 { 369 char *elements, *buffer; 370 struct nameidata nd; 371 struct label *intlabel; 372 struct mac mac; 373 int vfslocked, error; 374 375 if (!(mac_labeled & MPC_OBJECT_VNODE)) 376 return (EINVAL); 377 378 error = copyin(uap->mac_p, &mac, sizeof(mac)); 379 if (error) 380 return (error); 381 382 error = mac_check_structmac_consistent(&mac); 383 if (error) 384 return (error); 385 386 elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 387 error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL); 388 if (error) { 389 free(elements, M_MACTEMP); 390 return (error); 391 } 392 393 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); 394 NDINIT(&nd, LOOKUP, MPSAFE | LOCKLEAF | NOFOLLOW, UIO_USERSPACE, 395 uap->path_p, td); 396 error = namei(&nd); 397 if (error) 398 goto out; 399 400 intlabel = mac_vnode_label_alloc(); 401 vfslocked = NDHASGIANT(&nd); 402 mac_vnode_copy_label(nd.ni_vp->v_label, intlabel); 403 error = mac_vnode_externalize_label(intlabel, elements, buffer, 404 mac.m_buflen); 405 NDFREE(&nd, 0); 406 VFS_UNLOCK_GIANT(vfslocked); 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 __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 char *buffer; 430 int error, vfslocked; 431 432 error = copyin(uap->mac_p, &mac, sizeof(mac)); 433 if (error) 434 return (error); 435 436 error = mac_check_structmac_consistent(&mac); 437 if (error) 438 return (error); 439 440 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 441 error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL); 442 if (error) { 443 free(buffer, M_MACTEMP); 444 return (error); 445 } 446 447 error = fget(td, uap->fd, &fp); 448 if (error) 449 goto out; 450 451 switch (fp->f_type) { 452 case DTYPE_FIFO: 453 case DTYPE_VNODE: 454 if (!(mac_labeled & MPC_OBJECT_VNODE)) 455 return (EINVAL); 456 intlabel = mac_vnode_label_alloc(); 457 error = mac_vnode_internalize_label(intlabel, buffer); 458 if (error) { 459 mac_vnode_label_free(intlabel); 460 break; 461 } 462 vp = fp->f_vnode; 463 vfslocked = VFS_LOCK_GIANT(vp->v_mount); 464 error = vn_start_write(vp, &mp, V_WAIT | PCATCH); 465 if (error != 0) { 466 VFS_UNLOCK_GIANT(vfslocked); 467 mac_vnode_label_free(intlabel); 468 break; 469 } 470 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 471 error = vn_setlabel(vp, intlabel, td->td_ucred); 472 VOP_UNLOCK(vp, 0); 473 vn_finished_write(mp); 474 VFS_UNLOCK_GIANT(vfslocked); 475 mac_vnode_label_free(intlabel); 476 break; 477 478 case DTYPE_PIPE: 479 if (!(mac_labeled & MPC_OBJECT_PIPE)) 480 return (EINVAL); 481 intlabel = mac_pipe_label_alloc(); 482 error = mac_pipe_internalize_label(intlabel, buffer); 483 if (error == 0) { 484 pipe = fp->f_data; 485 PIPE_LOCK(pipe); 486 error = mac_pipe_label_set(td->td_ucred, 487 pipe->pipe_pair, intlabel); 488 PIPE_UNLOCK(pipe); 489 } 490 mac_pipe_label_free(intlabel); 491 break; 492 493 case DTYPE_SOCKET: 494 if (!(mac_labeled & MPC_OBJECT_SOCKET)) 495 return (EINVAL); 496 intlabel = mac_socket_label_alloc(M_WAITOK); 497 error = mac_socket_internalize_label(intlabel, buffer); 498 if (error == 0) { 499 so = fp->f_data; 500 error = mac_socket_label_set(td->td_ucred, so, 501 intlabel); 502 } 503 mac_socket_label_free(intlabel); 504 break; 505 506 default: 507 error = EINVAL; 508 } 509 fdrop(fp, td); 510 out: 511 free(buffer, M_MACTEMP); 512 return (error); 513 } 514 515 int 516 __mac_set_file(struct thread *td, struct __mac_set_file_args *uap) 517 { 518 struct label *intlabel; 519 struct nameidata nd; 520 struct mount *mp; 521 struct mac mac; 522 char *buffer; 523 int vfslocked, error; 524 525 if (!(mac_labeled & MPC_OBJECT_VNODE)) 526 return (EINVAL); 527 528 error = copyin(uap->mac_p, &mac, sizeof(mac)); 529 if (error) 530 return (error); 531 532 error = mac_check_structmac_consistent(&mac); 533 if (error) 534 return (error); 535 536 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 537 error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL); 538 if (error) { 539 free(buffer, M_MACTEMP); 540 return (error); 541 } 542 543 intlabel = mac_vnode_label_alloc(); 544 error = mac_vnode_internalize_label(intlabel, buffer); 545 free(buffer, M_MACTEMP); 546 if (error) 547 goto out; 548 549 NDINIT(&nd, LOOKUP, MPSAFE | LOCKLEAF | FOLLOW, UIO_USERSPACE, 550 uap->path_p, td); 551 error = namei(&nd); 552 vfslocked = NDHASGIANT(&nd); 553 if (error == 0) { 554 error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH); 555 if (error == 0) { 556 error = vn_setlabel(nd.ni_vp, intlabel, 557 td->td_ucred); 558 vn_finished_write(mp); 559 } 560 } 561 562 NDFREE(&nd, 0); 563 VFS_UNLOCK_GIANT(vfslocked); 564 out: 565 mac_vnode_label_free(intlabel); 566 return (error); 567 } 568 569 int 570 __mac_set_link(struct thread *td, struct __mac_set_link_args *uap) 571 { 572 struct label *intlabel; 573 struct nameidata nd; 574 struct mount *mp; 575 struct mac mac; 576 char *buffer; 577 int vfslocked, error; 578 579 if (!(mac_labeled & MPC_OBJECT_VNODE)) 580 return (EINVAL); 581 582 error = copyin(uap->mac_p, &mac, sizeof(mac)); 583 if (error) 584 return (error); 585 586 error = mac_check_structmac_consistent(&mac); 587 if (error) 588 return (error); 589 590 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 591 error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL); 592 if (error) { 593 free(buffer, M_MACTEMP); 594 return (error); 595 } 596 597 intlabel = mac_vnode_label_alloc(); 598 error = mac_vnode_internalize_label(intlabel, buffer); 599 free(buffer, M_MACTEMP); 600 if (error) 601 goto out; 602 603 NDINIT(&nd, LOOKUP, MPSAFE | LOCKLEAF | NOFOLLOW, UIO_USERSPACE, 604 uap->path_p, td); 605 error = namei(&nd); 606 vfslocked = NDHASGIANT(&nd); 607 if (error == 0) { 608 error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH); 609 if (error == 0) { 610 error = vn_setlabel(nd.ni_vp, intlabel, 611 td->td_ucred); 612 vn_finished_write(mp); 613 } 614 } 615 616 NDFREE(&nd, 0); 617 VFS_UNLOCK_GIANT(vfslocked); 618 out: 619 mac_vnode_label_free(intlabel); 620 return (error); 621 } 622 623 int 624 mac_syscall(struct thread *td, struct mac_syscall_args *uap) 625 { 626 struct mac_policy_conf *mpc; 627 char target[MAC_MAX_POLICY_NAME]; 628 int entrycount, error; 629 630 error = copyinstr(uap->policy, target, sizeof(target), NULL); 631 if (error) 632 return (error); 633 634 error = ENOSYS; 635 LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) { 636 if (strcmp(mpc->mpc_name, target) == 0 && 637 mpc->mpc_ops->mpo_syscall != NULL) { 638 error = mpc->mpc_ops->mpo_syscall(td, 639 uap->call, uap->arg); 640 goto out; 641 } 642 } 643 644 if ((entrycount = mac_policy_list_conditional_busy()) != 0) { 645 LIST_FOREACH(mpc, &mac_policy_list, mpc_list) { 646 if (strcmp(mpc->mpc_name, target) == 0 && 647 mpc->mpc_ops->mpo_syscall != NULL) { 648 error = mpc->mpc_ops->mpo_syscall(td, 649 uap->call, uap->arg); 650 break; 651 } 652 } 653 mac_policy_list_unbusy(); 654 } 655 out: 656 return (error); 657 } 658 659 #else /* !MAC */ 660 661 int 662 __mac_get_pid(struct thread *td, struct __mac_get_pid_args *uap) 663 { 664 665 return (ENOSYS); 666 } 667 668 int 669 __mac_get_proc(struct thread *td, struct __mac_get_proc_args *uap) 670 { 671 672 return (ENOSYS); 673 } 674 675 int 676 __mac_set_proc(struct thread *td, struct __mac_set_proc_args *uap) 677 { 678 679 return (ENOSYS); 680 } 681 682 int 683 __mac_get_fd(struct thread *td, struct __mac_get_fd_args *uap) 684 { 685 686 return (ENOSYS); 687 } 688 689 int 690 __mac_get_file(struct thread *td, struct __mac_get_file_args *uap) 691 { 692 693 return (ENOSYS); 694 } 695 696 int 697 __mac_get_link(struct thread *td, struct __mac_get_link_args *uap) 698 { 699 700 return (ENOSYS); 701 } 702 703 int 704 __mac_set_fd(struct thread *td, struct __mac_set_fd_args *uap) 705 { 706 707 return (ENOSYS); 708 } 709 710 int 711 __mac_set_file(struct thread *td, struct __mac_set_file_args *uap) 712 { 713 714 return (ENOSYS); 715 } 716 717 int 718 __mac_set_link(struct thread *td, struct __mac_set_link_args *uap) 719 { 720 721 return (ENOSYS); 722 } 723 724 int 725 mac_syscall(struct thread *td, struct mac_syscall_args *uap) 726 { 727 728 return (ENOSYS); 729 } 730 731 #endif /* !MAC */ 732