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