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