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