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