1/* 2 * Copyright (c) 2007 Apple Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28/*- 29 * Copyright (c) 1999-2002 Robert N. M. Watson 30 * Copyright (c) 2001 Ilmar S. Habibulin 31 * Copyright (c) 2001-2005 Networks Associates Technology, Inc. 32 * Copyright (c) 2005 SPARTA, Inc. 33 * All rights reserved. 34 * 35 * This software was developed by Robert Watson and Ilmar Habibulin for the 36 * TrustedBSD Project. 37 * 38 * This software was developed for the FreeBSD Project in part by McAfee 39 * Research, the Technology Research Division of Network Associates, Inc. 40 * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the 41 * DARPA CHATS research program. 42 * 43 * This software was enhanced by SPARTA ISSO under SPAWAR contract 44 * N66001-04-C-6019 ("SEFOS"). 45 * 46 * Redistribution and use in source and binary forms, with or without 47 * modification, are permitted provided that the following conditions 48 * are met: 49 * 1. Redistributions of source code must retain the above copyright 50 * notice, this list of conditions and the following disclaimer. 51 * 2. Redistributions in binary form must reproduce the above copyright 52 * notice, this list of conditions and the following disclaimer in the 53 * documentation and/or other materials provided with the distribution. 54 * 55 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 56 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 57 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 58 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 59 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 60 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 61 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 62 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 63 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 64 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 65 * SUCH DAMAGE. 66 */ 67 68#include <sys/cdefs.h> 69 70#include <sys/param.h> 71#include <sys/kernel.h> 72#include <sys/lock.h> 73#include <sys/malloc.h> 74#include <sys/sbuf.h> 75#include <sys/systm.h> 76#include <sys/mount.h> 77#include <sys/file.h> 78#include <sys/namei.h> 79#include <sys/protosw.h> 80#include <sys/socket.h> 81#include <sys/socketvar.h> 82#include <sys/sysctl.h> 83#include <sys/kpi_socket.h> 84 85#include <net/if.h> 86#include <net/if_var.h> 87 88#include <netinet/in.h> 89#include <netinet/ip_var.h> 90 91#include <security/mac_internal.h> 92 93#if CONFIG_MACF_SOCKET 94struct label * 95mac_socket_label_alloc(int flag) 96{ 97 struct label *label; 98 int error; 99 100 label = mac_labelzone_alloc(flag); 101 if (label == NULL) 102 return (NULL); 103 104 MAC_CHECK(socket_label_init, label, flag); 105 if (error) { 106 MAC_PERFORM(socket_label_destroy, label); 107 mac_labelzone_free(label); 108 return (NULL); 109 } 110 111 return (label); 112} 113 114static struct label * 115mac_socket_peer_label_alloc(int flag) 116{ 117 struct label *label; 118 int error; 119 120 label = mac_labelzone_alloc(flag); 121 if (label == NULL) 122 return (NULL); 123 124 MAC_CHECK(socketpeer_label_init, label, flag); 125 if (error) { 126 MAC_PERFORM(socketpeer_label_destroy, label); 127 mac_labelzone_free(label); 128 return (NULL); 129 } 130 131 return (label); 132} 133 134int 135mac_socket_label_init(struct socket *so, int flag) 136{ 137 138 so->so_label = mac_socket_label_alloc(flag); 139 if (so->so_label == NULL) 140 return (ENOMEM); 141 so->so_peerlabel = mac_socket_peer_label_alloc(flag); 142 if (so->so_peerlabel == NULL) { 143 mac_socket_label_free(so->so_label); 144 so->so_label = NULL; 145 return (ENOMEM); 146 } 147 return (0); 148} 149 150void 151mac_socket_label_free(struct label *label) 152{ 153 154 MAC_PERFORM(socket_label_destroy, label); 155 mac_labelzone_free(label); 156} 157 158static void 159mac_socket_peer_label_free(struct label *label) 160{ 161 162 MAC_PERFORM(socketpeer_label_destroy, label); 163 mac_labelzone_free(label); 164} 165 166void 167mac_socket_label_destroy(struct socket *so) 168{ 169 170 if (so->so_label != NULL) { 171 mac_socket_label_free(so->so_label); 172 so->so_label = NULL; 173 } 174 if (so->so_peerlabel != NULL) { 175 mac_socket_peer_label_free(so->so_peerlabel); 176 so->so_peerlabel = NULL; 177 } 178} 179 180void 181mac_socket_label_copy(struct label *src, struct label *dest) 182{ 183 184 MAC_PERFORM(socket_label_copy, src, dest); 185} 186 187int 188mac_socket_label_externalize(struct label *label, char *elements, 189 char *outbuf, size_t outbuflen) 190{ 191 int error; 192 193 error = MAC_EXTERNALIZE(socket, label, elements, outbuf, outbuflen); 194 195 return (error); 196} 197 198static int 199mac_socketpeer_label_externalize(struct label *label, char *elements, 200 char *outbuf, size_t outbuflen) 201{ 202 int error; 203 204 error = MAC_EXTERNALIZE(socketpeer, label, elements, outbuf, outbuflen); 205 206 return (error); 207} 208 209int 210mac_socket_label_internalize(struct label *label, char *string) 211{ 212 int error; 213 214 error = MAC_INTERNALIZE(socket, label, string); 215 216 return (error); 217} 218 219void 220mac_socket_label_associate(struct ucred *cred, struct socket *so) 221{ 222 if (!mac_socket_enforce) 223 return; 224 225 MAC_PERFORM(socket_label_associate, cred, 226 (socket_t)so, so->so_label); 227} 228 229void 230mac_socket_label_associate_accept(struct socket *oldsocket, 231 struct socket *newsocket) 232{ 233 if (!mac_socket_enforce) 234 return; 235 236 MAC_PERFORM(socket_label_associate_accept, 237 (socket_t)oldsocket, oldsocket->so_label, 238 (socket_t)newsocket, newsocket->so_label); 239} 240 241#if CONFIG_MACF_SOCKET && CONFIG_MACF_NET 242void 243mac_socketpeer_label_associate_mbuf(struct mbuf *mbuf, struct socket *so) 244{ 245 struct label *label; 246 247 if (!mac_socket_enforce && !mac_net_enforce) 248 return; 249 250 label = mac_mbuf_to_label(mbuf); 251 252 /* Policy must deal with NULL label (unlabeled mbufs) */ 253 MAC_PERFORM(socketpeer_label_associate_mbuf, mbuf, label, 254 (socket_t)so, so->so_peerlabel); 255} 256#else 257void 258mac_socketpeer_label_associate_mbuf(__unused struct mbuf *mbuf, 259 __unused struct socket *so) 260{ 261 return; 262} 263#endif 264 265void 266mac_socketpeer_label_associate_socket(struct socket *oldsocket, 267 struct socket *newsocket) 268{ 269 if (!mac_socket_enforce) 270 return; 271 272 MAC_PERFORM(socketpeer_label_associate_socket, 273 (socket_t)oldsocket, oldsocket->so_label, 274 (socket_t)newsocket, newsocket->so_peerlabel); 275} 276 277int 278mac_socket_check_kqfilter(kauth_cred_t cred, struct knote *kn, 279 struct socket *so) 280{ 281 int error; 282 283 if (!mac_socket_enforce) 284 return 0; 285 286 MAC_CHECK(socket_check_kqfilter, cred, kn, 287 (socket_t)so, so->so_label); 288 return (error); 289} 290 291static int 292mac_socket_check_label_update(kauth_cred_t cred, struct socket *so, 293 struct label *newlabel) 294{ 295 int error; 296 297 if (!mac_socket_enforce) 298 return 0; 299 300 MAC_CHECK(socket_check_label_update, cred, 301 (socket_t)so, so->so_label, 302 newlabel); 303 return (error); 304} 305 306int 307mac_socket_check_select(kauth_cred_t cred, struct socket *so, int which) 308{ 309 int error; 310 311 if (!mac_socket_enforce) 312 return 0; 313 314 MAC_CHECK(socket_check_select, cred, 315 (socket_t)so, so->so_label, which); 316 return (error); 317} 318 319int 320mac_socket_check_stat(kauth_cred_t cred, struct socket *so) 321{ 322 int error; 323 324 if (!mac_socket_enforce) 325 return 0; 326 327 MAC_CHECK(socket_check_stat, cred, 328 (socket_t)so, so->so_label); 329 return (error); 330} 331 332 333int 334mac_socket_label_update(kauth_cred_t cred, struct socket *so, struct label *label) 335{ 336 int error; 337#if 0 338 if (!mac_socket_enforce) 339 return; 340#endif 341 error = mac_socket_check_label_update(cred, so, label); 342 if (error) 343 return (error); 344 345 MAC_PERFORM(socket_label_update, cred, 346 (socket_t)so, so->so_label, label); 347 348#if CONFIG_MACF_NET 349 /* 350 * If the protocol has expressed interest in socket layer changes, 351 * such as if it needs to propagate changes to a cached pcb 352 * label from the socket, notify it of the label change while 353 * holding the socket lock. 354 * XXXMAC - are there cases when we should not do this? 355 */ 356 mac_inpcb_label_update(so); 357#endif 358 return (0); 359} 360 361int 362mac_setsockopt_label(kauth_cred_t cred, struct socket *so, struct mac *mac) 363{ 364 struct label *intlabel; 365 char *buffer; 366 int error; 367 size_t len; 368 369 error = mac_check_structmac_consistent(mac); 370 if (error) 371 return (error); 372 373 MALLOC(buffer, char *, mac->m_buflen, M_MACTEMP, M_WAITOK); 374 error = copyinstr(CAST_USER_ADDR_T(mac->m_string), buffer, 375 mac->m_buflen, &len); 376 if (error) { 377 FREE(buffer, M_MACTEMP); 378 return (error); 379 } 380 381 intlabel = mac_socket_label_alloc(MAC_WAITOK); 382 error = mac_socket_label_internalize(intlabel, buffer); 383 FREE(buffer, M_MACTEMP); 384 if (error) 385 goto out; 386 387 error = mac_socket_label_update(cred, so, intlabel); 388out: 389 mac_socket_label_free(intlabel); 390 return (error); 391} 392 393int 394mac_socket_label_get(__unused kauth_cred_t cred, struct socket *so, 395 struct mac *mac) 396{ 397 char *buffer, *elements; 398 struct label *intlabel; 399 int error; 400 size_t len; 401 402 error = mac_check_structmac_consistent(mac); 403 if (error) 404 return (error); 405 406 MALLOC(elements, char *, mac->m_buflen, M_MACTEMP, M_WAITOK); 407 error = copyinstr(CAST_USER_ADDR_T(mac->m_string), elements, 408 mac->m_buflen, &len); 409 if (error) { 410 FREE(elements, M_MACTEMP); 411 return (error); 412 } 413 414 MALLOC(buffer, char *, mac->m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); 415 intlabel = mac_socket_label_alloc(MAC_WAITOK); 416 mac_socket_label_copy(so->so_label, intlabel); 417 error = mac_socket_label_externalize(intlabel, elements, buffer, 418 mac->m_buflen); 419 mac_socket_label_free(intlabel); 420 if (error == 0) 421 error = copyout(buffer, CAST_USER_ADDR_T(mac->m_string), 422 strlen(buffer)+1); 423 424 FREE(buffer, M_MACTEMP); 425 FREE(elements, M_MACTEMP); 426 427 return (error); 428} 429 430int 431mac_socketpeer_label_get(__unused kauth_cred_t cred, struct socket *so, 432 struct mac *mac) 433{ 434 char *elements, *buffer; 435 struct label *intlabel; 436 int error; 437 size_t len; 438 439 error = mac_check_structmac_consistent(mac); 440 if (error) 441 return (error); 442 443 MALLOC(elements, char *, mac->m_buflen, M_MACTEMP, M_WAITOK); 444 error = copyinstr(CAST_USER_ADDR_T(mac->m_string), elements, 445 mac->m_buflen, &len); 446 if (error) { 447 FREE(elements, M_MACTEMP); 448 return (error); 449 } 450 451 MALLOC(buffer, char *, mac->m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); 452 intlabel = mac_socket_label_alloc(MAC_WAITOK); 453 mac_socket_label_copy(so->so_peerlabel, intlabel); 454 error = mac_socketpeer_label_externalize(intlabel, elements, buffer, 455 mac->m_buflen); 456 mac_socket_label_free(intlabel); 457 if (error == 0) 458 error = copyout(buffer, CAST_USER_ADDR_T(mac->m_string), 459 strlen(buffer)+1); 460 461 FREE(buffer, M_MACTEMP); 462 FREE(elements, M_MACTEMP); 463 464 return (error); 465} 466#endif /* MAC_SOCKET */ 467 468int 469mac_socket_check_accept(kauth_cred_t cred, struct socket *so) 470{ 471 int error; 472 473 if (!mac_socket_enforce) 474 return 0; 475 476 MAC_CHECK(socket_check_accept, cred, 477 (socket_t)so, so->so_label); 478 return (error); 479} 480 481int 482mac_socket_check_accepted(kauth_cred_t cred, struct socket *so) 483{ 484 struct sockaddr *sockaddr; 485 int error; 486 487 if (!mac_socket_enforce) 488 return 0; 489 490 if (sock_getaddr((socket_t)so, &sockaddr, 1) != 0) { 491 error = ECONNABORTED; 492 } else { 493 MAC_CHECK(socket_check_accepted, cred, 494 (socket_t)so, so->so_label, sockaddr); 495 sock_freeaddr(sockaddr); 496 } 497 return (error); 498} 499 500int 501mac_socket_check_bind(kauth_cred_t ucred, struct socket *so, 502 struct sockaddr *sockaddr) 503{ 504 int error; 505 506 if (!mac_socket_enforce) 507 return 0; 508 509 MAC_CHECK(socket_check_bind, ucred, 510 (socket_t)so, so->so_label, sockaddr); 511 return (error); 512} 513 514int 515mac_socket_check_connect(kauth_cred_t cred, struct socket *so, 516 struct sockaddr *sockaddr) 517{ 518 int error; 519 520 if (!mac_socket_enforce) 521 return 0; 522 523 MAC_CHECK(socket_check_connect, cred, 524 (socket_t)so, so->so_label, 525 sockaddr); 526 return (error); 527} 528 529int 530mac_socket_check_create(kauth_cred_t cred, int domain, int type, int protocol) 531{ 532 int error; 533 534 if (!mac_socket_enforce) 535 return 0; 536 537 MAC_CHECK(socket_check_create, cred, domain, type, protocol); 538 return (error); 539} 540 541#if CONFIG_MACF_SOCKET && CONFIG_MACF_NET 542int 543mac_socket_check_deliver(struct socket *so, struct mbuf *mbuf) 544{ 545 struct label *label; 546 int error; 547 548 if (!mac_socket_enforce) 549 return 0; 550 551 label = mac_mbuf_to_label(mbuf); 552 553 /* Policy must deal with NULL label (unlabeled mbufs) */ 554 MAC_CHECK(socket_check_deliver, 555 (socket_t)so, so->so_label, mbuf, label); 556 return (error); 557} 558#else 559int 560mac_socket_check_deliver(__unused struct socket *so, __unused struct mbuf *mbuf) 561{ 562 return (0); 563} 564#endif 565 566int 567mac_socket_check_listen(kauth_cred_t cred, struct socket *so) 568{ 569 int error; 570 571 if (!mac_socket_enforce) 572 return 0; 573 574 MAC_CHECK(socket_check_listen, cred, 575 (socket_t)so, so->so_label); 576 return (error); 577} 578 579int 580mac_socket_check_receive(kauth_cred_t cred, struct socket *so) 581{ 582 int error; 583 584 if (!mac_socket_enforce) 585 return 0; 586 587 MAC_CHECK(socket_check_receive, cred, 588 (socket_t)so, so->so_label); 589 return (error); 590} 591 592int 593mac_socket_check_received(kauth_cred_t cred, struct socket *so, struct sockaddr *saddr) 594{ 595 int error; 596 597 if (!mac_socket_enforce) 598 return 0; 599 600 MAC_CHECK(socket_check_received, cred, 601 (socket_t)so, so->so_label, saddr); 602 return (error); 603} 604 605int 606mac_socket_check_send(kauth_cred_t cred, struct socket *so, 607 struct sockaddr *sockaddr) 608{ 609 int error; 610 611 if (!mac_socket_enforce) 612 return 0; 613 614 MAC_CHECK(socket_check_send, cred, 615 (socket_t)so, so->so_label, sockaddr); 616 return (error); 617} 618 619int 620mac_socket_check_setsockopt(kauth_cred_t cred, struct socket *so, 621 struct sockopt *sopt) 622{ 623 int error; 624 625 if (!mac_socket_enforce) 626 return (0); 627 628 MAC_CHECK(socket_check_setsockopt, cred, 629 (socket_t)so, so->so_label, sopt); 630 return (error); 631} 632 633int mac_socket_check_getsockopt(kauth_cred_t cred, struct socket *so, 634 struct sockopt *sopt) 635{ 636 int error; 637 638 if (!mac_socket_enforce) 639 return (0); 640 641 MAC_CHECK(socket_check_getsockopt, cred, 642 (socket_t)so, so->so_label, sopt); 643 return (error); 644} 645