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 #include "opt_mac.h" 47 48 #include <sys/param.h> 49 #include <sys/capsicum.h> 50 #include <sys/fcntl.h> 51 #include <sys/kernel.h> 52 #include <sys/lock.h> 53 #include <sys/malloc.h> 54 #include <sys/mutex.h> 55 #include <sys/mac.h> 56 #include <sys/proc.h> 57 #include <sys/systm.h> 58 #include <sys/sysctl.h> 59 #include <sys/sysproto.h> 60 #include <sys/vnode.h> 61 #include <sys/mount.h> 62 #include <sys/file.h> 63 #include <sys/namei.h> 64 #include <sys/socket.h> 65 #include <sys/pipe.h> 66 #include <sys/socketvar.h> 67 68 #include <security/mac/mac_framework.h> 69 #include <security/mac/mac_internal.h> 70 #include <security/mac/mac_policy.h> 71 72 #ifdef MAC 73 74 FEATURE(security_mac, "Mandatory Access Control Framework support"); 75 76 static int kern___mac_get_path(struct thread *td, const char *path_p, 77 struct mac *mac_p, int follow); 78 static int kern___mac_set_path(struct thread *td, const char *path_p, 79 struct mac *mac_p, int follow); 80 81 int 82 sys___mac_get_pid(struct thread *td, struct __mac_get_pid_args *uap) 83 { 84 char *elements, *buffer; 85 struct mac mac; 86 struct proc *tproc; 87 struct ucred *tcred; 88 int error; 89 90 error = copyin(uap->mac_p, &mac, sizeof(mac)); 91 if (error) 92 return (error); 93 94 error = mac_check_structmac_consistent(&mac); 95 if (error) 96 return (error); 97 98 tproc = pfind(uap->pid); 99 if (tproc == NULL) 100 return (ESRCH); 101 102 tcred = NULL; /* Satisfy gcc. */ 103 error = p_cansee(td, tproc); 104 if (error == 0) 105 tcred = crhold(tproc->p_ucred); 106 PROC_UNLOCK(tproc); 107 if (error) 108 return (error); 109 110 elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 111 error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL); 112 if (error) { 113 free(elements, M_MACTEMP); 114 crfree(tcred); 115 return (error); 116 } 117 118 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); 119 error = mac_cred_externalize_label(tcred->cr_label, elements, 120 buffer, mac.m_buflen); 121 if (error == 0) 122 error = copyout(buffer, mac.m_string, strlen(buffer)+1); 123 124 free(buffer, M_MACTEMP); 125 free(elements, M_MACTEMP); 126 crfree(tcred); 127 return (error); 128 } 129 130 int 131 sys___mac_get_proc(struct thread *td, struct __mac_get_proc_args *uap) 132 { 133 char *elements, *buffer; 134 struct mac mac; 135 int error; 136 137 error = copyin(uap->mac_p, &mac, sizeof(mac)); 138 if (error) 139 return (error); 140 141 error = mac_check_structmac_consistent(&mac); 142 if (error) 143 return (error); 144 145 elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 146 error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL); 147 if (error) { 148 free(elements, M_MACTEMP); 149 return (error); 150 } 151 152 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); 153 error = mac_cred_externalize_label(td->td_ucred->cr_label, 154 elements, buffer, mac.m_buflen); 155 if (error == 0) 156 error = copyout(buffer, mac.m_string, strlen(buffer)+1); 157 158 free(buffer, M_MACTEMP); 159 free(elements, M_MACTEMP); 160 return (error); 161 } 162 163 int 164 sys___mac_set_proc(struct thread *td, struct __mac_set_proc_args *uap) 165 { 166 struct ucred *newcred, *oldcred; 167 struct label *intlabel; 168 struct proc *p; 169 struct mac mac; 170 char *buffer; 171 int error; 172 173 if (!(mac_labeled & MPC_OBJECT_CRED)) 174 return (EINVAL); 175 176 error = copyin(uap->mac_p, &mac, sizeof(mac)); 177 if (error) 178 return (error); 179 180 error = mac_check_structmac_consistent(&mac); 181 if (error) 182 return (error); 183 184 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 185 error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL); 186 if (error) { 187 free(buffer, M_MACTEMP); 188 return (error); 189 } 190 191 intlabel = mac_cred_label_alloc(); 192 error = mac_cred_internalize_label(intlabel, buffer); 193 free(buffer, M_MACTEMP); 194 if (error) 195 goto out; 196 197 newcred = crget(); 198 199 p = td->td_proc; 200 PROC_LOCK(p); 201 oldcred = p->p_ucred; 202 203 error = mac_cred_check_relabel(oldcred, intlabel); 204 if (error) { 205 PROC_UNLOCK(p); 206 crfree(newcred); 207 goto out; 208 } 209 210 setsugid(p); 211 crcopy(newcred, oldcred); 212 mac_cred_relabel(newcred, intlabel); 213 proc_set_cred(p, newcred); 214 215 PROC_UNLOCK(p); 216 crfree(oldcred); 217 mac_proc_vm_revoke(td); 218 219 out: 220 mac_cred_label_free(intlabel); 221 return (error); 222 } 223 224 int 225 sys___mac_get_fd(struct thread *td, struct __mac_get_fd_args *uap) 226 { 227 char *elements, *buffer; 228 struct label *intlabel; 229 struct file *fp; 230 struct mac mac; 231 struct vnode *vp; 232 struct pipe *pipe; 233 struct socket *so; 234 cap_rights_t rights; 235 int error; 236 237 error = copyin(uap->mac_p, &mac, sizeof(mac)); 238 if (error) 239 return (error); 240 241 error = mac_check_structmac_consistent(&mac); 242 if (error) 243 return (error); 244 245 elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 246 error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL); 247 if (error) { 248 free(elements, M_MACTEMP); 249 return (error); 250 } 251 252 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); 253 error = fget(td, uap->fd, cap_rights_init_one(&rights, CAP_MAC_GET), 254 &fp); 255 if (error) 256 goto out; 257 258 switch (fp->f_type) { 259 case DTYPE_FIFO: 260 case DTYPE_VNODE: 261 if (!(mac_labeled & MPC_OBJECT_VNODE)) { 262 error = EINVAL; 263 goto out_fdrop; 264 } 265 vp = fp->f_vnode; 266 intlabel = mac_vnode_label_alloc(); 267 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 268 mac_vnode_copy_label(vp->v_label, intlabel); 269 VOP_UNLOCK(vp); 270 error = mac_vnode_externalize_label(intlabel, elements, 271 buffer, mac.m_buflen); 272 mac_vnode_label_free(intlabel); 273 break; 274 275 case DTYPE_PIPE: 276 if (!(mac_labeled & MPC_OBJECT_PIPE)) { 277 error = EINVAL; 278 goto out_fdrop; 279 } 280 pipe = fp->f_data; 281 intlabel = mac_pipe_label_alloc(); 282 PIPE_LOCK(pipe); 283 mac_pipe_copy_label(pipe->pipe_pair->pp_label, intlabel); 284 PIPE_UNLOCK(pipe); 285 error = mac_pipe_externalize_label(intlabel, elements, 286 buffer, mac.m_buflen); 287 mac_pipe_label_free(intlabel); 288 break; 289 290 case DTYPE_SOCKET: 291 if (!(mac_labeled & MPC_OBJECT_SOCKET)) { 292 error = EINVAL; 293 goto out_fdrop; 294 } 295 so = fp->f_data; 296 intlabel = mac_socket_label_alloc(M_WAITOK); 297 SOCK_LOCK(so); 298 mac_socket_copy_label(so->so_label, intlabel); 299 SOCK_UNLOCK(so); 300 error = mac_socket_externalize_label(intlabel, elements, 301 buffer, mac.m_buflen); 302 mac_socket_label_free(intlabel); 303 break; 304 305 default: 306 error = EINVAL; 307 } 308 if (error == 0) 309 error = copyout(buffer, mac.m_string, strlen(buffer)+1); 310 out_fdrop: 311 fdrop(fp, td); 312 out: 313 free(buffer, M_MACTEMP); 314 free(elements, M_MACTEMP); 315 return (error); 316 } 317 318 int 319 sys___mac_get_file(struct thread *td, struct __mac_get_file_args *uap) 320 { 321 322 return (kern___mac_get_path(td, uap->path_p, uap->mac_p, FOLLOW)); 323 } 324 325 int 326 sys___mac_get_link(struct thread *td, struct __mac_get_link_args *uap) 327 { 328 329 return (kern___mac_get_path(td, uap->path_p, uap->mac_p, NOFOLLOW)); 330 } 331 332 static int 333 kern___mac_get_path(struct thread *td, const char *path_p, struct mac *mac_p, 334 int follow) 335 { 336 char *elements, *buffer; 337 struct nameidata nd; 338 struct label *intlabel; 339 struct mac mac; 340 int error; 341 342 if (!(mac_labeled & MPC_OBJECT_VNODE)) 343 return (EINVAL); 344 345 error = copyin(mac_p, &mac, sizeof(mac)); 346 if (error) 347 return (error); 348 349 error = mac_check_structmac_consistent(&mac); 350 if (error) 351 return (error); 352 353 elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 354 error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL); 355 if (error) { 356 free(elements, M_MACTEMP); 357 return (error); 358 } 359 360 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); 361 NDINIT(&nd, LOOKUP, LOCKLEAF | follow, UIO_USERSPACE, path_p); 362 error = namei(&nd); 363 if (error) 364 goto out; 365 366 intlabel = mac_vnode_label_alloc(); 367 mac_vnode_copy_label(nd.ni_vp->v_label, intlabel); 368 error = mac_vnode_externalize_label(intlabel, elements, buffer, 369 mac.m_buflen); 370 vput(nd.ni_vp); 371 NDFREE_PNBUF(&nd); 372 mac_vnode_label_free(intlabel); 373 374 if (error == 0) 375 error = copyout(buffer, mac.m_string, strlen(buffer)+1); 376 377 out: 378 free(buffer, M_MACTEMP); 379 free(elements, M_MACTEMP); 380 381 return (error); 382 } 383 384 int 385 sys___mac_set_fd(struct thread *td, struct __mac_set_fd_args *uap) 386 { 387 struct label *intlabel; 388 struct pipe *pipe; 389 struct socket *so; 390 struct file *fp; 391 struct mount *mp; 392 struct vnode *vp; 393 struct mac mac; 394 cap_rights_t rights; 395 char *buffer; 396 int error; 397 398 error = copyin(uap->mac_p, &mac, sizeof(mac)); 399 if (error) 400 return (error); 401 402 error = mac_check_structmac_consistent(&mac); 403 if (error) 404 return (error); 405 406 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 407 error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL); 408 if (error) { 409 free(buffer, M_MACTEMP); 410 return (error); 411 } 412 413 error = fget(td, uap->fd, cap_rights_init_one(&rights, CAP_MAC_SET), 414 &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 | V_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); 536 error = namei(&nd); 537 if (error == 0) { 538 error = vn_start_write(nd.ni_vp, &mp, V_WAIT | V_PCATCH); 539 if (error == 0) { 540 error = vn_setlabel(nd.ni_vp, intlabel, 541 td->td_ucred); 542 vn_finished_write(mp); 543 } 544 vput(nd.ni_vp); 545 NDFREE_PNBUF(&nd); 546 } 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