1/*- 2 * Copyright (c) 1999-2002, 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 McAfee 13 * Research, the Technology Research Division of Network Associates, Inc. 14 * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the 15 * 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/kernel.h> 52#include <sys/lock.h> 53#include <sys/malloc.h> 54#include <sys/mutex.h> 55#include <sys/mac.h> 56#include <sys/sbuf.h> 57#include <sys/sdt.h> 58#include <sys/systm.h> 59#include <sys/mount.h> 60#include <sys/file.h> 61#include <sys/namei.h> 62#include <sys/protosw.h> 63#include <sys/socket.h> 64#include <sys/socketvar.h> 65#include <sys/sysctl.h> 66 67#include <net/bpfdesc.h> 68#include <net/if.h> 69#include <net/if_var.h> 70 71#include <netinet/in.h> 72#include <netinet/in_pcb.h> 73#include <netinet/ip_var.h> 74 75#include <security/mac/mac_framework.h> 76#include <security/mac/mac_internal.h> 77#include <security/mac/mac_policy.h> 78 79/* 80 * Currently, sockets hold two labels: the label of the socket itself, and a 81 * peer label, which may be used by policies to hold a copy of the label of 82 * any remote endpoint. 83 * 84 * Possibly, this peer label should be maintained at the protocol layer 85 * (inpcb, unpcb, etc), as this would allow protocol-aware code to maintain 86 * the label consistently. For example, it might be copied live from a 87 * remote socket for UNIX domain sockets rather than keeping a local copy on 88 * this endpoint, but be cached and updated based on packets received for 89 * TCP/IP. 90 * 91 * Unlike with many other object types, the lock protecting MAC labels on 92 * sockets (the socket lock) is not frequently held at the points in code 93 * where socket-related checks are called. The MAC Framework acquires the 94 * lock over some entry points in order to enforce atomicity (such as label 95 * copies) but in other cases the policy modules will have to acquire the 96 * lock themselves if they use labels. This approach (a) avoids lock 97 * acquisitions when policies don't require labels and (b) solves a number of 98 * potential lock order issues when multiple sockets are used in the same 99 * entry point. 100 */ 101 102struct label * 103mac_socket_label_alloc(int flag) 104{ 105 struct label *label; 106 int error; 107 108 label = mac_labelzone_alloc(flag); 109 if (label == NULL) 110 return (NULL); 111 112 if (flag & M_WAITOK) 113 MAC_POLICY_CHECK(socket_init_label, label, flag); 114 else 115 MAC_POLICY_CHECK_NOSLEEP(socket_init_label, label, flag); 116 if (error) { 117 MAC_POLICY_PERFORM_NOSLEEP(socket_destroy_label, label); 118 mac_labelzone_free(label); 119 return (NULL); 120 } 121 return (label); 122} 123 124static struct label * 125mac_socketpeer_label_alloc(int flag) 126{ 127 struct label *label; 128 int error; 129 130 label = mac_labelzone_alloc(flag); 131 if (label == NULL) 132 return (NULL); 133 134 if (flag & M_WAITOK) 135 MAC_POLICY_CHECK(socketpeer_init_label, label, flag); 136 else 137 MAC_POLICY_CHECK_NOSLEEP(socketpeer_init_label, label, flag); 138 if (error) { 139 MAC_POLICY_PERFORM_NOSLEEP(socketpeer_destroy_label, label); 140 mac_labelzone_free(label); 141 return (NULL); 142 } 143 return (label); 144} 145 146int 147mac_socket_init(struct socket *so, int flag) 148{ 149 150 if (mac_labeled & MPC_OBJECT_SOCKET) { 151 so->so_label = mac_socket_label_alloc(flag); 152 if (so->so_label == NULL) 153 return (ENOMEM); 154 so->so_peerlabel = mac_socketpeer_label_alloc(flag); 155 if (so->so_peerlabel == NULL) { 156 mac_socket_label_free(so->so_label); 157 so->so_label = NULL; 158 return (ENOMEM); 159 } 160 } else { 161 so->so_label = NULL; 162 so->so_peerlabel = NULL; 163 } 164 return (0); 165} 166 167void 168mac_socket_label_free(struct label *label) 169{ 170 171 MAC_POLICY_PERFORM_NOSLEEP(socket_destroy_label, label); 172 mac_labelzone_free(label); 173} 174 175static void 176mac_socketpeer_label_free(struct label *label) 177{ 178 179 MAC_POLICY_PERFORM_NOSLEEP(socketpeer_destroy_label, label); 180 mac_labelzone_free(label); 181} 182 183void 184mac_socket_destroy(struct socket *so) 185{ 186 187 if (so->so_label != NULL) { 188 mac_socket_label_free(so->so_label); 189 so->so_label = NULL; 190 mac_socketpeer_label_free(so->so_peerlabel); 191 so->so_peerlabel = NULL; 192 } 193} 194 195void 196mac_socket_copy_label(struct label *src, struct label *dest) 197{ 198 199 MAC_POLICY_PERFORM_NOSLEEP(socket_copy_label, src, dest); 200} 201 202int 203mac_socket_externalize_label(struct label *label, char *elements, 204 char *outbuf, size_t outbuflen) 205{ 206 int error; 207 208 MAC_POLICY_EXTERNALIZE(socket, label, elements, outbuf, outbuflen); 209 210 return (error); 211} 212 213static int 214mac_socketpeer_externalize_label(struct label *label, char *elements, 215 char *outbuf, size_t outbuflen) 216{ 217 int error; 218 219 MAC_POLICY_EXTERNALIZE(socketpeer, label, elements, outbuf, 220 outbuflen); 221 222 return (error); 223} 224 225int 226mac_socket_internalize_label(struct label *label, char *string) 227{ 228 int error; 229 230 MAC_POLICY_INTERNALIZE(socket, label, string); 231 232 return (error); 233} 234 235void 236mac_socket_create(struct ucred *cred, struct socket *so) 237{ 238 239 MAC_POLICY_PERFORM_NOSLEEP(socket_create, cred, so, so->so_label); 240} 241 242void 243mac_socket_newconn(struct socket *oldso, struct socket *newso) 244{ 245 246 MAC_POLICY_PERFORM_NOSLEEP(socket_newconn, oldso, oldso->so_label, 247 newso, newso->so_label); 248} 249 250static void 251mac_socket_relabel(struct ucred *cred, struct socket *so, 252 struct label *newlabel) 253{ 254 255 SOCK_LOCK_ASSERT(so); 256 257 MAC_POLICY_PERFORM_NOSLEEP(socket_relabel, cred, so, so->so_label, 258 newlabel); 259} 260 261void 262mac_socketpeer_set_from_mbuf(struct mbuf *m, struct socket *so) 263{ 264 struct label *label; 265 266 if (mac_policy_count == 0) 267 return; 268 269 label = mac_mbuf_to_label(m); 270 271 MAC_POLICY_PERFORM_NOSLEEP(socketpeer_set_from_mbuf, m, label, so, 272 so->so_peerlabel); 273} 274 275void 276mac_socketpeer_set_from_socket(struct socket *oldso, struct socket *newso) 277{ 278 279 if (mac_policy_count == 0) 280 return; 281 282 MAC_POLICY_PERFORM_NOSLEEP(socketpeer_set_from_socket, oldso, 283 oldso->so_label, newso, newso->so_peerlabel); 284} 285 286void 287mac_socket_create_mbuf(struct socket *so, struct mbuf *m) 288{ 289 struct label *label; 290 291 if (mac_policy_count == 0) 292 return; 293 294 label = mac_mbuf_to_label(m); 295 296 MAC_POLICY_PERFORM_NOSLEEP(socket_create_mbuf, so, so->so_label, m, 297 label); 298} 299 300MAC_CHECK_PROBE_DEFINE2(socket_check_accept, "struct ucred *", 301 "struct socket *"); 302 303int 304mac_socket_check_accept(struct ucred *cred, struct socket *so) 305{ 306 int error; 307 308 MAC_POLICY_CHECK_NOSLEEP(socket_check_accept, cred, so, 309 so->so_label); 310 MAC_CHECK_PROBE2(socket_check_accept, error, cred, so); 311 312 return (error); 313} 314 315MAC_CHECK_PROBE_DEFINE3(socket_check_bind, "struct ucred *", 316 "struct socket *", "struct sockaddr *"); 317 318int 319mac_socket_check_bind(struct ucred *cred, struct socket *so, 320 struct sockaddr *sa) 321{ 322 int error; 323 324 MAC_POLICY_CHECK_NOSLEEP(socket_check_bind, cred, so, so->so_label, 325 sa); 326 MAC_CHECK_PROBE3(socket_check_bind, error, cred, so, sa); 327 328 return (error); 329} 330 331MAC_CHECK_PROBE_DEFINE3(socket_check_connect, "struct ucred *", 332 "struct socket *", "struct sockaddr *"); 333 334int 335mac_socket_check_connect(struct ucred *cred, struct socket *so, 336 struct sockaddr *sa) 337{ 338 int error; 339 340 MAC_POLICY_CHECK_NOSLEEP(socket_check_connect, cred, so, 341 so->so_label, sa); 342 MAC_CHECK_PROBE3(socket_check_connect, error, cred, so, sa); 343 344 return (error); 345} 346 347MAC_CHECK_PROBE_DEFINE4(socket_check_create, "struct ucred *", "int", "int", 348 "int"); 349 350int 351mac_socket_check_create(struct ucred *cred, int domain, int type, int proto) 352{ 353 int error; 354 355 MAC_POLICY_CHECK_NOSLEEP(socket_check_create, cred, domain, type, 356 proto); 357 MAC_CHECK_PROBE4(socket_check_create, error, cred, domain, type, 358 proto); 359 360 return (error); 361} 362 363MAC_CHECK_PROBE_DEFINE2(socket_check_deliver, "struct socket *", 364 "struct mbuf *"); 365 366int 367mac_socket_check_deliver(struct socket *so, struct mbuf *m) 368{ 369 struct label *label; 370 int error; 371 372 if (mac_policy_count == 0) 373 return (0); 374 375 label = mac_mbuf_to_label(m); 376 377 MAC_POLICY_CHECK_NOSLEEP(socket_check_deliver, so, so->so_label, m, 378 label); 379 MAC_CHECK_PROBE2(socket_check_deliver, error, so, m); 380 381 return (error); 382} 383 384MAC_CHECK_PROBE_DEFINE2(socket_check_listen, "struct ucred *", 385 "struct socket *"); 386 387int 388mac_socket_check_listen(struct ucred *cred, struct socket *so) 389{ 390 int error; 391 392 MAC_POLICY_CHECK_NOSLEEP(socket_check_listen, cred, so, 393 so->so_label); 394 MAC_CHECK_PROBE2(socket_check_listen, error, cred, so); 395 396 return (error); 397} 398 399MAC_CHECK_PROBE_DEFINE2(socket_check_poll, "struct ucred *", 400 "struct socket *"); 401 402int 403mac_socket_check_poll(struct ucred *cred, struct socket *so) 404{ 405 int error; 406 407 MAC_POLICY_CHECK_NOSLEEP(socket_check_poll, cred, so, so->so_label); 408 MAC_CHECK_PROBE2(socket_check_poll, error, cred, so); 409 410 return (error); 411} 412 413MAC_CHECK_PROBE_DEFINE2(socket_check_receive, "struct ucred *", 414 "struct socket *"); 415 416int 417mac_socket_check_receive(struct ucred *cred, struct socket *so) 418{ 419 int error; 420 421 MAC_POLICY_CHECK_NOSLEEP(socket_check_receive, cred, so, 422 so->so_label); 423 MAC_CHECK_PROBE2(socket_check_receive, error, cred, so); 424 425 return (error); 426} 427 428MAC_CHECK_PROBE_DEFINE3(socket_check_relabel, "struct ucred *", 429 "struct socket *", "struct label *"); 430 431static int 432mac_socket_check_relabel(struct ucred *cred, struct socket *so, 433 struct label *newlabel) 434{ 435 int error; 436 437 SOCK_LOCK_ASSERT(so); 438 439 MAC_POLICY_CHECK_NOSLEEP(socket_check_relabel, cred, so, 440 so->so_label, newlabel); 441 MAC_CHECK_PROBE3(socket_check_relabel, error, cred, so, newlabel); 442 443 return (error); 444} 445 446MAC_CHECK_PROBE_DEFINE2(socket_check_send, "struct ucred *", 447 "struct socket *"); 448 449int 450mac_socket_check_send(struct ucred *cred, struct socket *so) 451{ 452 int error; 453 454 MAC_POLICY_CHECK_NOSLEEP(socket_check_send, cred, so, so->so_label); 455 MAC_CHECK_PROBE2(socket_check_send, error, cred, so); 456 457 return (error); 458} 459 460MAC_CHECK_PROBE_DEFINE2(socket_check_stat, "struct ucred *", 461 "struct socket *"); 462 463int 464mac_socket_check_stat(struct ucred *cred, struct socket *so) 465{ 466 int error; 467 468 MAC_POLICY_CHECK_NOSLEEP(socket_check_stat, cred, so, so->so_label); 469 MAC_CHECK_PROBE2(socket_check_stat, error, cred, so); 470 471 return (error); 472} 473 474MAC_CHECK_PROBE_DEFINE2(socket_check_visible, "struct ucred *", 475 "struct socket *"); 476 477int 478mac_socket_check_visible(struct ucred *cred, struct socket *so) 479{ 480 int error; 481 482 MAC_POLICY_CHECK_NOSLEEP(socket_check_visible, cred, so, 483 so->so_label); 484 MAC_CHECK_PROBE2(socket_check_visible, error, cred, so); 485 486 return (error); 487} 488 489int 490mac_socket_label_set(struct ucred *cred, struct socket *so, 491 struct label *label) 492{ 493 int error; 494 495 /* 496 * We acquire the socket lock when we perform the test and set, but 497 * have to release it as the pcb code needs to acquire the pcb lock, 498 * which will precede the socket lock in the lock order. However, 499 * this is fine, as any race will simply result in the inpcb being 500 * refreshed twice, but still consistently, as the inpcb code will 501 * acquire the socket lock before refreshing, holding both locks. 502 */ 503 SOCK_LOCK(so); 504 error = mac_socket_check_relabel(cred, so, label); 505 if (error) { 506 SOCK_UNLOCK(so); 507 return (error); 508 } 509 510 mac_socket_relabel(cred, so, label); 511 SOCK_UNLOCK(so); 512 513 /* 514 * If the protocol has expressed interest in socket layer changes, 515 * such as if it needs to propagate changes to a cached pcb label 516 * from the socket, notify it of the label change while holding the 517 * socket lock. 518 */ 519 if (so->so_proto->pr_usrreqs->pru_sosetlabel != NULL) 520 (so->so_proto->pr_usrreqs->pru_sosetlabel)(so); 521 522 return (0); 523} 524 525int 526mac_setsockopt_label(struct ucred *cred, struct socket *so, struct mac *mac) 527{ 528 struct label *intlabel; 529 char *buffer; 530 int error; 531 532 if (!(mac_labeled & MPC_OBJECT_SOCKET)) 533 return (EINVAL); 534 535 error = mac_check_structmac_consistent(mac); 536 if (error) 537 return (error); 538 539 buffer = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK); 540 error = copyinstr(mac->m_string, buffer, mac->m_buflen, NULL); 541 if (error) { 542 free(buffer, M_MACTEMP); 543 return (error); 544 } 545 546 intlabel = mac_socket_label_alloc(M_WAITOK); 547 error = mac_socket_internalize_label(intlabel, buffer); 548 free(buffer, M_MACTEMP); 549 if (error) 550 goto out; 551 552 error = mac_socket_label_set(cred, so, intlabel); 553out: 554 mac_socket_label_free(intlabel); 555 return (error); 556} 557 558int 559mac_getsockopt_label(struct ucred *cred, struct socket *so, struct mac *mac) 560{ 561 char *buffer, *elements; 562 struct label *intlabel; 563 int error; 564 565 if (!(mac_labeled & MPC_OBJECT_SOCKET)) 566 return (EINVAL); 567 568 error = mac_check_structmac_consistent(mac); 569 if (error) 570 return (error); 571 572 elements = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK); 573 error = copyinstr(mac->m_string, elements, mac->m_buflen, NULL); 574 if (error) { 575 free(elements, M_MACTEMP); 576 return (error); 577 } 578 579 buffer = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); 580 intlabel = mac_socket_label_alloc(M_WAITOK); 581 SOCK_LOCK(so); 582 mac_socket_copy_label(so->so_label, intlabel); 583 SOCK_UNLOCK(so); 584 error = mac_socket_externalize_label(intlabel, elements, buffer, 585 mac->m_buflen); 586 mac_socket_label_free(intlabel); 587 if (error == 0) 588 error = copyout(buffer, mac->m_string, strlen(buffer)+1); 589 590 free(buffer, M_MACTEMP); 591 free(elements, M_MACTEMP); 592 593 return (error); 594} 595 596int 597mac_getsockopt_peerlabel(struct ucred *cred, struct socket *so, 598 struct mac *mac) 599{ 600 char *elements, *buffer; 601 struct label *intlabel; 602 int error; 603 604 if (!(mac_labeled & MPC_OBJECT_SOCKET)) 605 return (EINVAL); 606 607 error = mac_check_structmac_consistent(mac); 608 if (error) 609 return (error); 610 611 elements = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK); 612 error = copyinstr(mac->m_string, elements, mac->m_buflen, NULL); 613 if (error) { 614 free(elements, M_MACTEMP); 615 return (error); 616 } 617 618 buffer = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); 619 intlabel = mac_socket_label_alloc(M_WAITOK); 620 SOCK_LOCK(so); 621 mac_socket_copy_label(so->so_peerlabel, intlabel); 622 SOCK_UNLOCK(so); 623 error = mac_socketpeer_externalize_label(intlabel, elements, buffer, 624 mac->m_buflen); 625 mac_socket_label_free(intlabel); 626 if (error == 0) 627 error = copyout(buffer, mac->m_string, strlen(buffer)+1); 628 629 free(buffer, M_MACTEMP); 630 free(elements, M_MACTEMP); 631 632 return (error); 633} 634