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 vput(nd.ni_vp); 373 NDFREE_PNBUF(&nd); 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 | V_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 | V_PCATCH); 541 if (error == 0) { 542 error = vn_setlabel(nd.ni_vp, intlabel, 543 td->td_ucred); 544 vn_finished_write(mp); 545 } 546 vput(nd.ni_vp); 547 NDFREE_PNBUF(&nd); 548 } 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