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