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