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