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 /* 76 * XXXRW: struct ifnet locking is incomplete in the network code, so we 77 * use our own global mutex for struct ifnet. Non-ideal, but should help 78 * in the SMP environment. 79 */ 80 static struct mtx mac_ifnet_mtx; 81 MTX_SYSINIT(mac_ifnet_mtx, &mac_ifnet_mtx, "mac_ifnet", MTX_DEF); 82 #define MAC_IFNET_LOCK(ifp) mtx_lock(&mac_ifnet_mtx) 83 #define MAC_IFNET_UNLOCK(ifp) mtx_unlock(&mac_ifnet_mtx) 84 85 struct label * 86 mac_mbuf_to_label(struct mbuf *mbuf) 87 { 88 struct m_tag *tag; 89 struct label *label; 90 91 if (mbuf == NULL) 92 return (NULL); 93 tag = m_tag_find(mbuf, PACKET_TAG_MACLABEL, NULL); 94 if (tag == NULL) 95 return (NULL); 96 label = (struct label *)(tag+1); 97 return (label); 98 } 99 100 static struct label * 101 mac_bpfdesc_label_alloc(void) 102 { 103 struct label *label; 104 105 label = mac_labelzone_alloc(M_WAITOK); 106 MAC_PERFORM(init_bpfdesc_label, label); 107 return (label); 108 } 109 110 void 111 mac_init_bpfdesc(struct bpf_d *bpf_d) 112 { 113 114 bpf_d->bd_label = mac_bpfdesc_label_alloc(); 115 } 116 117 static struct label * 118 mac_ifnet_label_alloc(void) 119 { 120 struct label *label; 121 122 label = mac_labelzone_alloc(M_WAITOK); 123 MAC_PERFORM(init_ifnet_label, label); 124 return (label); 125 } 126 127 void 128 mac_init_ifnet(struct ifnet *ifp) 129 { 130 131 ifp->if_label = mac_ifnet_label_alloc(); 132 } 133 134 int 135 mac_init_mbuf_tag(struct m_tag *tag, int flag) 136 { 137 struct label *label; 138 int error; 139 140 label = (struct label *) (tag + 1); 141 mac_init_label(label); 142 143 MAC_CHECK(init_mbuf_label, label, flag); 144 if (error) { 145 MAC_PERFORM(destroy_mbuf_label, label); 146 mac_destroy_label(label); 147 } 148 return (error); 149 } 150 151 int 152 mac_init_mbuf(struct mbuf *m, int flag) 153 { 154 struct m_tag *tag; 155 int error; 156 157 M_ASSERTPKTHDR(m); 158 159 #ifndef MAC_ALWAYS_LABEL_MBUF 160 /* 161 * If conditionally allocating mbuf labels, don't allocate unless 162 * they are required. 163 */ 164 if (!mac_labelmbufs) 165 return (0); 166 #endif 167 tag = m_tag_get(PACKET_TAG_MACLABEL, sizeof(struct label), 168 flag); 169 if (tag == NULL) 170 return (ENOMEM); 171 error = mac_init_mbuf_tag(tag, flag); 172 if (error) { 173 m_tag_free(tag); 174 return (error); 175 } 176 m_tag_prepend(m, tag); 177 return (0); 178 } 179 180 static void 181 mac_bpfdesc_label_free(struct label *label) 182 { 183 184 MAC_PERFORM(destroy_bpfdesc_label, label); 185 mac_labelzone_free(label); 186 } 187 188 void 189 mac_destroy_bpfdesc(struct bpf_d *bpf_d) 190 { 191 192 mac_bpfdesc_label_free(bpf_d->bd_label); 193 bpf_d->bd_label = NULL; 194 } 195 196 static void 197 mac_ifnet_label_free(struct label *label) 198 { 199 200 MAC_PERFORM(destroy_ifnet_label, label); 201 mac_labelzone_free(label); 202 } 203 204 void 205 mac_destroy_ifnet(struct ifnet *ifp) 206 { 207 208 mac_ifnet_label_free(ifp->if_label); 209 ifp->if_label = NULL; 210 } 211 212 void 213 mac_destroy_mbuf_tag(struct m_tag *tag) 214 { 215 struct label *label; 216 217 label = (struct label *)(tag+1); 218 219 MAC_PERFORM(destroy_mbuf_label, label); 220 mac_destroy_label(label); 221 } 222 223 void 224 mac_copy_mbuf_tag(struct m_tag *src, struct m_tag *dest) 225 { 226 struct label *src_label, *dest_label; 227 228 src_label = (struct label *)(src+1); 229 dest_label = (struct label *)(dest+1); 230 231 /* 232 * mac_init_mbuf_tag() is called on the target tag in 233 * m_tag_copy(), so we don't need to call it here. 234 */ 235 MAC_PERFORM(copy_mbuf_label, src_label, dest_label); 236 } 237 238 void 239 mac_copy_mbuf(struct mbuf *m_from, struct mbuf *m_to) 240 { 241 struct label *src_label, *dest_label; 242 243 src_label = mac_mbuf_to_label(m_from); 244 dest_label = mac_mbuf_to_label(m_to); 245 246 MAC_PERFORM(copy_mbuf_label, src_label, dest_label); 247 } 248 249 static void 250 mac_copy_ifnet_label(struct label *src, struct label *dest) 251 { 252 253 MAC_PERFORM(copy_ifnet_label, src, dest); 254 } 255 256 static int 257 mac_externalize_ifnet_label(struct label *label, char *elements, 258 char *outbuf, size_t outbuflen) 259 { 260 int error; 261 262 MAC_EXTERNALIZE(ifnet, label, elements, outbuf, outbuflen); 263 264 return (error); 265 } 266 267 static int 268 mac_internalize_ifnet_label(struct label *label, char *string) 269 { 270 int error; 271 272 MAC_INTERNALIZE(ifnet, label, string); 273 274 return (error); 275 } 276 277 void 278 mac_create_ifnet(struct ifnet *ifnet) 279 { 280 281 MAC_IFNET_LOCK(ifnet); 282 MAC_PERFORM(create_ifnet, ifnet, ifnet->if_label); 283 MAC_IFNET_UNLOCK(ifnet); 284 } 285 286 void 287 mac_create_bpfdesc(struct ucred *cred, struct bpf_d *bpf_d) 288 { 289 290 MAC_PERFORM(create_bpfdesc, cred, bpf_d, bpf_d->bd_label); 291 } 292 293 void 294 mac_create_mbuf_from_bpfdesc(struct bpf_d *bpf_d, struct mbuf *mbuf) 295 { 296 struct label *label; 297 298 BPFD_LOCK_ASSERT(bpf_d); 299 300 label = mac_mbuf_to_label(mbuf); 301 302 MAC_PERFORM(create_mbuf_from_bpfdesc, bpf_d, bpf_d->bd_label, mbuf, 303 label); 304 } 305 306 void 307 mac_create_mbuf_linklayer(struct ifnet *ifnet, struct mbuf *mbuf) 308 { 309 struct label *label; 310 311 label = mac_mbuf_to_label(mbuf); 312 313 MAC_IFNET_LOCK(ifnet); 314 MAC_PERFORM(create_mbuf_linklayer, ifnet, ifnet->if_label, mbuf, 315 label); 316 MAC_IFNET_UNLOCK(ifnet); 317 } 318 319 void 320 mac_create_mbuf_from_ifnet(struct ifnet *ifnet, struct mbuf *mbuf) 321 { 322 struct label *label; 323 324 label = mac_mbuf_to_label(mbuf); 325 326 MAC_IFNET_LOCK(ifnet); 327 MAC_PERFORM(create_mbuf_from_ifnet, ifnet, ifnet->if_label, mbuf, 328 label); 329 MAC_IFNET_UNLOCK(ifnet); 330 } 331 332 void 333 mac_create_mbuf_multicast_encap(struct mbuf *oldmbuf, struct ifnet *ifnet, 334 struct mbuf *newmbuf) 335 { 336 struct label *oldmbuflabel, *newmbuflabel; 337 338 oldmbuflabel = mac_mbuf_to_label(oldmbuf); 339 newmbuflabel = mac_mbuf_to_label(newmbuf); 340 341 MAC_IFNET_LOCK(ifnet); 342 MAC_PERFORM(create_mbuf_multicast_encap, oldmbuf, oldmbuflabel, 343 ifnet, ifnet->if_label, newmbuf, newmbuflabel); 344 MAC_IFNET_UNLOCK(ifnet); 345 } 346 347 void 348 mac_create_mbuf_netlayer(struct mbuf *oldmbuf, struct mbuf *newmbuf) 349 { 350 struct label *oldmbuflabel, *newmbuflabel; 351 352 oldmbuflabel = mac_mbuf_to_label(oldmbuf); 353 newmbuflabel = mac_mbuf_to_label(newmbuf); 354 355 MAC_PERFORM(create_mbuf_netlayer, oldmbuf, oldmbuflabel, newmbuf, 356 newmbuflabel); 357 } 358 359 int 360 mac_check_bpfdesc_receive(struct bpf_d *bpf_d, struct ifnet *ifnet) 361 { 362 int error; 363 364 BPFD_LOCK_ASSERT(bpf_d); 365 366 if (!mac_enforce_network) 367 return (0); 368 369 MAC_IFNET_LOCK(ifnet); 370 MAC_CHECK(check_bpfdesc_receive, bpf_d, bpf_d->bd_label, ifnet, 371 ifnet->if_label); 372 MAC_IFNET_UNLOCK(ifnet); 373 374 return (error); 375 } 376 377 int 378 mac_check_ifnet_transmit(struct ifnet *ifnet, struct mbuf *mbuf) 379 { 380 struct label *label; 381 int error; 382 383 M_ASSERTPKTHDR(mbuf); 384 385 if (!mac_enforce_network) 386 return (0); 387 388 label = mac_mbuf_to_label(mbuf); 389 390 MAC_IFNET_LOCK(ifnet); 391 MAC_CHECK(check_ifnet_transmit, ifnet, ifnet->if_label, mbuf, 392 label); 393 MAC_IFNET_UNLOCK(ifnet); 394 395 return (error); 396 } 397 398 int 399 mac_ioctl_ifnet_get(struct ucred *cred, struct ifreq *ifr, 400 struct ifnet *ifnet) 401 { 402 char *elements, *buffer; 403 struct label *intlabel; 404 struct mac mac; 405 int error; 406 407 error = copyin(ifr->ifr_ifru.ifru_data, &mac, sizeof(mac)); 408 if (error) 409 return (error); 410 411 error = mac_check_structmac_consistent(&mac); 412 if (error) 413 return (error); 414 415 elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 416 error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL); 417 if (error) { 418 free(elements, M_MACTEMP); 419 return (error); 420 } 421 422 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); 423 intlabel = mac_ifnet_label_alloc(); 424 MAC_IFNET_LOCK(ifnet); 425 mac_copy_ifnet_label(ifnet->if_label, intlabel); 426 MAC_IFNET_UNLOCK(ifnet); 427 error = mac_externalize_ifnet_label(ifnet->if_label, elements, 428 buffer, mac.m_buflen); 429 mac_ifnet_label_free(intlabel); 430 if (error == 0) 431 error = copyout(buffer, mac.m_string, strlen(buffer)+1); 432 433 free(buffer, M_MACTEMP); 434 free(elements, M_MACTEMP); 435 436 return (error); 437 } 438 439 int 440 mac_ioctl_ifnet_set(struct ucred *cred, struct ifreq *ifr, 441 struct ifnet *ifnet) 442 { 443 struct label *intlabel; 444 struct mac mac; 445 char *buffer; 446 int error; 447 448 error = copyin(ifr->ifr_ifru.ifru_data, &mac, sizeof(mac)); 449 if (error) 450 return (error); 451 452 error = mac_check_structmac_consistent(&mac); 453 if (error) 454 return (error); 455 456 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 457 error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL); 458 if (error) { 459 free(buffer, M_MACTEMP); 460 return (error); 461 } 462 463 intlabel = mac_ifnet_label_alloc(); 464 error = mac_internalize_ifnet_label(intlabel, buffer); 465 free(buffer, M_MACTEMP); 466 if (error) { 467 mac_ifnet_label_free(intlabel); 468 return (error); 469 } 470 471 /* 472 * XXX: Note that this is a redundant privilege check, since 473 * policies impose this check themselves if required by the 474 * policy. Eventually, this should go away. 475 */ 476 error = suser_cred(cred, 0); 477 if (error) { 478 mac_ifnet_label_free(intlabel); 479 return (error); 480 } 481 482 MAC_IFNET_LOCK(ifnet); 483 MAC_CHECK(check_ifnet_relabel, cred, ifnet, ifnet->if_label, 484 intlabel); 485 if (error) { 486 MAC_IFNET_UNLOCK(ifnet); 487 mac_ifnet_label_free(intlabel); 488 return (error); 489 } 490 491 MAC_PERFORM(relabel_ifnet, cred, ifnet, ifnet->if_label, intlabel); 492 MAC_IFNET_UNLOCK(ifnet); 493 494 mac_ifnet_label_free(intlabel); 495 return (0); 496 } 497