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 PROC_UNLOCK(p); 207 crfree(oldcred); 208 mac_proc_vm_revoke(td); 209 210 out: 211 mac_cred_label_free(intlabel); 212 return (error); 213 } 214 215 int 216 __mac_get_fd(struct thread *td, struct __mac_get_fd_args *uap) 217 { 218 char *elements, *buffer; 219 struct label *intlabel; 220 struct file *fp; 221 struct mac mac; 222 struct vnode *vp; 223 struct pipe *pipe; 224 struct socket *so; 225 short label_type; 226 int vfslocked, error; 227 228 error = copyin(uap->mac_p, &mac, sizeof(mac)); 229 if (error) 230 return (error); 231 232 error = mac_check_structmac_consistent(&mac); 233 if (error) 234 return (error); 235 236 elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 237 error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL); 238 if (error) { 239 free(elements, M_MACTEMP); 240 return (error); 241 } 242 243 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); 244 error = fget(td, uap->fd, &fp); 245 if (error) 246 goto out; 247 248 label_type = fp->f_type; 249 switch (fp->f_type) { 250 case DTYPE_FIFO: 251 case DTYPE_VNODE: 252 if (!(mac_labeled & MPC_OBJECT_VNODE)) 253 return (EINVAL); 254 vp = fp->f_vnode; 255 intlabel = mac_vnode_label_alloc(); 256 vfslocked = VFS_LOCK_GIANT(vp->v_mount); 257 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 258 mac_vnode_copy_label(vp->v_label, intlabel); 259 VOP_UNLOCK(vp, 0); 260 VFS_UNLOCK_GIANT(vfslocked); 261 error = mac_vnode_externalize_label(intlabel, elements, 262 buffer, mac.m_buflen); 263 mac_vnode_label_free(intlabel); 264 break; 265 266 case DTYPE_PIPE: 267 if (!(mac_labeled & MPC_OBJECT_PIPE)) 268 return (EINVAL); 269 pipe = fp->f_data; 270 intlabel = mac_pipe_label_alloc(); 271 PIPE_LOCK(pipe); 272 mac_pipe_copy_label(pipe->pipe_pair->pp_label, intlabel); 273 PIPE_UNLOCK(pipe); 274 error = mac_pipe_externalize_label(intlabel, elements, 275 buffer, mac.m_buflen); 276 mac_pipe_label_free(intlabel); 277 break; 278 279 case DTYPE_SOCKET: 280 if (!(mac_labeled & MPC_OBJECT_SOCKET)) 281 return (EINVAL); 282 so = fp->f_data; 283 intlabel = mac_socket_label_alloc(M_WAITOK); 284 SOCK_LOCK(so); 285 mac_socket_copy_label(so->so_label, intlabel); 286 SOCK_UNLOCK(so); 287 error = mac_socket_externalize_label(intlabel, elements, 288 buffer, mac.m_buflen); 289 mac_socket_label_free(intlabel); 290 break; 291 292 default: 293 error = EINVAL; 294 } 295 fdrop(fp, td); 296 if (error == 0) 297 error = copyout(buffer, mac.m_string, strlen(buffer)+1); 298 299 out: 300 free(buffer, M_MACTEMP); 301 free(elements, M_MACTEMP); 302 return (error); 303 } 304 305 int 306 __mac_get_file(struct thread *td, struct __mac_get_file_args *uap) 307 { 308 char *elements, *buffer; 309 struct nameidata nd; 310 struct label *intlabel; 311 struct mac mac; 312 int vfslocked, error; 313 314 if (!(mac_labeled & MPC_OBJECT_VNODE)) 315 return (EINVAL); 316 317 error = copyin(uap->mac_p, &mac, sizeof(mac)); 318 if (error) 319 return (error); 320 321 error = mac_check_structmac_consistent(&mac); 322 if (error) 323 return (error); 324 325 elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 326 error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL); 327 if (error) { 328 free(elements, M_MACTEMP); 329 return (error); 330 } 331 332 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); 333 NDINIT(&nd, LOOKUP, MPSAFE | LOCKLEAF | FOLLOW, UIO_USERSPACE, 334 uap->path_p, td); 335 error = namei(&nd); 336 if (error) 337 goto out; 338 339 intlabel = mac_vnode_label_alloc(); 340 vfslocked = NDHASGIANT(&nd); 341 mac_vnode_copy_label(nd.ni_vp->v_label, intlabel); 342 error = mac_vnode_externalize_label(intlabel, elements, buffer, 343 mac.m_buflen); 344 345 NDFREE(&nd, 0); 346 VFS_UNLOCK_GIANT(vfslocked); 347 mac_vnode_label_free(intlabel); 348 if (error == 0) 349 error = copyout(buffer, mac.m_string, strlen(buffer)+1); 350 351 out: 352 free(buffer, M_MACTEMP); 353 free(elements, M_MACTEMP); 354 355 return (error); 356 } 357 358 int 359 __mac_get_link(struct thread *td, struct __mac_get_link_args *uap) 360 { 361 char *elements, *buffer; 362 struct nameidata nd; 363 struct label *intlabel; 364 struct mac mac; 365 int vfslocked, error; 366 367 if (!(mac_labeled & MPC_OBJECT_VNODE)) 368 return (EINVAL); 369 370 error = copyin(uap->mac_p, &mac, sizeof(mac)); 371 if (error) 372 return (error); 373 374 error = mac_check_structmac_consistent(&mac); 375 if (error) 376 return (error); 377 378 elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 379 error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL); 380 if (error) { 381 free(elements, M_MACTEMP); 382 return (error); 383 } 384 385 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); 386 NDINIT(&nd, LOOKUP, MPSAFE | LOCKLEAF | NOFOLLOW, UIO_USERSPACE, 387 uap->path_p, td); 388 error = namei(&nd); 389 if (error) 390 goto out; 391 392 intlabel = mac_vnode_label_alloc(); 393 vfslocked = NDHASGIANT(&nd); 394 mac_vnode_copy_label(nd.ni_vp->v_label, intlabel); 395 error = mac_vnode_externalize_label(intlabel, elements, buffer, 396 mac.m_buflen); 397 NDFREE(&nd, 0); 398 VFS_UNLOCK_GIANT(vfslocked); 399 mac_vnode_label_free(intlabel); 400 401 if (error == 0) 402 error = copyout(buffer, mac.m_string, strlen(buffer)+1); 403 404 out: 405 free(buffer, M_MACTEMP); 406 free(elements, M_MACTEMP); 407 408 return (error); 409 } 410 411 int 412 __mac_set_fd(struct thread *td, struct __mac_set_fd_args *uap) 413 { 414 struct label *intlabel; 415 struct pipe *pipe; 416 struct socket *so; 417 struct file *fp; 418 struct mount *mp; 419 struct vnode *vp; 420 struct mac mac; 421 char *buffer; 422 int error, vfslocked; 423 424 error = copyin(uap->mac_p, &mac, sizeof(mac)); 425 if (error) 426 return (error); 427 428 error = mac_check_structmac_consistent(&mac); 429 if (error) 430 return (error); 431 432 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 433 error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL); 434 if (error) { 435 free(buffer, M_MACTEMP); 436 return (error); 437 } 438 439 error = fget(td, uap->fd, &fp); 440 if (error) 441 goto out; 442 443 switch (fp->f_type) { 444 case DTYPE_FIFO: 445 case DTYPE_VNODE: 446 if (!(mac_labeled & MPC_OBJECT_VNODE)) 447 return (EINVAL); 448 intlabel = mac_vnode_label_alloc(); 449 error = mac_vnode_internalize_label(intlabel, buffer); 450 if (error) { 451 mac_vnode_label_free(intlabel); 452 break; 453 } 454 vp = fp->f_vnode; 455 vfslocked = VFS_LOCK_GIANT(vp->v_mount); 456 error = vn_start_write(vp, &mp, V_WAIT | PCATCH); 457 if (error != 0) { 458 VFS_UNLOCK_GIANT(vfslocked); 459 mac_vnode_label_free(intlabel); 460 break; 461 } 462 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 463 error = vn_setlabel(vp, intlabel, td->td_ucred); 464 VOP_UNLOCK(vp, 0); 465 vn_finished_write(mp); 466 VFS_UNLOCK_GIANT(vfslocked); 467 mac_vnode_label_free(intlabel); 468 break; 469 470 case DTYPE_PIPE: 471 if (!(mac_labeled & MPC_OBJECT_PIPE)) 472 return (EINVAL); 473 intlabel = mac_pipe_label_alloc(); 474 error = mac_pipe_internalize_label(intlabel, buffer); 475 if (error == 0) { 476 pipe = fp->f_data; 477 PIPE_LOCK(pipe); 478 error = mac_pipe_label_set(td->td_ucred, 479 pipe->pipe_pair, intlabel); 480 PIPE_UNLOCK(pipe); 481 } 482 mac_pipe_label_free(intlabel); 483 break; 484 485 case DTYPE_SOCKET: 486 if (!(mac_labeled & MPC_OBJECT_SOCKET)) 487 return (EINVAL); 488 intlabel = mac_socket_label_alloc(M_WAITOK); 489 error = mac_socket_internalize_label(intlabel, buffer); 490 if (error == 0) { 491 so = fp->f_data; 492 error = mac_socket_label_set(td->td_ucred, so, 493 intlabel); 494 } 495 mac_socket_label_free(intlabel); 496 break; 497 498 default: 499 error = EINVAL; 500 } 501 fdrop(fp, td); 502 out: 503 free(buffer, M_MACTEMP); 504 return (error); 505 } 506 507 int 508 __mac_set_file(struct thread *td, struct __mac_set_file_args *uap) 509 { 510 struct label *intlabel; 511 struct nameidata nd; 512 struct mount *mp; 513 struct mac mac; 514 char *buffer; 515 int vfslocked, error; 516 517 if (!(mac_labeled & MPC_OBJECT_VNODE)) 518 return (EINVAL); 519 520 error = copyin(uap->mac_p, &mac, sizeof(mac)); 521 if (error) 522 return (error); 523 524 error = mac_check_structmac_consistent(&mac); 525 if (error) 526 return (error); 527 528 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 529 error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL); 530 if (error) { 531 free(buffer, M_MACTEMP); 532 return (error); 533 } 534 535 intlabel = mac_vnode_label_alloc(); 536 error = mac_vnode_internalize_label(intlabel, buffer); 537 free(buffer, M_MACTEMP); 538 if (error) 539 goto out; 540 541 NDINIT(&nd, LOOKUP, MPSAFE | LOCKLEAF | FOLLOW, UIO_USERSPACE, 542 uap->path_p, td); 543 error = namei(&nd); 544 vfslocked = NDHASGIANT(&nd); 545 if (error == 0) { 546 error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH); 547 if (error == 0) { 548 error = vn_setlabel(nd.ni_vp, intlabel, 549 td->td_ucred); 550 vn_finished_write(mp); 551 } 552 } 553 554 NDFREE(&nd, 0); 555 VFS_UNLOCK_GIANT(vfslocked); 556 out: 557 mac_vnode_label_free(intlabel); 558 return (error); 559 } 560 561 int 562 __mac_set_link(struct thread *td, struct __mac_set_link_args *uap) 563 { 564 struct label *intlabel; 565 struct nameidata nd; 566 struct mount *mp; 567 struct mac mac; 568 char *buffer; 569 int vfslocked, error; 570 571 if (!(mac_labeled & MPC_OBJECT_VNODE)) 572 return (EINVAL); 573 574 error = copyin(uap->mac_p, &mac, sizeof(mac)); 575 if (error) 576 return (error); 577 578 error = mac_check_structmac_consistent(&mac); 579 if (error) 580 return (error); 581 582 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 583 error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL); 584 if (error) { 585 free(buffer, M_MACTEMP); 586 return (error); 587 } 588 589 intlabel = mac_vnode_label_alloc(); 590 error = mac_vnode_internalize_label(intlabel, buffer); 591 free(buffer, M_MACTEMP); 592 if (error) 593 goto out; 594 595 NDINIT(&nd, LOOKUP, MPSAFE | LOCKLEAF | NOFOLLOW, UIO_USERSPACE, 596 uap->path_p, td); 597 error = namei(&nd); 598 vfslocked = NDHASGIANT(&nd); 599 if (error == 0) { 600 error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH); 601 if (error == 0) { 602 error = vn_setlabel(nd.ni_vp, intlabel, 603 td->td_ucred); 604 vn_finished_write(mp); 605 } 606 } 607 608 NDFREE(&nd, 0); 609 VFS_UNLOCK_GIANT(vfslocked); 610 out: 611 mac_vnode_label_free(intlabel); 612 return (error); 613 } 614 615 int 616 mac_syscall(struct thread *td, struct mac_syscall_args *uap) 617 { 618 struct mac_policy_conf *mpc; 619 char target[MAC_MAX_POLICY_NAME]; 620 int entrycount, error; 621 622 error = copyinstr(uap->policy, target, sizeof(target), NULL); 623 if (error) 624 return (error); 625 626 error = ENOSYS; 627 LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) { 628 if (strcmp(mpc->mpc_name, target) == 0 && 629 mpc->mpc_ops->mpo_syscall != NULL) { 630 error = mpc->mpc_ops->mpo_syscall(td, 631 uap->call, uap->arg); 632 goto out; 633 } 634 } 635 636 if ((entrycount = mac_policy_list_conditional_busy()) != 0) { 637 LIST_FOREACH(mpc, &mac_policy_list, mpc_list) { 638 if (strcmp(mpc->mpc_name, target) == 0 && 639 mpc->mpc_ops->mpo_syscall != NULL) { 640 error = mpc->mpc_ops->mpo_syscall(td, 641 uap->call, uap->arg); 642 break; 643 } 644 } 645 mac_policy_list_unbusy(); 646 } 647 out: 648 return (error); 649 } 650 651 #else /* !MAC */ 652 653 int 654 __mac_get_pid(struct thread *td, struct __mac_get_pid_args *uap) 655 { 656 657 return (ENOSYS); 658 } 659 660 int 661 __mac_get_proc(struct thread *td, struct __mac_get_proc_args *uap) 662 { 663 664 return (ENOSYS); 665 } 666 667 int 668 __mac_set_proc(struct thread *td, struct __mac_set_proc_args *uap) 669 { 670 671 return (ENOSYS); 672 } 673 674 int 675 __mac_get_fd(struct thread *td, struct __mac_get_fd_args *uap) 676 { 677 678 return (ENOSYS); 679 } 680 681 int 682 __mac_get_file(struct thread *td, struct __mac_get_file_args *uap) 683 { 684 685 return (ENOSYS); 686 } 687 688 int 689 __mac_get_link(struct thread *td, struct __mac_get_link_args *uap) 690 { 691 692 return (ENOSYS); 693 } 694 695 int 696 __mac_set_fd(struct thread *td, struct __mac_set_fd_args *uap) 697 { 698 699 return (ENOSYS); 700 } 701 702 int 703 __mac_set_file(struct thread *td, struct __mac_set_file_args *uap) 704 { 705 706 return (ENOSYS); 707 } 708 709 int 710 __mac_set_link(struct thread *td, struct __mac_set_link_args *uap) 711 { 712 713 return (ENOSYS); 714 } 715 716 int 717 mac_syscall(struct thread *td, struct mac_syscall_args *uap) 718 { 719 720 return (ENOSYS); 721 } 722 723 #endif /* !MAC */ 724