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