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