1/* 2 * Copyright (c) 2007-2012 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 <security/mac_internal.h> 86 87#if CONFIG_MACF_SOCKET 88struct label * 89mac_socket_label_alloc(int flag) 90{ 91 struct label *label; 92 int error; 93 94 label = mac_labelzone_alloc(flag); 95 if (label == NULL) 96 return (NULL); 97 98 MAC_CHECK(socket_label_init, label, flag); 99 if (error) { 100 MAC_PERFORM(socket_label_destroy, label); 101 mac_labelzone_free(label); 102 return (NULL); 103 } 104 105 return (label); 106} 107 108static struct label * 109mac_socket_peer_label_alloc(int flag) 110{ 111 struct label *label; 112 int error; 113 114 label = mac_labelzone_alloc(flag); 115 if (label == NULL) 116 return (NULL); 117 118 MAC_CHECK(socketpeer_label_init, label, flag); 119 if (error) { 120 MAC_PERFORM(socketpeer_label_destroy, label); 121 mac_labelzone_free(label); 122 return (NULL); 123 } 124 125 return (label); 126} 127 128int 129mac_socket_label_init(struct socket *so, int flag) 130{ 131 132 so->so_label = mac_socket_label_alloc(flag); 133 if (so->so_label == NULL) 134 return (ENOMEM); 135 so->so_peerlabel = mac_socket_peer_label_alloc(flag); 136 if (so->so_peerlabel == NULL) { 137 mac_socket_label_free(so->so_label); 138 so->so_label = NULL; 139 return (ENOMEM); 140 } 141 return (0); 142} 143 144void 145mac_socket_label_free(struct label *label) 146{ 147 148 MAC_PERFORM(socket_label_destroy, label); 149 mac_labelzone_free(label); 150} 151 152static void 153mac_socket_peer_label_free(struct label *label) 154{ 155 156 MAC_PERFORM(socketpeer_label_destroy, label); 157 mac_labelzone_free(label); 158} 159 160void 161mac_socket_label_destroy(struct socket *so) 162{ 163 164 if (so->so_label != NULL) { 165 mac_socket_label_free(so->so_label); 166 so->so_label = NULL; 167 } 168 if (so->so_peerlabel != NULL) { 169 mac_socket_peer_label_free(so->so_peerlabel); 170 so->so_peerlabel = NULL; 171 } 172} 173 174void 175mac_socket_label_copy(struct label *src, struct label *dest) 176{ 177 178 MAC_PERFORM(socket_label_copy, src, dest); 179} 180 181int 182mac_socket_label_externalize(struct label *label, char *elements, 183 char *outbuf, size_t outbuflen) 184{ 185 int error; 186 187 error = MAC_EXTERNALIZE(socket, label, elements, outbuf, outbuflen); 188 189 return (error); 190} 191 192static int 193mac_socketpeer_label_externalize(struct label *label, char *elements, 194 char *outbuf, size_t outbuflen) 195{ 196 int error; 197 198 error = MAC_EXTERNALIZE(socketpeer, label, elements, outbuf, outbuflen); 199 200 return (error); 201} 202 203int 204mac_socket_label_internalize(struct label *label, char *string) 205{ 206 int error; 207 208 error = MAC_INTERNALIZE(socket, label, string); 209 210 return (error); 211} 212 213void 214mac_socket_label_associate(struct ucred *cred, struct socket *so) 215{ 216 if (!mac_socket_enforce) 217 return; 218 219 MAC_PERFORM(socket_label_associate, cred, 220 (socket_t)so, so->so_label); 221} 222 223void 224mac_socket_label_associate_accept(struct socket *oldsocket, 225 struct socket *newsocket) 226{ 227 if (!mac_socket_enforce) 228 return; 229 230 MAC_PERFORM(socket_label_associate_accept, 231 (socket_t)oldsocket, oldsocket->so_label, 232 (socket_t)newsocket, newsocket->so_label); 233} 234 235#if CONFIG_MACF_SOCKET && CONFIG_MACF_NET 236void 237mac_socketpeer_label_associate_mbuf(struct mbuf *mbuf, struct socket *so) 238{ 239 struct label *label; 240 241 if (!mac_socket_enforce && !mac_net_enforce) 242 return; 243 244 label = mac_mbuf_to_label(mbuf); 245 246 /* Policy must deal with NULL label (unlabeled mbufs) */ 247 MAC_PERFORM(socketpeer_label_associate_mbuf, mbuf, label, 248 (socket_t)so, so->so_peerlabel); 249} 250#else 251void 252mac_socketpeer_label_associate_mbuf(__unused struct mbuf *mbuf, 253 __unused struct socket *so) 254{ 255 return; 256} 257#endif 258 259void 260mac_socketpeer_label_associate_socket(struct socket *oldsocket, 261 struct socket *newsocket) 262{ 263 if (!mac_socket_enforce) 264 return; 265 266 MAC_PERFORM(socketpeer_label_associate_socket, 267 (socket_t)oldsocket, oldsocket->so_label, 268 (socket_t)newsocket, newsocket->so_peerlabel); 269} 270 271int 272mac_socket_check_kqfilter(kauth_cred_t cred, struct knote *kn, 273 struct socket *so) 274{ 275 int error; 276 277 if (!mac_socket_enforce) 278 return 0; 279 280 MAC_CHECK(socket_check_kqfilter, cred, kn, 281 (socket_t)so, so->so_label); 282 return (error); 283} 284 285static int 286mac_socket_check_label_update(kauth_cred_t cred, struct socket *so, 287 struct label *newlabel) 288{ 289 int error; 290 291 if (!mac_socket_enforce) 292 return 0; 293 294 MAC_CHECK(socket_check_label_update, cred, 295 (socket_t)so, so->so_label, 296 newlabel); 297 return (error); 298} 299 300int 301mac_socket_check_select(kauth_cred_t cred, struct socket *so, int which) 302{ 303 int error; 304 305 if (!mac_socket_enforce) 306 return 0; 307 308 MAC_CHECK(socket_check_select, cred, 309 (socket_t)so, so->so_label, which); 310 return (error); 311} 312 313int 314mac_socket_check_stat(kauth_cred_t cred, struct socket *so) 315{ 316 int error; 317 318 if (!mac_socket_enforce) 319 return 0; 320 321 MAC_CHECK(socket_check_stat, cred, 322 (socket_t)so, so->so_label); 323 return (error); 324} 325 326 327int 328mac_socket_label_update(kauth_cred_t cred, struct socket *so, struct label *label) 329{ 330 int error; 331#if 0 332 if (!mac_socket_enforce) 333 return; 334#endif 335 error = mac_socket_check_label_update(cred, so, label); 336 if (error) 337 return (error); 338 339 MAC_PERFORM(socket_label_update, cred, 340 (socket_t)so, so->so_label, label); 341 342#if CONFIG_MACF_NET 343 /* 344 * If the protocol has expressed interest in socket layer changes, 345 * such as if it needs to propagate changes to a cached pcb 346 * label from the socket, notify it of the label change while 347 * holding the socket lock. 348 * XXXMAC - are there cases when we should not do this? 349 */ 350 mac_inpcb_label_update(so); 351#endif 352 return (0); 353} 354 355int 356mac_setsockopt_label(kauth_cred_t cred, struct socket *so, struct mac *mac) 357{ 358 struct label *intlabel; 359 char *buffer; 360 int error; 361 size_t len; 362 363 error = mac_check_structmac_consistent(mac); 364 if (error) 365 return (error); 366 367 MALLOC(buffer, char *, mac->m_buflen, M_MACTEMP, M_WAITOK); 368 error = copyinstr(CAST_USER_ADDR_T(mac->m_string), buffer, 369 mac->m_buflen, &len); 370 if (error) { 371 FREE(buffer, M_MACTEMP); 372 return (error); 373 } 374 375 intlabel = mac_socket_label_alloc(MAC_WAITOK); 376 error = mac_socket_label_internalize(intlabel, buffer); 377 FREE(buffer, M_MACTEMP); 378 if (error) 379 goto out; 380 381 error = mac_socket_label_update(cred, so, intlabel); 382out: 383 mac_socket_label_free(intlabel); 384 return (error); 385} 386 387int 388mac_socket_label_get(__unused kauth_cred_t cred, struct socket *so, 389 struct mac *mac) 390{ 391 char *buffer, *elements; 392 struct label *intlabel; 393 int error; 394 size_t len; 395 396 error = mac_check_structmac_consistent(mac); 397 if (error) 398 return (error); 399 400 MALLOC(elements, char *, mac->m_buflen, M_MACTEMP, M_WAITOK); 401 error = copyinstr(CAST_USER_ADDR_T(mac->m_string), elements, 402 mac->m_buflen, &len); 403 if (error) { 404 FREE(elements, M_MACTEMP); 405 return (error); 406 } 407 408 MALLOC(buffer, char *, mac->m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); 409 intlabel = mac_socket_label_alloc(MAC_WAITOK); 410 mac_socket_label_copy(so->so_label, intlabel); 411 error = mac_socket_label_externalize(intlabel, elements, buffer, 412 mac->m_buflen); 413 mac_socket_label_free(intlabel); 414 if (error == 0) 415 error = copyout(buffer, CAST_USER_ADDR_T(mac->m_string), 416 strlen(buffer)+1); 417 418 FREE(buffer, M_MACTEMP); 419 FREE(elements, M_MACTEMP); 420 421 return (error); 422} 423 424int 425mac_socketpeer_label_get(__unused kauth_cred_t cred, struct socket *so, 426 struct mac *mac) 427{ 428 char *elements, *buffer; 429 struct label *intlabel; 430 int error; 431 size_t len; 432 433 error = mac_check_structmac_consistent(mac); 434 if (error) 435 return (error); 436 437 MALLOC(elements, char *, mac->m_buflen, M_MACTEMP, M_WAITOK); 438 error = copyinstr(CAST_USER_ADDR_T(mac->m_string), elements, 439 mac->m_buflen, &len); 440 if (error) { 441 FREE(elements, M_MACTEMP); 442 return (error); 443 } 444 445 MALLOC(buffer, char *, mac->m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); 446 intlabel = mac_socket_label_alloc(MAC_WAITOK); 447 mac_socket_label_copy(so->so_peerlabel, intlabel); 448 error = mac_socketpeer_label_externalize(intlabel, elements, buffer, 449 mac->m_buflen); 450 mac_socket_label_free(intlabel); 451 if (error == 0) 452 error = copyout(buffer, CAST_USER_ADDR_T(mac->m_string), 453 strlen(buffer)+1); 454 455 FREE(buffer, M_MACTEMP); 456 FREE(elements, M_MACTEMP); 457 458 return (error); 459} 460#endif /* MAC_SOCKET */ 461 462int 463mac_socket_check_accept(kauth_cred_t cred, struct socket *so) 464{ 465 int error; 466 467 if (!mac_socket_enforce) 468 return 0; 469 470 MAC_CHECK(socket_check_accept, cred, 471 (socket_t)so, so->so_label); 472 return (error); 473} 474 475#if CONFIG_MACF_SOCKET_SUBSET 476int 477mac_socket_check_accepted(kauth_cred_t cred, struct socket *so) 478{ 479 struct sockaddr *sockaddr; 480 int error; 481 482 if (!mac_socket_enforce) 483 return 0; 484 485 if (sock_getaddr((socket_t)so, &sockaddr, 1) != 0) { 486 error = ECONNABORTED; 487 } else { 488 MAC_CHECK(socket_check_accepted, cred, 489 (socket_t)so, so->so_label, sockaddr); 490 sock_freeaddr(sockaddr); 491 } 492 return (error); 493} 494#endif 495 496int 497mac_socket_check_bind(kauth_cred_t ucred, struct socket *so, 498 struct sockaddr *sockaddr) 499{ 500 int error; 501 502 if (!mac_socket_enforce) 503 return 0; 504 505 MAC_CHECK(socket_check_bind, ucred, 506 (socket_t)so, so->so_label, sockaddr); 507 return (error); 508} 509 510int 511mac_socket_check_connect(kauth_cred_t cred, struct socket *so, 512 struct sockaddr *sockaddr) 513{ 514 int error; 515 516 if (!mac_socket_enforce) 517 return 0; 518 519 MAC_CHECK(socket_check_connect, cred, 520 (socket_t)so, so->so_label, 521 sockaddr); 522 return (error); 523} 524 525int 526mac_socket_check_create(kauth_cred_t cred, int domain, int type, int protocol) 527{ 528 int error; 529 530 if (!mac_socket_enforce) 531 return 0; 532 533 MAC_CHECK(socket_check_create, cred, domain, type, protocol); 534 return (error); 535} 536 537#if CONFIG_MACF_SOCKET && CONFIG_MACF_NET 538int 539mac_socket_check_deliver(struct socket *so, struct mbuf *mbuf) 540{ 541 struct label *label; 542 int error; 543 544 if (!mac_socket_enforce) 545 return 0; 546 547 label = mac_mbuf_to_label(mbuf); 548 549 /* Policy must deal with NULL label (unlabeled mbufs) */ 550 MAC_CHECK(socket_check_deliver, 551 (socket_t)so, so->so_label, mbuf, label); 552 return (error); 553} 554#else 555int 556mac_socket_check_deliver(__unused struct socket *so, __unused struct mbuf *mbuf) 557{ 558 return (0); 559} 560#endif 561 562int 563mac_socket_check_listen(kauth_cred_t cred, struct socket *so) 564{ 565 int error; 566 567 if (!mac_socket_enforce) 568 return 0; 569 570 MAC_CHECK(socket_check_listen, cred, 571 (socket_t)so, so->so_label); 572 return (error); 573} 574 575int 576mac_socket_check_receive(kauth_cred_t cred, struct socket *so) 577{ 578 int error; 579 580 if (!mac_socket_enforce) 581 return 0; 582 583 MAC_CHECK(socket_check_receive, cred, 584 (socket_t)so, so->so_label); 585 return (error); 586} 587 588int 589mac_socket_check_received(kauth_cred_t cred, struct socket *so, struct sockaddr *saddr) 590{ 591 int error; 592 593 if (!mac_socket_enforce) 594 return 0; 595 596 MAC_CHECK(socket_check_received, cred, 597 so, so->so_label, saddr); 598 return (error); 599} 600 601int 602mac_socket_check_send(kauth_cred_t cred, struct socket *so, 603 struct sockaddr *sockaddr) 604{ 605 int error; 606 607 if (!mac_socket_enforce) 608 return 0; 609 610 MAC_CHECK(socket_check_send, cred, 611 (socket_t)so, so->so_label, sockaddr); 612 return (error); 613} 614 615int 616mac_socket_check_setsockopt(kauth_cred_t cred, struct socket *so, 617 struct sockopt *sopt) 618{ 619 int error; 620 621 if (!mac_socket_enforce) 622 return (0); 623 624 MAC_CHECK(socket_check_setsockopt, cred, 625 (socket_t)so, so->so_label, sopt); 626 return (error); 627} 628 629int mac_socket_check_getsockopt(kauth_cred_t cred, struct socket *so, 630 struct sockopt *sopt) 631{ 632 int error; 633 634 if (!mac_socket_enforce) 635 return (0); 636 637 MAC_CHECK(socket_check_getsockopt, cred, 638 (socket_t)so, so->so_label, sopt); 639 return (error); 640} 641