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 *m) 86 { 87 struct m_tag *tag; 88 struct label *label; 89 90 if (m == NULL) 91 return (NULL); 92 tag = m_tag_find(m, 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 *d) 111 { 112 113 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 *d) 189 { 190 191 mac_bpfdesc_label_free(d->bd_label); 192 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 *ifp) 282 { 283 284 MAC_IFNET_LOCK(ifp); 285 MAC_PERFORM(create_ifnet, ifp, ifp->if_label); 286 MAC_IFNET_UNLOCK(ifp); 287 } 288 289 void 290 mac_create_bpfdesc(struct ucred *cred, struct bpf_d *d) 291 { 292 293 MAC_PERFORM(create_bpfdesc, cred, d, d->bd_label); 294 } 295 296 void 297 mac_create_mbuf_from_bpfdesc(struct bpf_d *d, struct mbuf *m) 298 { 299 struct label *label; 300 301 BPFD_LOCK_ASSERT(d); 302 303 label = mac_mbuf_to_label(m); 304 305 MAC_PERFORM(create_mbuf_from_bpfdesc, d, d->bd_label, m, label); 306 } 307 308 void 309 mac_create_mbuf_linklayer(struct ifnet *ifp, struct mbuf *m) 310 { 311 struct label *label; 312 313 label = mac_mbuf_to_label(m); 314 315 MAC_IFNET_LOCK(ifp); 316 MAC_PERFORM(create_mbuf_linklayer, ifp, ifp->if_label, m, label); 317 MAC_IFNET_UNLOCK(ifp); 318 } 319 320 void 321 mac_create_mbuf_from_ifnet(struct ifnet *ifp, struct mbuf *m) 322 { 323 struct label *label; 324 325 label = mac_mbuf_to_label(m); 326 327 MAC_IFNET_LOCK(ifp); 328 MAC_PERFORM(create_mbuf_from_ifnet, ifp, ifp->if_label, m, label); 329 MAC_IFNET_UNLOCK(ifp); 330 } 331 332 void 333 mac_create_mbuf_multicast_encap(struct mbuf *m, struct ifnet *ifp, 334 struct mbuf *mnew) 335 { 336 struct label *mlabel, *mnewlabel; 337 338 mlabel = mac_mbuf_to_label(m); 339 mnewlabel = mac_mbuf_to_label(mnew); 340 341 MAC_IFNET_LOCK(ifp); 342 MAC_PERFORM(create_mbuf_multicast_encap, m, mlabel, ifp, 343 ifp->if_label, mnew, mnewlabel); 344 MAC_IFNET_UNLOCK(ifp); 345 } 346 347 void 348 mac_create_mbuf_netlayer(struct mbuf *m, struct mbuf *mnew) 349 { 350 struct label *mlabel, *mnewlabel; 351 352 mlabel = mac_mbuf_to_label(m); 353 mnewlabel = mac_mbuf_to_label(mnew); 354 355 MAC_PERFORM(create_mbuf_netlayer, m, mlabel, mnew, mnewlabel); 356 } 357 358 int 359 mac_check_bpfdesc_receive(struct bpf_d *d, struct ifnet *ifp) 360 { 361 int error; 362 363 BPFD_LOCK_ASSERT(d); 364 365 MAC_IFNET_LOCK(ifp); 366 MAC_CHECK(check_bpfdesc_receive, d, d->bd_label, ifp, ifp->if_label); 367 MAC_IFNET_UNLOCK(ifp); 368 369 return (error); 370 } 371 372 int 373 mac_check_ifnet_transmit(struct ifnet *ifp, struct mbuf *m) 374 { 375 struct label *label; 376 int error; 377 378 M_ASSERTPKTHDR(m); 379 380 label = mac_mbuf_to_label(m); 381 382 MAC_IFNET_LOCK(ifp); 383 MAC_CHECK(check_ifnet_transmit, ifp, ifp->if_label, m, label); 384 MAC_IFNET_UNLOCK(ifp); 385 386 return (error); 387 } 388 389 int 390 mac_ioctl_ifnet_get(struct ucred *cred, struct ifreq *ifr, 391 struct ifnet *ifp) 392 { 393 char *elements, *buffer; 394 struct label *intlabel; 395 struct mac mac; 396 int error; 397 398 error = copyin(ifr->ifr_ifru.ifru_data, &mac, sizeof(mac)); 399 if (error) 400 return (error); 401 402 error = mac_check_structmac_consistent(&mac); 403 if (error) 404 return (error); 405 406 elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 407 error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL); 408 if (error) { 409 free(elements, M_MACTEMP); 410 return (error); 411 } 412 413 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); 414 intlabel = mac_ifnet_label_alloc(); 415 MAC_IFNET_LOCK(ifp); 416 mac_copy_ifnet_label(ifp->if_label, intlabel); 417 MAC_IFNET_UNLOCK(ifp); 418 error = mac_externalize_ifnet_label(intlabel, elements, buffer, 419 mac.m_buflen); 420 mac_ifnet_label_free(intlabel); 421 if (error == 0) 422 error = copyout(buffer, mac.m_string, strlen(buffer)+1); 423 424 free(buffer, M_MACTEMP); 425 free(elements, M_MACTEMP); 426 427 return (error); 428 } 429 430 int 431 mac_ioctl_ifnet_set(struct ucred *cred, struct ifreq *ifr, struct ifnet *ifp) 432 { 433 struct label *intlabel; 434 struct mac mac; 435 char *buffer; 436 int error; 437 438 error = copyin(ifr->ifr_ifru.ifru_data, &mac, sizeof(mac)); 439 if (error) 440 return (error); 441 442 error = mac_check_structmac_consistent(&mac); 443 if (error) 444 return (error); 445 446 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 447 error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL); 448 if (error) { 449 free(buffer, M_MACTEMP); 450 return (error); 451 } 452 453 intlabel = mac_ifnet_label_alloc(); 454 error = mac_internalize_ifnet_label(intlabel, buffer); 455 free(buffer, M_MACTEMP); 456 if (error) { 457 mac_ifnet_label_free(intlabel); 458 return (error); 459 } 460 461 /* 462 * XXX: Note that this is a redundant privilege check, since policies 463 * impose this check themselves if required by the policy 464 * Eventually, this should go away. 465 */ 466 error = priv_check_cred(cred, PRIV_NET_SETIFMAC, 0); 467 if (error) { 468 mac_ifnet_label_free(intlabel); 469 return (error); 470 } 471 472 MAC_IFNET_LOCK(ifp); 473 MAC_CHECK(check_ifnet_relabel, cred, ifp, ifp->if_label, intlabel); 474 if (error) { 475 MAC_IFNET_UNLOCK(ifp); 476 mac_ifnet_label_free(intlabel); 477 return (error); 478 } 479 480 MAC_PERFORM(relabel_ifnet, cred, ifp, ifp->if_label, intlabel); 481 MAC_IFNET_UNLOCK(ifp); 482 483 mac_ifnet_label_free(intlabel); 484 return (0); 485 } 486