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