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 77FEATURE(security_mac, "Mandatory Access Control Framework support"); 78 79static int kern___mac_get_path(struct thread *td, const char *path_p, 80 struct mac *mac_p, int follow); 81static int kern___mac_set_path(struct thread *td, const char *path_p, 82 struct mac *mac_p, int follow); 83 84int 85sys___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 133int 134sys___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 166int 167sys___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 222out: 223 mac_cred_label_free(intlabel); 224 return (error); 225} 226 227int 228sys___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, 0); 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); 312out_fdrop: 313 fdrop(fp, td); 314out: 315 free(buffer, M_MACTEMP); 316 free(elements, M_MACTEMP); 317 return (error); 318} 319 320int 321sys___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 327int 328sys___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 334static int 335kern___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 378out: 379 free(buffer, M_MACTEMP); 380 free(elements, M_MACTEMP); 381 382 return (error); 383} 384 385int 386sys___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, 0); 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 } 479out_fdrop: 480 fdrop(fp, td); 481out: 482 free(buffer, M_MACTEMP); 483 return (error); 484} 485 486int 487sys___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 493int 494sys___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 500static int 501kern___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); 547out: 548 mac_vnode_label_free(intlabel); 549 return (error); 550} 551 552int 553sys_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 } 585out: 586 return (error); 587} 588 589#else /* !MAC */ 590 591int 592sys___mac_get_pid(struct thread *td, struct __mac_get_pid_args *uap) 593{ 594 595 return (ENOSYS); 596} 597 598int 599sys___mac_get_proc(struct thread *td, struct __mac_get_proc_args *uap) 600{ 601 602 return (ENOSYS); 603} 604 605int 606sys___mac_set_proc(struct thread *td, struct __mac_set_proc_args *uap) 607{ 608 609 return (ENOSYS); 610} 611 612int 613sys___mac_get_fd(struct thread *td, struct __mac_get_fd_args *uap) 614{ 615 616 return (ENOSYS); 617} 618 619int 620sys___mac_get_file(struct thread *td, struct __mac_get_file_args *uap) 621{ 622 623 return (ENOSYS); 624} 625 626int 627sys___mac_get_link(struct thread *td, struct __mac_get_link_args *uap) 628{ 629 630 return (ENOSYS); 631} 632 633int 634sys___mac_set_fd(struct thread *td, struct __mac_set_fd_args *uap) 635{ 636 637 return (ENOSYS); 638} 639 640int 641sys___mac_set_file(struct thread *td, struct __mac_set_file_args *uap) 642{ 643 644 return (ENOSYS); 645} 646 647int 648sys___mac_set_link(struct thread *td, struct __mac_set_link_args *uap) 649{ 650 651 return (ENOSYS); 652} 653 654int 655sys_mac_syscall(struct thread *td, struct mac_syscall_args *uap) 656{ 657 658 return (ENOSYS); 659} 660 661#endif /* !MAC */ 662