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