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_cred_externalize_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_cred_externalize_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_cred_internalize_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_cred_check_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_cred_relabel(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); 259 mac_vnode_copy_label(vp->v_label, intlabel); 260 VOP_UNLOCK(vp, 0); 261 VFS_UNLOCK_GIANT(vfslocked); 262 error = mac_vnode_externalize_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_pipe_copy_label(pipe->pipe_pair->pp_label, intlabel); 272 PIPE_UNLOCK(pipe); 273 error = mac_pipe_externalize_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 SOCK_LOCK(so); 282 mac_socket_copy_label(so->so_label, intlabel); 283 SOCK_UNLOCK(so); 284 error = mac_socket_externalize_label(intlabel, elements, 285 buffer, mac.m_buflen); 286 mac_socket_label_free(intlabel); 287 break; 288 289 default: 290 error = EINVAL; 291 } 292 fdrop(fp, td); 293 if (error == 0) 294 error = copyout(buffer, mac.m_string, strlen(buffer)+1); 295 296 out: 297 free(buffer, M_MACTEMP); 298 free(elements, M_MACTEMP); 299 return (error); 300 } 301 302 int 303 __mac_get_file(struct thread *td, struct __mac_get_file_args *uap) 304 { 305 char *elements, *buffer; 306 struct nameidata nd; 307 struct label *intlabel; 308 struct mac mac; 309 int vfslocked, error; 310 311 error = copyin(uap->mac_p, &mac, sizeof(mac)); 312 if (error) 313 return (error); 314 315 error = mac_check_structmac_consistent(&mac); 316 if (error) 317 return (error); 318 319 elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 320 error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL); 321 if (error) { 322 free(elements, M_MACTEMP); 323 return (error); 324 } 325 326 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); 327 NDINIT(&nd, LOOKUP, MPSAFE | LOCKLEAF | FOLLOW, UIO_USERSPACE, 328 uap->path_p, td); 329 error = namei(&nd); 330 if (error) 331 goto out; 332 333 intlabel = mac_vnode_label_alloc(); 334 vfslocked = NDHASGIANT(&nd); 335 mac_vnode_copy_label(nd.ni_vp->v_label, intlabel); 336 error = mac_vnode_externalize_label(intlabel, elements, buffer, 337 mac.m_buflen); 338 339 NDFREE(&nd, 0); 340 VFS_UNLOCK_GIANT(vfslocked); 341 mac_vnode_label_free(intlabel); 342 if (error == 0) 343 error = copyout(buffer, mac.m_string, strlen(buffer)+1); 344 345 out: 346 free(buffer, M_MACTEMP); 347 free(elements, M_MACTEMP); 348 349 return (error); 350 } 351 352 int 353 __mac_get_link(struct thread *td, struct __mac_get_link_args *uap) 354 { 355 char *elements, *buffer; 356 struct nameidata nd; 357 struct label *intlabel; 358 struct mac mac; 359 int vfslocked, error; 360 361 error = copyin(uap->mac_p, &mac, sizeof(mac)); 362 if (error) 363 return (error); 364 365 error = mac_check_structmac_consistent(&mac); 366 if (error) 367 return (error); 368 369 elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 370 error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL); 371 if (error) { 372 free(elements, M_MACTEMP); 373 return (error); 374 } 375 376 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); 377 NDINIT(&nd, LOOKUP, MPSAFE | LOCKLEAF | NOFOLLOW, UIO_USERSPACE, 378 uap->path_p, td); 379 error = namei(&nd); 380 if (error) 381 goto out; 382 383 intlabel = mac_vnode_label_alloc(); 384 vfslocked = NDHASGIANT(&nd); 385 mac_vnode_copy_label(nd.ni_vp->v_label, intlabel); 386 error = mac_vnode_externalize_label(intlabel, elements, buffer, 387 mac.m_buflen); 388 NDFREE(&nd, 0); 389 VFS_UNLOCK_GIANT(vfslocked); 390 mac_vnode_label_free(intlabel); 391 392 if (error == 0) 393 error = copyout(buffer, mac.m_string, strlen(buffer)+1); 394 395 out: 396 free(buffer, M_MACTEMP); 397 free(elements, M_MACTEMP); 398 399 return (error); 400 } 401 402 int 403 __mac_set_fd(struct thread *td, struct __mac_set_fd_args *uap) 404 { 405 struct label *intlabel; 406 struct pipe *pipe; 407 struct socket *so; 408 struct file *fp; 409 struct mount *mp; 410 struct vnode *vp; 411 struct mac mac; 412 char *buffer; 413 int error, vfslocked; 414 415 error = copyin(uap->mac_p, &mac, sizeof(mac)); 416 if (error) 417 return (error); 418 419 error = mac_check_structmac_consistent(&mac); 420 if (error) 421 return (error); 422 423 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 424 error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL); 425 if (error) { 426 free(buffer, M_MACTEMP); 427 return (error); 428 } 429 430 error = fget(td, uap->fd, &fp); 431 if (error) 432 goto out; 433 434 switch (fp->f_type) { 435 case DTYPE_FIFO: 436 case DTYPE_VNODE: 437 intlabel = mac_vnode_label_alloc(); 438 error = mac_vnode_internalize_label(intlabel, buffer); 439 if (error) { 440 mac_vnode_label_free(intlabel); 441 break; 442 } 443 vp = fp->f_vnode; 444 vfslocked = VFS_LOCK_GIANT(vp->v_mount); 445 error = vn_start_write(vp, &mp, V_WAIT | PCATCH); 446 if (error != 0) { 447 VFS_UNLOCK_GIANT(vfslocked); 448 mac_vnode_label_free(intlabel); 449 break; 450 } 451 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 452 error = vn_setlabel(vp, intlabel, td->td_ucred); 453 VOP_UNLOCK(vp, 0); 454 vn_finished_write(mp); 455 VFS_UNLOCK_GIANT(vfslocked); 456 mac_vnode_label_free(intlabel); 457 break; 458 459 case DTYPE_PIPE: 460 intlabel = mac_pipe_label_alloc(); 461 error = mac_pipe_internalize_label(intlabel, buffer); 462 if (error == 0) { 463 pipe = fp->f_data; 464 PIPE_LOCK(pipe); 465 error = mac_pipe_label_set(td->td_ucred, 466 pipe->pipe_pair, intlabel); 467 PIPE_UNLOCK(pipe); 468 } 469 mac_pipe_label_free(intlabel); 470 break; 471 472 case DTYPE_SOCKET: 473 intlabel = mac_socket_label_alloc(M_WAITOK); 474 error = mac_socket_internalize_label(intlabel, buffer); 475 if (error == 0) { 476 so = fp->f_data; 477 error = mac_socket_label_set(td->td_ucred, so, 478 intlabel); 479 } 480 mac_socket_label_free(intlabel); 481 break; 482 483 default: 484 error = EINVAL; 485 } 486 fdrop(fp, td); 487 out: 488 free(buffer, M_MACTEMP); 489 return (error); 490 } 491 492 int 493 __mac_set_file(struct thread *td, struct __mac_set_file_args *uap) 494 { 495 struct label *intlabel; 496 struct nameidata nd; 497 struct mount *mp; 498 struct mac mac; 499 char *buffer; 500 int vfslocked, error; 501 502 error = copyin(uap->mac_p, &mac, sizeof(mac)); 503 if (error) 504 return (error); 505 506 error = mac_check_structmac_consistent(&mac); 507 if (error) 508 return (error); 509 510 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 511 error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL); 512 if (error) { 513 free(buffer, M_MACTEMP); 514 return (error); 515 } 516 517 intlabel = mac_vnode_label_alloc(); 518 error = mac_vnode_internalize_label(intlabel, buffer); 519 free(buffer, M_MACTEMP); 520 if (error) 521 goto out; 522 523 NDINIT(&nd, LOOKUP, MPSAFE | LOCKLEAF | FOLLOW, UIO_USERSPACE, 524 uap->path_p, td); 525 error = namei(&nd); 526 vfslocked = NDHASGIANT(&nd); 527 if (error == 0) { 528 error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH); 529 if (error == 0) { 530 error = vn_setlabel(nd.ni_vp, intlabel, 531 td->td_ucred); 532 vn_finished_write(mp); 533 } 534 } 535 536 NDFREE(&nd, 0); 537 VFS_UNLOCK_GIANT(vfslocked); 538 out: 539 mac_vnode_label_free(intlabel); 540 return (error); 541 } 542 543 int 544 __mac_set_link(struct thread *td, struct __mac_set_link_args *uap) 545 { 546 struct label *intlabel; 547 struct nameidata nd; 548 struct mount *mp; 549 struct mac mac; 550 char *buffer; 551 int vfslocked, error; 552 553 error = copyin(uap->mac_p, &mac, sizeof(mac)); 554 if (error) 555 return (error); 556 557 error = mac_check_structmac_consistent(&mac); 558 if (error) 559 return (error); 560 561 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 562 error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL); 563 if (error) { 564 free(buffer, M_MACTEMP); 565 return (error); 566 } 567 568 intlabel = mac_vnode_label_alloc(); 569 error = mac_vnode_internalize_label(intlabel, buffer); 570 free(buffer, M_MACTEMP); 571 if (error) 572 goto out; 573 574 NDINIT(&nd, LOOKUP, MPSAFE | LOCKLEAF | NOFOLLOW, UIO_USERSPACE, 575 uap->path_p, td); 576 error = namei(&nd); 577 vfslocked = NDHASGIANT(&nd); 578 if (error == 0) { 579 error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH); 580 if (error == 0) { 581 error = vn_setlabel(nd.ni_vp, intlabel, 582 td->td_ucred); 583 vn_finished_write(mp); 584 } 585 } 586 587 NDFREE(&nd, 0); 588 VFS_UNLOCK_GIANT(vfslocked); 589 out: 590 mac_vnode_label_free(intlabel); 591 return (error); 592 } 593 594 int 595 mac_syscall(struct thread *td, struct mac_syscall_args *uap) 596 { 597 struct mac_policy_conf *mpc; 598 char target[MAC_MAX_POLICY_NAME]; 599 int entrycount, error; 600 601 error = copyinstr(uap->policy, target, sizeof(target), NULL); 602 if (error) 603 return (error); 604 605 error = ENOSYS; 606 LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) { 607 if (strcmp(mpc->mpc_name, target) == 0 && 608 mpc->mpc_ops->mpo_syscall != NULL) { 609 error = mpc->mpc_ops->mpo_syscall(td, 610 uap->call, uap->arg); 611 goto out; 612 } 613 } 614 615 if ((entrycount = mac_policy_list_conditional_busy()) != 0) { 616 LIST_FOREACH(mpc, &mac_policy_list, mpc_list) { 617 if (strcmp(mpc->mpc_name, target) == 0 && 618 mpc->mpc_ops->mpo_syscall != NULL) { 619 error = mpc->mpc_ops->mpo_syscall(td, 620 uap->call, uap->arg); 621 break; 622 } 623 } 624 mac_policy_list_unbusy(); 625 } 626 out: 627 return (error); 628 } 629 630 #else /* !MAC */ 631 632 int 633 __mac_get_pid(struct thread *td, struct __mac_get_pid_args *uap) 634 { 635 636 return (ENOSYS); 637 } 638 639 int 640 __mac_get_proc(struct thread *td, struct __mac_get_proc_args *uap) 641 { 642 643 return (ENOSYS); 644 } 645 646 int 647 __mac_set_proc(struct thread *td, struct __mac_set_proc_args *uap) 648 { 649 650 return (ENOSYS); 651 } 652 653 int 654 __mac_get_fd(struct thread *td, struct __mac_get_fd_args *uap) 655 { 656 657 return (ENOSYS); 658 } 659 660 int 661 __mac_get_file(struct thread *td, struct __mac_get_file_args *uap) 662 { 663 664 return (ENOSYS); 665 } 666 667 int 668 __mac_get_link(struct thread *td, struct __mac_get_link_args *uap) 669 { 670 671 return (ENOSYS); 672 } 673 674 int 675 __mac_set_fd(struct thread *td, struct __mac_set_fd_args *uap) 676 { 677 678 return (ENOSYS); 679 } 680 681 int 682 __mac_set_file(struct thread *td, struct __mac_set_file_args *uap) 683 { 684 685 return (ENOSYS); 686 } 687 688 int 689 __mac_set_link(struct thread *td, struct __mac_set_link_args *uap) 690 { 691 692 return (ENOSYS); 693 } 694 695 int 696 mac_syscall(struct thread *td, struct mac_syscall_args *uap) 697 { 698 699 return (ENOSYS); 700 } 701 702 #endif /* !MAC */ 703