1 /*- 2 * Copyright (c) 1999-2002 Robert N. M. Watson 3 * Copyright (c) 2001 Ilmar S. Habibulin 4 * Copyright (c) 2001-2005 Networks Associates Technology, Inc. 5 * Copyright (c) 2005 SPARTA, Inc. 6 * All rights reserved. 7 * 8 * This software was developed by Robert Watson and Ilmar Habibulin for the 9 * TrustedBSD Project. 10 * 11 * This software was developed for the FreeBSD Project in part by McAfee 12 * Research, the Technology Research Division of Network Associates, Inc. 13 * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the 14 * DARPA CHATS research program. 15 * 16 * This software was enhanced by SPARTA ISSO under SPAWAR contract 17 * N66001-04-C-6019 ("SEFOS"). 18 * 19 * Redistribution and use in source and binary forms, with or without 20 * modification, are permitted provided that the following conditions 21 * are met: 22 * 1. Redistributions of source code must retain the above copyright 23 * notice, this list of conditions and the following disclaimer. 24 * 2. Redistributions in binary form must reproduce the above copyright 25 * notice, this list of conditions and the following disclaimer in the 26 * documentation and/or other materials provided with the distribution. 27 * 28 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 31 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 38 * SUCH DAMAGE. 39 */ 40 41 #include <sys/cdefs.h> 42 __FBSDID("$FreeBSD$"); 43 44 #include "opt_mac.h" 45 46 #include <sys/param.h> 47 #include <sys/kernel.h> 48 #include <sys/lock.h> 49 #include <sys/malloc.h> 50 #include <sys/mutex.h> 51 #include <sys/mac.h> 52 #include <sys/sbuf.h> 53 #include <sys/systm.h> 54 #include <sys/mount.h> 55 #include <sys/file.h> 56 #include <sys/namei.h> 57 #include <sys/protosw.h> 58 #include <sys/socket.h> 59 #include <sys/socketvar.h> 60 #include <sys/sysctl.h> 61 62 #include <sys/mac_policy.h> 63 64 #include <net/bpfdesc.h> 65 #include <net/if.h> 66 #include <net/if_var.h> 67 68 #include <netinet/in.h> 69 #include <netinet/in_pcb.h> 70 #include <netinet/ip_var.h> 71 72 #include <security/mac/mac_internal.h> 73 74 /* 75 * mac_enforce_socket is used by the inet code when delivering to an inpcb 76 * without hitting the socket layer, and has to be non-static for now. 77 */ 78 int mac_enforce_socket = 1; 79 SYSCTL_INT(_security_mac, OID_AUTO, enforce_socket, CTLFLAG_RW, 80 &mac_enforce_socket, 0, "Enforce MAC policy on socket operations"); 81 TUNABLE_INT("security.mac.enforce_socket", &mac_enforce_socket); 82 83 #ifdef MAC_DEBUG 84 static unsigned int nmacsockets; 85 86 SYSCTL_UINT(_security_mac_debug_counters, OID_AUTO, sockets, CTLFLAG_RD, 87 &nmacsockets, 0, "number of sockets in use"); 88 #endif 89 90 struct label * 91 mac_socket_label_alloc(int flag) 92 { 93 struct label *label; 94 int error; 95 96 label = mac_labelzone_alloc(flag); 97 if (label == NULL) 98 return (NULL); 99 100 MAC_CHECK(init_socket_label, label, flag); 101 if (error) { 102 MAC_PERFORM(destroy_socket_label, label); 103 mac_labelzone_free(label); 104 return (NULL); 105 } 106 MAC_DEBUG_COUNTER_INC(&nmacsockets); 107 return (label); 108 } 109 110 static struct label * 111 mac_socket_peer_label_alloc(int flag) 112 { 113 struct label *label; 114 int error; 115 116 label = mac_labelzone_alloc(flag); 117 if (label == NULL) 118 return (NULL); 119 120 MAC_CHECK(init_socket_peer_label, label, flag); 121 if (error) { 122 MAC_PERFORM(destroy_socket_peer_label, label); 123 mac_labelzone_free(label); 124 return (NULL); 125 } 126 MAC_DEBUG_COUNTER_INC(&nmacsockets); 127 return (label); 128 } 129 130 int 131 mac_init_socket(struct socket *so, int flag) 132 { 133 134 so->so_label = mac_socket_label_alloc(flag); 135 if (so->so_label == NULL) 136 return (ENOMEM); 137 so->so_peerlabel = mac_socket_peer_label_alloc(flag); 138 if (so->so_peerlabel == NULL) { 139 mac_socket_label_free(so->so_label); 140 so->so_label = NULL; 141 return (ENOMEM); 142 } 143 return (0); 144 } 145 146 void 147 mac_socket_label_free(struct label *label) 148 { 149 150 MAC_PERFORM(destroy_socket_label, label); 151 mac_labelzone_free(label); 152 MAC_DEBUG_COUNTER_DEC(&nmacsockets); 153 } 154 155 static void 156 mac_socket_peer_label_free(struct label *label) 157 { 158 159 MAC_PERFORM(destroy_socket_peer_label, label); 160 mac_labelzone_free(label); 161 MAC_DEBUG_COUNTER_DEC(&nmacsockets); 162 } 163 164 void 165 mac_destroy_socket(struct socket *socket) 166 { 167 168 mac_socket_label_free(socket->so_label); 169 socket->so_label = NULL; 170 mac_socket_peer_label_free(socket->so_peerlabel); 171 socket->so_peerlabel = NULL; 172 } 173 174 void 175 mac_copy_socket_label(struct label *src, struct label *dest) 176 { 177 178 MAC_PERFORM(copy_socket_label, src, dest); 179 } 180 181 int 182 mac_externalize_socket_label(struct label *label, char *elements, 183 char *outbuf, size_t outbuflen) 184 { 185 int error; 186 187 MAC_EXTERNALIZE(socket, label, elements, outbuf, outbuflen); 188 189 return (error); 190 } 191 192 static int 193 mac_externalize_socket_peer_label(struct label *label, char *elements, 194 char *outbuf, size_t outbuflen) 195 { 196 int error; 197 198 MAC_EXTERNALIZE(socket_peer, label, elements, outbuf, outbuflen); 199 200 return (error); 201 } 202 203 int 204 mac_internalize_socket_label(struct label *label, char *string) 205 { 206 int error; 207 208 MAC_INTERNALIZE(socket, label, string); 209 210 return (error); 211 } 212 213 void 214 mac_create_socket(struct ucred *cred, struct socket *socket) 215 { 216 217 MAC_PERFORM(create_socket, cred, socket, socket->so_label); 218 } 219 220 void 221 mac_create_socket_from_socket(struct socket *oldsocket, 222 struct socket *newsocket) 223 { 224 225 SOCK_LOCK_ASSERT(oldsocket); 226 MAC_PERFORM(create_socket_from_socket, oldsocket, oldsocket->so_label, 227 newsocket, newsocket->so_label); 228 } 229 230 static void 231 mac_relabel_socket(struct ucred *cred, struct socket *socket, 232 struct label *newlabel) 233 { 234 235 SOCK_LOCK_ASSERT(socket); 236 MAC_PERFORM(relabel_socket, cred, socket, socket->so_label, newlabel); 237 } 238 239 void 240 mac_set_socket_peer_from_mbuf(struct mbuf *mbuf, struct socket *socket) 241 { 242 struct label *label; 243 244 SOCK_LOCK_ASSERT(socket); 245 246 label = mac_mbuf_to_label(mbuf); 247 248 MAC_PERFORM(set_socket_peer_from_mbuf, mbuf, label, socket, 249 socket->so_peerlabel); 250 } 251 252 void 253 mac_set_socket_peer_from_socket(struct socket *oldsocket, 254 struct socket *newsocket) 255 { 256 257 /* 258 * XXXRW: only hold the socket lock on one at a time, as one 259 * socket is the original, and one is the new. However, it's 260 * called in both directions, so we can't assert the lock 261 * here currently. 262 */ 263 MAC_PERFORM(set_socket_peer_from_socket, oldsocket, 264 oldsocket->so_label, newsocket, newsocket->so_peerlabel); 265 } 266 267 void 268 mac_create_mbuf_from_socket(struct socket *socket, struct mbuf *mbuf) 269 { 270 struct label *label; 271 272 label = mac_mbuf_to_label(mbuf); 273 274 SOCK_LOCK_ASSERT(socket); 275 MAC_PERFORM(create_mbuf_from_socket, socket, socket->so_label, mbuf, 276 label); 277 } 278 279 int 280 mac_check_socket_accept(struct ucred *cred, struct socket *socket) 281 { 282 int error; 283 284 SOCK_LOCK_ASSERT(socket); 285 286 if (!mac_enforce_socket) 287 return (0); 288 289 MAC_CHECK(check_socket_accept, cred, socket, socket->so_label); 290 291 return (error); 292 } 293 294 int 295 mac_check_socket_bind(struct ucred *ucred, struct socket *socket, 296 struct sockaddr *sockaddr) 297 { 298 int error; 299 300 SOCK_LOCK_ASSERT(socket); 301 302 if (!mac_enforce_socket) 303 return (0); 304 305 MAC_CHECK(check_socket_bind, ucred, socket, socket->so_label, 306 sockaddr); 307 308 return (error); 309 } 310 311 int 312 mac_check_socket_connect(struct ucred *cred, struct socket *socket, 313 struct sockaddr *sockaddr) 314 { 315 int error; 316 317 SOCK_LOCK_ASSERT(socket); 318 319 if (!mac_enforce_socket) 320 return (0); 321 322 MAC_CHECK(check_socket_connect, cred, socket, socket->so_label, 323 sockaddr); 324 325 return (error); 326 } 327 328 int 329 mac_check_socket_create(struct ucred *cred, int domain, int type, 330 int protocol) 331 { 332 int error; 333 334 if (!mac_enforce_socket) 335 return (0); 336 337 MAC_CHECK(check_socket_create, cred, domain, type, protocol); 338 339 return (error); 340 } 341 342 int 343 mac_check_socket_deliver(struct socket *socket, struct mbuf *mbuf) 344 { 345 struct label *label; 346 int error; 347 348 SOCK_LOCK_ASSERT(socket); 349 350 if (!mac_enforce_socket) 351 return (0); 352 353 label = mac_mbuf_to_label(mbuf); 354 355 MAC_CHECK(check_socket_deliver, socket, socket->so_label, mbuf, 356 label); 357 358 return (error); 359 } 360 361 int 362 mac_check_socket_listen(struct ucred *cred, struct socket *socket) 363 { 364 int error; 365 366 SOCK_LOCK_ASSERT(socket); 367 368 if (!mac_enforce_socket) 369 return (0); 370 371 MAC_CHECK(check_socket_listen, cred, socket, socket->so_label); 372 return (error); 373 } 374 375 int 376 mac_check_socket_poll(struct ucred *cred, struct socket *so) 377 { 378 int error; 379 380 SOCK_LOCK_ASSERT(so); 381 382 if (!mac_enforce_socket) 383 return (0); 384 385 MAC_CHECK(check_socket_poll, cred, so, so->so_label); 386 return (error); 387 } 388 389 int 390 mac_check_socket_receive(struct ucred *cred, struct socket *so) 391 { 392 int error; 393 394 SOCK_LOCK_ASSERT(so); 395 396 if (!mac_enforce_socket) 397 return (0); 398 399 MAC_CHECK(check_socket_receive, cred, so, so->so_label); 400 401 return (error); 402 } 403 404 static int 405 mac_check_socket_relabel(struct ucred *cred, struct socket *socket, 406 struct label *newlabel) 407 { 408 int error; 409 410 SOCK_LOCK_ASSERT(socket); 411 412 MAC_CHECK(check_socket_relabel, cred, socket, socket->so_label, 413 newlabel); 414 415 return (error); 416 } 417 418 int 419 mac_check_socket_send(struct ucred *cred, struct socket *so) 420 { 421 int error; 422 423 SOCK_LOCK_ASSERT(so); 424 425 if (!mac_enforce_socket) 426 return (0); 427 428 MAC_CHECK(check_socket_send, cred, so, so->so_label); 429 430 return (error); 431 } 432 433 int 434 mac_check_socket_stat(struct ucred *cred, struct socket *so) 435 { 436 int error; 437 438 SOCK_LOCK_ASSERT(so); 439 440 if (!mac_enforce_socket) 441 return (0); 442 443 MAC_CHECK(check_socket_stat, cred, so, so->so_label); 444 445 return (error); 446 } 447 448 int 449 mac_check_socket_visible(struct ucred *cred, struct socket *socket) 450 { 451 int error; 452 453 SOCK_LOCK_ASSERT(socket); 454 455 if (!mac_enforce_socket) 456 return (0); 457 458 MAC_CHECK(check_socket_visible, cred, socket, socket->so_label); 459 460 return (error); 461 } 462 463 int 464 mac_socket_label_set(struct ucred *cred, struct socket *so, 465 struct label *label) 466 { 467 int error; 468 469 /* 470 * We acquire the socket lock when we perform the test and set, 471 * but have to release it as the pcb code needs to acquire the 472 * pcb lock, which will precede the socket lock in the lock 473 * order. However, this is fine, as any race will simply 474 * result in the inpcb being refreshed twice, but still 475 * consistently, as the inpcb code will acquire the socket lock 476 * before refreshing, holding both locks. 477 */ 478 SOCK_LOCK(so); 479 error = mac_check_socket_relabel(cred, so, label); 480 if (error) { 481 SOCK_UNLOCK(so); 482 return (error); 483 } 484 485 mac_relabel_socket(cred, so, label); 486 SOCK_UNLOCK(so); 487 /* 488 * If the protocol has expressed interest in socket layer changes, 489 * such as if it needs to propagate changes to a cached pcb 490 * label from the socket, notify it of the label change while 491 * holding the socket lock. 492 */ 493 if (so->so_proto->pr_usrreqs->pru_sosetlabel != NULL) 494 (so->so_proto->pr_usrreqs->pru_sosetlabel)(so); 495 496 return (0); 497 } 498 499 int 500 mac_setsockopt_label(struct ucred *cred, struct socket *so, struct mac *mac) 501 { 502 struct label *intlabel; 503 char *buffer; 504 int error; 505 506 error = mac_check_structmac_consistent(mac); 507 if (error) 508 return (error); 509 510 buffer = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK); 511 error = copyinstr(mac->m_string, buffer, mac->m_buflen, NULL); 512 if (error) { 513 free(buffer, M_MACTEMP); 514 return (error); 515 } 516 517 intlabel = mac_socket_label_alloc(M_WAITOK); 518 error = mac_internalize_socket_label(intlabel, buffer); 519 free(buffer, M_MACTEMP); 520 if (error) 521 goto out; 522 523 error = mac_socket_label_set(cred, so, intlabel); 524 out: 525 mac_socket_label_free(intlabel); 526 return (error); 527 } 528 529 int 530 mac_getsockopt_label(struct ucred *cred, struct socket *so, struct mac *mac) 531 { 532 char *buffer, *elements; 533 struct label *intlabel; 534 int error; 535 536 error = mac_check_structmac_consistent(mac); 537 if (error) 538 return (error); 539 540 elements = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK); 541 error = copyinstr(mac->m_string, elements, mac->m_buflen, NULL); 542 if (error) { 543 free(elements, M_MACTEMP); 544 return (error); 545 } 546 547 buffer = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); 548 intlabel = mac_socket_label_alloc(M_WAITOK); 549 SOCK_LOCK(so); 550 mac_copy_socket_label(so->so_label, intlabel); 551 SOCK_UNLOCK(so); 552 error = mac_externalize_socket_label(intlabel, elements, buffer, 553 mac->m_buflen); 554 mac_socket_label_free(intlabel); 555 if (error == 0) 556 error = copyout(buffer, mac->m_string, strlen(buffer)+1); 557 558 free(buffer, M_MACTEMP); 559 free(elements, M_MACTEMP); 560 561 return (error); 562 } 563 564 int 565 mac_getsockopt_peerlabel(struct ucred *cred, struct socket *so, 566 struct mac *mac) 567 { 568 char *elements, *buffer; 569 struct label *intlabel; 570 int error; 571 572 error = mac_check_structmac_consistent(mac); 573 if (error) 574 return (error); 575 576 elements = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK); 577 error = copyinstr(mac->m_string, elements, mac->m_buflen, NULL); 578 if (error) { 579 free(elements, M_MACTEMP); 580 return (error); 581 } 582 583 buffer = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); 584 intlabel = mac_socket_label_alloc(M_WAITOK); 585 SOCK_LOCK(so); 586 mac_copy_socket_label(so->so_peerlabel, intlabel); 587 SOCK_UNLOCK(so); 588 error = mac_externalize_socket_peer_label(intlabel, elements, buffer, 589 mac->m_buflen); 590 mac_socket_label_free(intlabel); 591 if (error == 0) 592 error = copyout(buffer, mac->m_string, strlen(buffer)+1); 593 594 free(buffer, M_MACTEMP); 595 free(elements, M_MACTEMP); 596 597 return (error); 598 } 599