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