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/sysent.h> 63 #include <sys/vnode.h> 64 #include <sys/mount.h> 65 #include <sys/file.h> 66 #include <sys/namei.h> 67 #include <sys/socket.h> 68 #include <sys/pipe.h> 69 #include <sys/socketvar.h> 70 71 #include <security/mac/mac_framework.h> 72 #include <security/mac/mac_internal.h> 73 #include <security/mac/mac_policy.h> 74 75 #ifdef MAC 76 77 FEATURE(security_mac, "Mandatory Access Control Framework support"); 78 79 static int kern___mac_get_path(struct thread *td, const char *path_p, 80 struct mac *mac_p, int follow); 81 static int kern___mac_set_path(struct thread *td, const char *path_p, 82 struct mac *mac_p, int follow); 83 84 int 85 sys___mac_get_pid(struct thread *td, struct __mac_get_pid_args *uap) 86 { 87 char *elements, *buffer; 88 struct mac mac; 89 struct proc *tproc; 90 struct ucred *tcred; 91 int error; 92 93 error = copyin(uap->mac_p, &mac, sizeof(mac)); 94 if (error) 95 return (error); 96 97 error = mac_check_structmac_consistent(&mac); 98 if (error) 99 return (error); 100 101 tproc = pfind(uap->pid); 102 if (tproc == NULL) 103 return (ESRCH); 104 105 tcred = NULL; /* Satisfy gcc. */ 106 error = p_cansee(td, tproc); 107 if (error == 0) 108 tcred = crhold(tproc->p_ucred); 109 PROC_UNLOCK(tproc); 110 if (error) 111 return (error); 112 113 elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 114 error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL); 115 if (error) { 116 free(elements, M_MACTEMP); 117 crfree(tcred); 118 return (error); 119 } 120 121 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); 122 error = mac_cred_externalize_label(tcred->cr_label, elements, 123 buffer, mac.m_buflen); 124 if (error == 0) 125 error = copyout(buffer, mac.m_string, strlen(buffer)+1); 126 127 free(buffer, M_MACTEMP); 128 free(elements, M_MACTEMP); 129 crfree(tcred); 130 return (error); 131 } 132 133 int 134 sys___mac_get_proc(struct thread *td, struct __mac_get_proc_args *uap) 135 { 136 char *elements, *buffer; 137 struct mac mac; 138 int error; 139 140 error = copyin(uap->mac_p, &mac, sizeof(mac)); 141 if (error) 142 return (error); 143 144 error = mac_check_structmac_consistent(&mac); 145 if (error) 146 return (error); 147 148 elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 149 error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL); 150 if (error) { 151 free(elements, M_MACTEMP); 152 return (error); 153 } 154 155 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); 156 error = mac_cred_externalize_label(td->td_ucred->cr_label, 157 elements, buffer, mac.m_buflen); 158 if (error == 0) 159 error = copyout(buffer, mac.m_string, strlen(buffer)+1); 160 161 free(buffer, M_MACTEMP); 162 free(elements, M_MACTEMP); 163 return (error); 164 } 165 166 int 167 sys___mac_set_proc(struct thread *td, struct __mac_set_proc_args *uap) 168 { 169 struct ucred *newcred, *oldcred; 170 struct label *intlabel; 171 struct proc *p; 172 struct mac mac; 173 char *buffer; 174 int error; 175 176 if (!(mac_labeled & MPC_OBJECT_CRED)) 177 return (EINVAL); 178 179 error = copyin(uap->mac_p, &mac, sizeof(mac)); 180 if (error) 181 return (error); 182 183 error = mac_check_structmac_consistent(&mac); 184 if (error) 185 return (error); 186 187 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 188 error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL); 189 if (error) { 190 free(buffer, M_MACTEMP); 191 return (error); 192 } 193 194 intlabel = mac_cred_label_alloc(); 195 error = mac_cred_internalize_label(intlabel, buffer); 196 free(buffer, M_MACTEMP); 197 if (error) 198 goto out; 199 200 newcred = crget(); 201 202 p = td->td_proc; 203 PROC_LOCK(p); 204 oldcred = p->p_ucred; 205 206 error = mac_cred_check_relabel(oldcred, intlabel); 207 if (error) { 208 PROC_UNLOCK(p); 209 crfree(newcred); 210 goto out; 211 } 212 213 setsugid(p); 214 crcopy(newcred, oldcred); 215 mac_cred_relabel(newcred, intlabel); 216 proc_set_cred(p, newcred); 217 218 PROC_UNLOCK(p); 219 crfree(oldcred); 220 mac_proc_vm_revoke(td); 221 222 out: 223 mac_cred_label_free(intlabel); 224 return (error); 225 } 226 227 int 228 sys___mac_get_fd(struct thread *td, struct __mac_get_fd_args *uap) 229 { 230 char *elements, *buffer; 231 struct label *intlabel; 232 struct file *fp; 233 struct mac mac; 234 struct vnode *vp; 235 struct pipe *pipe; 236 struct socket *so; 237 cap_rights_t rights; 238 int error; 239 240 error = copyin(uap->mac_p, &mac, sizeof(mac)); 241 if (error) 242 return (error); 243 244 error = mac_check_structmac_consistent(&mac); 245 if (error) 246 return (error); 247 248 elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 249 error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL); 250 if (error) { 251 free(elements, M_MACTEMP); 252 return (error); 253 } 254 255 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); 256 error = fget(td, uap->fd, cap_rights_init(&rights, CAP_MAC_GET), &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, td); 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(&rights, CAP_MAC_SET), &fp); 415 if (error) 416 goto out; 417 418 switch (fp->f_type) { 419 case DTYPE_FIFO: 420 case DTYPE_VNODE: 421 if (!(mac_labeled & MPC_OBJECT_VNODE)) { 422 error = EINVAL; 423 goto out_fdrop; 424 } 425 intlabel = mac_vnode_label_alloc(); 426 error = mac_vnode_internalize_label(intlabel, buffer); 427 if (error) { 428 mac_vnode_label_free(intlabel); 429 break; 430 } 431 vp = fp->f_vnode; 432 error = vn_start_write(vp, &mp, V_WAIT | PCATCH); 433 if (error != 0) { 434 mac_vnode_label_free(intlabel); 435 break; 436 } 437 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 438 error = vn_setlabel(vp, intlabel, td->td_ucred); 439 VOP_UNLOCK(vp); 440 vn_finished_write(mp); 441 mac_vnode_label_free(intlabel); 442 break; 443 444 case DTYPE_PIPE: 445 if (!(mac_labeled & MPC_OBJECT_PIPE)) { 446 error = EINVAL; 447 goto out_fdrop; 448 } 449 intlabel = mac_pipe_label_alloc(); 450 error = mac_pipe_internalize_label(intlabel, buffer); 451 if (error == 0) { 452 pipe = fp->f_data; 453 PIPE_LOCK(pipe); 454 error = mac_pipe_label_set(td->td_ucred, 455 pipe->pipe_pair, intlabel); 456 PIPE_UNLOCK(pipe); 457 } 458 mac_pipe_label_free(intlabel); 459 break; 460 461 case DTYPE_SOCKET: 462 if (!(mac_labeled & MPC_OBJECT_SOCKET)) { 463 error = EINVAL; 464 goto out_fdrop; 465 } 466 intlabel = mac_socket_label_alloc(M_WAITOK); 467 error = mac_socket_internalize_label(intlabel, buffer); 468 if (error == 0) { 469 so = fp->f_data; 470 error = mac_socket_label_set(td->td_ucred, so, 471 intlabel); 472 } 473 mac_socket_label_free(intlabel); 474 break; 475 476 default: 477 error = EINVAL; 478 } 479 out_fdrop: 480 fdrop(fp, td); 481 out: 482 free(buffer, M_MACTEMP); 483 return (error); 484 } 485 486 int 487 sys___mac_set_file(struct thread *td, struct __mac_set_file_args *uap) 488 { 489 490 return (kern___mac_set_path(td, uap->path_p, uap->mac_p, FOLLOW)); 491 } 492 493 int 494 sys___mac_set_link(struct thread *td, struct __mac_set_link_args *uap) 495 { 496 497 return (kern___mac_set_path(td, uap->path_p, uap->mac_p, NOFOLLOW)); 498 } 499 500 static int 501 kern___mac_set_path(struct thread *td, const char *path_p, struct mac *mac_p, 502 int follow) 503 { 504 struct label *intlabel; 505 struct nameidata nd; 506 struct mount *mp; 507 struct mac mac; 508 char *buffer; 509 int error; 510 511 if (!(mac_labeled & MPC_OBJECT_VNODE)) 512 return (EINVAL); 513 514 error = copyin(mac_p, &mac, sizeof(mac)); 515 if (error) 516 return (error); 517 518 error = mac_check_structmac_consistent(&mac); 519 if (error) 520 return (error); 521 522 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 523 error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL); 524 if (error) { 525 free(buffer, M_MACTEMP); 526 return (error); 527 } 528 529 intlabel = mac_vnode_label_alloc(); 530 error = mac_vnode_internalize_label(intlabel, buffer); 531 free(buffer, M_MACTEMP); 532 if (error) 533 goto out; 534 535 NDINIT(&nd, LOOKUP, LOCKLEAF | follow, UIO_USERSPACE, path_p, td); 536 error = namei(&nd); 537 if (error == 0) { 538 error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH); 539 if (error == 0) { 540 error = vn_setlabel(nd.ni_vp, intlabel, 541 td->td_ucred); 542 vn_finished_write(mp); 543 } 544 } 545 546 NDFREE(&nd, 0); 547 out: 548 mac_vnode_label_free(intlabel); 549 return (error); 550 } 551 552 int 553 sys_mac_syscall(struct thread *td, struct mac_syscall_args *uap) 554 { 555 struct mac_policy_conf *mpc; 556 char target[MAC_MAX_POLICY_NAME]; 557 int error; 558 559 error = copyinstr(uap->policy, target, sizeof(target), NULL); 560 if (error) 561 return (error); 562 563 error = ENOSYS; 564 LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) { 565 if (strcmp(mpc->mpc_name, target) == 0 && 566 mpc->mpc_ops->mpo_syscall != NULL) { 567 error = mpc->mpc_ops->mpo_syscall(td, 568 uap->call, uap->arg); 569 goto out; 570 } 571 } 572 573 if (!LIST_EMPTY(&mac_policy_list)) { 574 mac_policy_slock_sleep(); 575 LIST_FOREACH(mpc, &mac_policy_list, mpc_list) { 576 if (strcmp(mpc->mpc_name, target) == 0 && 577 mpc->mpc_ops->mpo_syscall != NULL) { 578 error = mpc->mpc_ops->mpo_syscall(td, 579 uap->call, uap->arg); 580 break; 581 } 582 } 583 mac_policy_sunlock_sleep(); 584 } 585 out: 586 return (error); 587 } 588 589 #else /* !MAC */ 590 591 int 592 sys___mac_get_pid(struct thread *td, struct __mac_get_pid_args *uap) 593 { 594 595 return (ENOSYS); 596 } 597 598 int 599 sys___mac_get_proc(struct thread *td, struct __mac_get_proc_args *uap) 600 { 601 602 return (ENOSYS); 603 } 604 605 int 606 sys___mac_set_proc(struct thread *td, struct __mac_set_proc_args *uap) 607 { 608 609 return (ENOSYS); 610 } 611 612 int 613 sys___mac_get_fd(struct thread *td, struct __mac_get_fd_args *uap) 614 { 615 616 return (ENOSYS); 617 } 618 619 int 620 sys___mac_get_file(struct thread *td, struct __mac_get_file_args *uap) 621 { 622 623 return (ENOSYS); 624 } 625 626 int 627 sys___mac_get_link(struct thread *td, struct __mac_get_link_args *uap) 628 { 629 630 return (ENOSYS); 631 } 632 633 int 634 sys___mac_set_fd(struct thread *td, struct __mac_set_fd_args *uap) 635 { 636 637 return (ENOSYS); 638 } 639 640 int 641 sys___mac_set_file(struct thread *td, struct __mac_set_file_args *uap) 642 { 643 644 return (ENOSYS); 645 } 646 647 int 648 sys___mac_set_link(struct thread *td, struct __mac_set_link_args *uap) 649 { 650 651 return (ENOSYS); 652 } 653 654 int 655 sys_mac_syscall(struct thread *td, struct mac_syscall_args *uap) 656 { 657 658 return (ENOSYS); 659 } 660 661 #endif /* !MAC */ 662