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