1 /*- 2 * Copyright (c) 1999-2002 Robert N. M. Watson 3 * Copyright (c) 2001 Ilmar S. Habibulin 4 * Copyright (c) 2001-2004 Networks Associates Technology, Inc. 5 * All rights reserved. 6 * 7 * This software was developed by Robert Watson and Ilmar Habibulin for the 8 * TrustedBSD Project. 9 * 10 * This software was developed for the FreeBSD Project in part by Network 11 * Associates Laboratories, the Security Research Division of Network 12 * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), 13 * as part of the DARPA CHATS research program. 14 * 15 * Redistribution and use in source and binary forms, with or without 16 * modification, are permitted provided that the following conditions 17 * are met: 18 * 1. Redistributions of source code must retain the above copyright 19 * notice, this list of conditions and the following disclaimer. 20 * 2. Redistributions in binary form must reproduce the above copyright 21 * notice, this list of conditions and the following disclaimer in the 22 * documentation and/or other materials provided with the distribution. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 */ 36 37 #include <sys/cdefs.h> 38 __FBSDID("$FreeBSD$"); 39 40 #include "opt_mac.h" 41 42 #include <sys/param.h> 43 #include <sys/kernel.h> 44 #include <sys/lock.h> 45 #include <sys/malloc.h> 46 #include <sys/mutex.h> 47 #include <sys/mac.h> 48 #include <sys/sbuf.h> 49 #include <sys/systm.h> 50 #include <sys/mount.h> 51 #include <sys/file.h> 52 #include <sys/namei.h> 53 #include <sys/protosw.h> 54 #include <sys/socket.h> 55 #include <sys/socketvar.h> 56 #include <sys/sysctl.h> 57 58 #include <sys/mac_policy.h> 59 60 #include <net/bpfdesc.h> 61 #include <net/if.h> 62 #include <net/if_var.h> 63 64 #include <security/mac/mac_internal.h> 65 66 /* 67 * mac_enforce_network is used by IPv4 and IPv6 checks, and so must 68 * be non-static for now. 69 */ 70 int mac_enforce_network = 1; 71 SYSCTL_INT(_security_mac, OID_AUTO, enforce_network, CTLFLAG_RW, 72 &mac_enforce_network, 0, "Enforce MAC policy on network packets"); 73 TUNABLE_INT("security.mac.enforce_network", &mac_enforce_network); 74 75 #ifdef MAC_DEBUG 76 static unsigned int nmacbpfdescs, nmacifnets, nmacmbufs; 77 78 SYSCTL_UINT(_security_mac_debug_counters, OID_AUTO, bpfdescs, CTLFLAG_RD, 79 &nmacbpfdescs, 0, "number of bpfdescs in use"); 80 SYSCTL_UINT(_security_mac_debug_counters, OID_AUTO, ifnets, CTLFLAG_RD, 81 &nmacifnets, 0, "number of ifnets in use"); 82 SYSCTL_UINT(_security_mac_debug_counters, OID_AUTO, mbufs, CTLFLAG_RD, 83 &nmacmbufs, 0, "number of mbufs in use"); 84 #endif 85 86 /* 87 * XXXRW: struct ifnet locking is incomplete in the network code, so we 88 * use our own global mutex for struct ifnet. Non-ideal, but should help 89 * in the SMP environment. 90 */ 91 static struct mtx mac_ifnet_mtx; 92 MTX_SYSINIT(mac_ifnet_mtx, &mac_ifnet_mtx, "mac_ifnet", MTX_DEF); 93 #define MAC_IFNET_LOCK(ifp) mtx_lock(&mac_ifnet_mtx) 94 #define MAC_IFNET_UNLOCK(ifp) mtx_unlock(&mac_ifnet_mtx) 95 96 struct label * 97 mac_mbuf_to_label(struct mbuf *mbuf) 98 { 99 struct m_tag *tag; 100 struct label *label; 101 102 if (mbuf == NULL) 103 return (NULL); 104 tag = m_tag_find(mbuf, PACKET_TAG_MACLABEL, NULL); 105 if (tag == NULL) 106 return (NULL); 107 label = (struct label *)(tag+1); 108 return (label); 109 } 110 111 static struct label * 112 mac_bpfdesc_label_alloc(void) 113 { 114 struct label *label; 115 116 label = mac_labelzone_alloc(M_WAITOK); 117 MAC_PERFORM(init_bpfdesc_label, label); 118 MAC_DEBUG_COUNTER_INC(&nmacbpfdescs); 119 return (label); 120 } 121 122 void 123 mac_init_bpfdesc(struct bpf_d *bpf_d) 124 { 125 126 bpf_d->bd_label = mac_bpfdesc_label_alloc(); 127 } 128 129 static struct label * 130 mac_ifnet_label_alloc(void) 131 { 132 struct label *label; 133 134 label = mac_labelzone_alloc(M_WAITOK); 135 MAC_PERFORM(init_ifnet_label, label); 136 MAC_DEBUG_COUNTER_INC(&nmacifnets); 137 return (label); 138 } 139 140 void 141 mac_init_ifnet(struct ifnet *ifp) 142 { 143 144 ifp->if_label = mac_ifnet_label_alloc(); 145 } 146 147 int 148 mac_init_mbuf_tag(struct m_tag *tag, int flag) 149 { 150 struct label *label; 151 int error; 152 153 label = (struct label *) (tag + 1); 154 mac_init_label(label); 155 156 MAC_CHECK(init_mbuf_label, label, flag); 157 if (error) { 158 MAC_PERFORM(destroy_mbuf_label, label); 159 mac_destroy_label(label); 160 } else { 161 MAC_DEBUG_COUNTER_INC(&nmacmbufs); 162 } 163 return (error); 164 } 165 166 int 167 mac_init_mbuf(struct mbuf *m, int flag) 168 { 169 struct m_tag *tag; 170 int error; 171 172 M_ASSERTPKTHDR(m); 173 174 #ifndef MAC_ALWAYS_LABEL_MBUF 175 /* 176 * If conditionally allocating mbuf labels, don't allocate unless 177 * they are required. 178 */ 179 if (!mac_labelmbufs) 180 return (0); 181 #endif 182 tag = m_tag_get(PACKET_TAG_MACLABEL, sizeof(struct label), 183 flag); 184 if (tag == NULL) 185 return (ENOMEM); 186 error = mac_init_mbuf_tag(tag, flag); 187 if (error) { 188 m_tag_free(tag); 189 return (error); 190 } 191 m_tag_prepend(m, tag); 192 return (0); 193 } 194 195 static void 196 mac_bpfdesc_label_free(struct label *label) 197 { 198 199 MAC_PERFORM(destroy_bpfdesc_label, label); 200 mac_labelzone_free(label); 201 MAC_DEBUG_COUNTER_DEC(&nmacbpfdescs); 202 } 203 204 void 205 mac_destroy_bpfdesc(struct bpf_d *bpf_d) 206 { 207 208 mac_bpfdesc_label_free(bpf_d->bd_label); 209 bpf_d->bd_label = NULL; 210 } 211 212 static void 213 mac_ifnet_label_free(struct label *label) 214 { 215 216 MAC_PERFORM(destroy_ifnet_label, label); 217 mac_labelzone_free(label); 218 MAC_DEBUG_COUNTER_DEC(&nmacifnets); 219 } 220 221 void 222 mac_destroy_ifnet(struct ifnet *ifp) 223 { 224 225 mac_ifnet_label_free(ifp->if_label); 226 ifp->if_label = NULL; 227 } 228 229 void 230 mac_destroy_mbuf_tag(struct m_tag *tag) 231 { 232 struct label *label; 233 234 label = (struct label *)(tag+1); 235 236 MAC_PERFORM(destroy_mbuf_label, label); 237 mac_destroy_label(label); 238 MAC_DEBUG_COUNTER_DEC(&nmacmbufs); 239 } 240 241 void 242 mac_copy_mbuf_tag(struct m_tag *src, struct m_tag *dest) 243 { 244 struct label *src_label, *dest_label; 245 246 src_label = (struct label *)(src+1); 247 dest_label = (struct label *)(dest+1); 248 249 /* 250 * mac_init_mbuf_tag() is called on the target tag in 251 * m_tag_copy(), so we don't need to call it here. 252 */ 253 MAC_PERFORM(copy_mbuf_label, src_label, dest_label); 254 } 255 256 static void 257 mac_copy_ifnet_label(struct label *src, struct label *dest) 258 { 259 260 MAC_PERFORM(copy_ifnet_label, src, dest); 261 } 262 263 static int 264 mac_externalize_ifnet_label(struct label *label, char *elements, 265 char *outbuf, size_t outbuflen) 266 { 267 int error; 268 269 MAC_EXTERNALIZE(ifnet, label, elements, outbuf, outbuflen); 270 271 return (error); 272 } 273 274 static int 275 mac_internalize_ifnet_label(struct label *label, char *string) 276 { 277 int error; 278 279 MAC_INTERNALIZE(ifnet, label, string); 280 281 return (error); 282 } 283 284 void 285 mac_create_ifnet(struct ifnet *ifnet) 286 { 287 288 MAC_IFNET_LOCK(ifnet); 289 MAC_PERFORM(create_ifnet, ifnet, ifnet->if_label); 290 MAC_IFNET_UNLOCK(ifnet); 291 } 292 293 void 294 mac_create_bpfdesc(struct ucred *cred, struct bpf_d *bpf_d) 295 { 296 297 MAC_PERFORM(create_bpfdesc, cred, bpf_d, bpf_d->bd_label); 298 } 299 300 void 301 mac_create_mbuf_from_mbuf(struct mbuf *oldmbuf, struct mbuf *newmbuf) 302 { 303 struct label *oldmbuflabel, *newmbuflabel; 304 305 oldmbuflabel = mac_mbuf_to_label(oldmbuf); 306 newmbuflabel = mac_mbuf_to_label(newmbuf); 307 308 MAC_PERFORM(create_mbuf_from_mbuf, oldmbuf, oldmbuflabel, newmbuf, 309 newmbuflabel); 310 } 311 312 void 313 mac_create_mbuf_from_bpfdesc(struct bpf_d *bpf_d, struct mbuf *mbuf) 314 { 315 struct label *label; 316 317 BPFD_LOCK_ASSERT(bpf_d); 318 319 label = mac_mbuf_to_label(mbuf); 320 321 MAC_PERFORM(create_mbuf_from_bpfdesc, bpf_d, bpf_d->bd_label, mbuf, 322 label); 323 } 324 325 void 326 mac_create_mbuf_linklayer(struct ifnet *ifnet, struct mbuf *mbuf) 327 { 328 struct label *label; 329 330 label = mac_mbuf_to_label(mbuf); 331 332 MAC_IFNET_LOCK(ifnet); 333 MAC_PERFORM(create_mbuf_linklayer, ifnet, ifnet->if_label, mbuf, 334 label); 335 MAC_IFNET_UNLOCK(ifnet); 336 } 337 338 void 339 mac_create_mbuf_from_ifnet(struct ifnet *ifnet, struct mbuf *mbuf) 340 { 341 struct label *label; 342 343 label = mac_mbuf_to_label(mbuf); 344 345 MAC_IFNET_LOCK(ifnet); 346 MAC_PERFORM(create_mbuf_from_ifnet, ifnet, ifnet->if_label, mbuf, 347 label); 348 MAC_IFNET_UNLOCK(ifnet); 349 } 350 351 void 352 mac_create_mbuf_multicast_encap(struct mbuf *oldmbuf, struct ifnet *ifnet, 353 struct mbuf *newmbuf) 354 { 355 struct label *oldmbuflabel, *newmbuflabel; 356 357 oldmbuflabel = mac_mbuf_to_label(oldmbuf); 358 newmbuflabel = mac_mbuf_to_label(newmbuf); 359 360 MAC_IFNET_LOCK(ifnet); 361 MAC_PERFORM(create_mbuf_multicast_encap, oldmbuf, oldmbuflabel, 362 ifnet, ifnet->if_label, newmbuf, newmbuflabel); 363 MAC_IFNET_UNLOCK(ifnet); 364 } 365 366 void 367 mac_create_mbuf_netlayer(struct mbuf *oldmbuf, struct mbuf *newmbuf) 368 { 369 struct label *oldmbuflabel, *newmbuflabel; 370 371 oldmbuflabel = mac_mbuf_to_label(oldmbuf); 372 newmbuflabel = mac_mbuf_to_label(newmbuf); 373 374 MAC_PERFORM(create_mbuf_netlayer, oldmbuf, oldmbuflabel, newmbuf, 375 newmbuflabel); 376 } 377 378 int 379 mac_check_bpfdesc_receive(struct bpf_d *bpf_d, struct ifnet *ifnet) 380 { 381 int error; 382 383 BPFD_LOCK_ASSERT(bpf_d); 384 385 if (!mac_enforce_network) 386 return (0); 387 388 MAC_IFNET_LOCK(ifnet); 389 MAC_CHECK(check_bpfdesc_receive, bpf_d, bpf_d->bd_label, ifnet, 390 ifnet->if_label); 391 MAC_IFNET_UNLOCK(ifnet); 392 393 return (error); 394 } 395 396 int 397 mac_check_ifnet_transmit(struct ifnet *ifnet, struct mbuf *mbuf) 398 { 399 struct label *label; 400 int error; 401 402 M_ASSERTPKTHDR(mbuf); 403 404 if (!mac_enforce_network) 405 return (0); 406 407 label = mac_mbuf_to_label(mbuf); 408 409 MAC_IFNET_LOCK(ifnet); 410 MAC_CHECK(check_ifnet_transmit, ifnet, ifnet->if_label, mbuf, 411 label); 412 MAC_IFNET_UNLOCK(ifnet); 413 414 return (error); 415 } 416 417 int 418 mac_ioctl_ifnet_get(struct ucred *cred, struct ifreq *ifr, 419 struct ifnet *ifnet) 420 { 421 char *elements, *buffer; 422 struct label *intlabel; 423 struct mac mac; 424 int error; 425 426 error = copyin(ifr->ifr_ifru.ifru_data, &mac, sizeof(mac)); 427 if (error) 428 return (error); 429 430 error = mac_check_structmac_consistent(&mac); 431 if (error) 432 return (error); 433 434 elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 435 error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL); 436 if (error) { 437 free(elements, M_MACTEMP); 438 return (error); 439 } 440 441 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); 442 intlabel = mac_ifnet_label_alloc(); 443 MAC_IFNET_LOCK(ifnet); 444 mac_copy_ifnet_label(ifnet->if_label, intlabel); 445 MAC_IFNET_UNLOCK(ifnet); 446 error = mac_externalize_ifnet_label(ifnet->if_label, elements, 447 buffer, mac.m_buflen); 448 mac_ifnet_label_free(intlabel); 449 if (error == 0) 450 error = copyout(buffer, mac.m_string, strlen(buffer)+1); 451 452 free(buffer, M_MACTEMP); 453 free(elements, M_MACTEMP); 454 455 return (error); 456 } 457 458 int 459 mac_ioctl_ifnet_set(struct ucred *cred, struct ifreq *ifr, 460 struct ifnet *ifnet) 461 { 462 struct label *intlabel; 463 struct mac mac; 464 char *buffer; 465 int error; 466 467 error = copyin(ifr->ifr_ifru.ifru_data, &mac, sizeof(mac)); 468 if (error) 469 return (error); 470 471 error = mac_check_structmac_consistent(&mac); 472 if (error) 473 return (error); 474 475 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 476 error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL); 477 if (error) { 478 free(buffer, M_MACTEMP); 479 return (error); 480 } 481 482 intlabel = mac_ifnet_label_alloc(); 483 error = mac_internalize_ifnet_label(intlabel, buffer); 484 free(buffer, M_MACTEMP); 485 if (error) { 486 mac_ifnet_label_free(intlabel); 487 return (error); 488 } 489 490 /* 491 * XXX: Note that this is a redundant privilege check, since 492 * policies impose this check themselves if required by the 493 * policy. Eventually, this should go away. 494 */ 495 error = suser_cred(cred, 0); 496 if (error) { 497 mac_ifnet_label_free(intlabel); 498 return (error); 499 } 500 501 MAC_IFNET_LOCK(ifnet); 502 MAC_CHECK(check_ifnet_relabel, cred, ifnet, ifnet->if_label, 503 intlabel); 504 if (error) { 505 MAC_IFNET_UNLOCK(ifnet); 506 mac_ifnet_label_free(intlabel); 507 return (error); 508 } 509 510 MAC_PERFORM(relabel_ifnet, cred, ifnet, ifnet->if_label, intlabel); 511 MAC_IFNET_UNLOCK(ifnet); 512 513 mac_ifnet_label_free(intlabel); 514 return (0); 515 } 516