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 102 struct label * 103 mac_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 124 static struct label * 125 mac_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 146 int 147 mac_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 167 void 168 mac_socket_label_free(struct label *label) 169 { 170 171 MAC_POLICY_PERFORM_NOSLEEP(socket_destroy_label, label); 172 mac_labelzone_free(label); 173 } 174 175 static void 176 mac_socketpeer_label_free(struct label *label) 177 { 178 179 MAC_POLICY_PERFORM_NOSLEEP(socketpeer_destroy_label, label); 180 mac_labelzone_free(label); 181 } 182 183 void 184 mac_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 195 void 196 mac_socket_copy_label(struct label *src, struct label *dest) 197 { 198 199 MAC_POLICY_PERFORM_NOSLEEP(socket_copy_label, src, dest); 200 } 201 202 int 203 mac_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 213 static int 214 mac_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 225 int 226 mac_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 235 void 236 mac_socket_create(struct ucred *cred, struct socket *so) 237 { 238 239 MAC_POLICY_PERFORM_NOSLEEP(socket_create, cred, so, so->so_label); 240 } 241 242 void 243 mac_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 250 static void 251 mac_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 261 void 262 mac_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 275 void 276 mac_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 286 void 287 mac_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 300 MAC_CHECK_PROBE_DEFINE2(socket_check_accept, "struct ucred *", 301 "struct socket *"); 302 303 int 304 mac_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 315 MAC_CHECK_PROBE_DEFINE3(socket_check_bind, "struct ucred *", 316 "struct socket *", "struct sockaddr *"); 317 318 int 319 mac_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 331 MAC_CHECK_PROBE_DEFINE3(socket_check_connect, "struct ucred *", 332 "struct socket *", "struct sockaddr *"); 333 334 int 335 mac_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 347 MAC_CHECK_PROBE_DEFINE4(socket_check_create, "struct ucred *", "int", "int", 348 "int"); 349 350 int 351 mac_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 363 MAC_CHECK_PROBE_DEFINE2(socket_check_deliver, "struct socket *", 364 "struct mbuf *"); 365 366 int 367 mac_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 384 MAC_CHECK_PROBE_DEFINE2(socket_check_listen, "struct ucred *", 385 "struct socket *"); 386 387 int 388 mac_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 399 MAC_CHECK_PROBE_DEFINE2(socket_check_poll, "struct ucred *", 400 "struct socket *"); 401 402 int 403 mac_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 413 MAC_CHECK_PROBE_DEFINE2(socket_check_receive, "struct ucred *", 414 "struct socket *"); 415 416 int 417 mac_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 428 MAC_CHECK_PROBE_DEFINE3(socket_check_relabel, "struct ucred *", 429 "struct socket *", "struct label *"); 430 431 static int 432 mac_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 446 MAC_CHECK_PROBE_DEFINE2(socket_check_send, "struct ucred *", 447 "struct socket *"); 448 449 int 450 mac_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 460 MAC_CHECK_PROBE_DEFINE2(socket_check_stat, "struct ucred *", 461 "struct socket *"); 462 463 int 464 mac_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 474 MAC_CHECK_PROBE_DEFINE2(socket_check_visible, "struct ucred *", 475 "struct socket *"); 476 477 int 478 mac_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 489 int 490 mac_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_sosetlabel != NULL) 520 so->so_proto->pr_sosetlabel(so); 521 522 return (0); 523 } 524 525 int 526 mac_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); 553 out: 554 mac_socket_label_free(intlabel); 555 return (error); 556 } 557 558 int 559 mac_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 596 int 597 mac_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