1 /*- 2 * Copyright (c) 1999-2002, 2009 Robert N. M. Watson 3 * Copyright (c) 2001 Ilmar S. Habibulin 4 * Copyright (c) 2001-2004 Networks Associates Technology, Inc. 5 * Copyright (c) 2006 SPARTA, Inc. 6 * Copyright (c) 2008 Apple Inc. 7 * All rights reserved. 8 * 9 * This software was developed by Robert Watson and Ilmar Habibulin for the 10 * TrustedBSD Project. 11 * 12 * This software was enhanced by SPARTA ISSO under SPAWAR contract 13 * N66001-04-C-6019 ("SEFOS"). 14 * 15 * This software was developed for the FreeBSD Project in part by Network 16 * Associates Laboratories, the Security Research Division of Network 17 * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), 18 * as part of the DARPA CHATS research program. 19 * 20 * This software was developed at the University of Cambridge Computer 21 * Laboratory with support from a grant from Google, Inc. 22 * 23 * Redistribution and use in source and binary forms, with or without 24 * modification, are permitted provided that the following conditions 25 * are met: 26 * 1. Redistributions of source code must retain the above copyright 27 * notice, this list of conditions and the following disclaimer. 28 * 2. Redistributions in binary form must reproduce the above copyright 29 * notice, this list of conditions and the following disclaimer in the 30 * documentation and/or other materials provided with the distribution. 31 * 32 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 33 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 34 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 35 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 36 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 37 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 38 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 39 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 40 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 41 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 42 * SUCH DAMAGE. 43 */ 44 45 #include <sys/cdefs.h> 46 __FBSDID("$FreeBSD$"); 47 48 #include "opt_mac.h" 49 50 #include <sys/param.h> 51 #include <sys/kernel.h> 52 #include <sys/lock.h> 53 #include <sys/malloc.h> 54 #include <sys/mutex.h> 55 #include <sys/mac.h> 56 #include <sys/priv.h> 57 #include <sys/sbuf.h> 58 #include <sys/sdt.h> 59 #include <sys/systm.h> 60 #include <sys/mount.h> 61 #include <sys/file.h> 62 #include <sys/namei.h> 63 #include <sys/protosw.h> 64 #include <sys/socket.h> 65 #include <sys/socketvar.h> 66 #include <sys/sysctl.h> 67 68 #include <net/bpfdesc.h> 69 #include <net/if.h> 70 #include <net/if_var.h> 71 72 #include <security/mac/mac_framework.h> 73 #include <security/mac/mac_internal.h> 74 #include <security/mac/mac_policy.h> 75 76 /* 77 * XXXRW: struct ifnet locking is incomplete in the network code, so we use 78 * our own global mutex for struct ifnet. Non-ideal, but should help in the 79 * SMP environment. 80 */ 81 struct mtx mac_ifnet_mtx; 82 MTX_SYSINIT(mac_ifnet_mtx, &mac_ifnet_mtx, "mac_ifnet", MTX_DEF); 83 84 /* 85 * Retrieve the label associated with an mbuf by searching for the tag. 86 * Depending on the value of mac_labelmbufs, it's possible that a label will 87 * not be present, in which case NULL is returned. Policies must handle the 88 * possibility of an mbuf not having label storage if they do not enforce 89 * early loading. 90 */ 91 struct label * 92 mac_mbuf_to_label(struct mbuf *m) 93 { 94 struct m_tag *tag; 95 struct label *label; 96 97 if (m == NULL) 98 return (NULL); 99 tag = m_tag_find(m, PACKET_TAG_MACLABEL, NULL); 100 if (tag == NULL) 101 return (NULL); 102 label = (struct label *)(tag+1); 103 return (label); 104 } 105 106 static struct label * 107 mac_bpfdesc_label_alloc(void) 108 { 109 struct label *label; 110 111 label = mac_labelzone_alloc(M_WAITOK); 112 MAC_POLICY_PERFORM(bpfdesc_init_label, label); 113 return (label); 114 } 115 116 void 117 mac_bpfdesc_init(struct bpf_d *d) 118 { 119 120 if (mac_labeled & MPC_OBJECT_BPFDESC) 121 d->bd_label = mac_bpfdesc_label_alloc(); 122 else 123 d->bd_label = NULL; 124 } 125 126 static struct label * 127 mac_ifnet_label_alloc(void) 128 { 129 struct label *label; 130 131 label = mac_labelzone_alloc(M_WAITOK); 132 MAC_POLICY_PERFORM(ifnet_init_label, label); 133 return (label); 134 } 135 136 void 137 mac_ifnet_init(struct ifnet *ifp) 138 { 139 140 if (mac_labeled & MPC_OBJECT_IFNET) 141 ifp->if_label = mac_ifnet_label_alloc(); 142 else 143 ifp->if_label = NULL; 144 } 145 146 int 147 mac_mbuf_tag_init(struct m_tag *tag, int flag) 148 { 149 struct label *label; 150 int error; 151 152 label = (struct label *) (tag + 1); 153 mac_init_label(label); 154 155 if (flag & M_WAITOK) 156 MAC_POLICY_CHECK(mbuf_init_label, label, flag); 157 else 158 MAC_POLICY_CHECK_NOSLEEP(mbuf_init_label, label, flag); 159 if (error) { 160 MAC_POLICY_PERFORM_NOSLEEP(mbuf_destroy_label, label); 161 mac_destroy_label(label); 162 } 163 return (error); 164 } 165 166 int 167 mac_mbuf_init(struct mbuf *m, int flag) 168 { 169 struct m_tag *tag; 170 int error; 171 172 M_ASSERTPKTHDR(m); 173 174 if (mac_labeled & MPC_OBJECT_MBUF) { 175 tag = m_tag_get(PACKET_TAG_MACLABEL, sizeof(struct label), 176 flag); 177 if (tag == NULL) 178 return (ENOMEM); 179 error = mac_mbuf_tag_init(tag, flag); 180 if (error) { 181 m_tag_free(tag); 182 return (error); 183 } 184 m_tag_prepend(m, tag); 185 } 186 return (0); 187 } 188 189 static void 190 mac_bpfdesc_label_free(struct label *label) 191 { 192 193 MAC_POLICY_PERFORM_NOSLEEP(bpfdesc_destroy_label, label); 194 mac_labelzone_free(label); 195 } 196 197 void 198 mac_bpfdesc_destroy(struct bpf_d *d) 199 { 200 201 if (d->bd_label != NULL) { 202 mac_bpfdesc_label_free(d->bd_label); 203 d->bd_label = NULL; 204 } 205 } 206 207 static void 208 mac_ifnet_label_free(struct label *label) 209 { 210 211 MAC_POLICY_PERFORM_NOSLEEP(ifnet_destroy_label, label); 212 mac_labelzone_free(label); 213 } 214 215 void 216 mac_ifnet_destroy(struct ifnet *ifp) 217 { 218 219 if (ifp->if_label != NULL) { 220 mac_ifnet_label_free(ifp->if_label); 221 ifp->if_label = NULL; 222 } 223 } 224 225 void 226 mac_mbuf_tag_destroy(struct m_tag *tag) 227 { 228 struct label *label; 229 230 label = (struct label *)(tag+1); 231 232 MAC_POLICY_PERFORM_NOSLEEP(mbuf_destroy_label, label); 233 mac_destroy_label(label); 234 } 235 236 /* 237 * mac_mbuf_tag_copy is called when an mbuf header is duplicated, in which 238 * case the labels must also be duplicated. 239 */ 240 void 241 mac_mbuf_tag_copy(struct m_tag *src, struct m_tag *dest) 242 { 243 struct label *src_label, *dest_label; 244 245 src_label = (struct label *)(src+1); 246 dest_label = (struct label *)(dest+1); 247 248 /* 249 * mac_mbuf_tag_init() is called on the target tag in m_tag_copy(), 250 * so we don't need to call it here. 251 */ 252 MAC_POLICY_PERFORM_NOSLEEP(mbuf_copy_label, src_label, dest_label); 253 } 254 255 void 256 mac_mbuf_copy(struct mbuf *m_from, struct mbuf *m_to) 257 { 258 struct label *src_label, *dest_label; 259 260 if (mac_policy_count == 0) 261 return; 262 263 src_label = mac_mbuf_to_label(m_from); 264 dest_label = mac_mbuf_to_label(m_to); 265 266 MAC_POLICY_PERFORM_NOSLEEP(mbuf_copy_label, src_label, dest_label); 267 } 268 269 static void 270 mac_ifnet_copy_label(struct label *src, struct label *dest) 271 { 272 273 MAC_POLICY_PERFORM_NOSLEEP(ifnet_copy_label, src, dest); 274 } 275 276 static int 277 mac_ifnet_externalize_label(struct label *label, char *elements, 278 char *outbuf, size_t outbuflen) 279 { 280 int error; 281 282 MAC_POLICY_EXTERNALIZE(ifnet, label, elements, outbuf, outbuflen); 283 284 return (error); 285 } 286 287 static int 288 mac_ifnet_internalize_label(struct label *label, char *string) 289 { 290 int error; 291 292 MAC_POLICY_INTERNALIZE(ifnet, label, string); 293 294 return (error); 295 } 296 297 void 298 mac_ifnet_create(struct ifnet *ifp) 299 { 300 301 if (mac_policy_count == 0) 302 return; 303 304 MAC_IFNET_LOCK(ifp); 305 MAC_POLICY_PERFORM_NOSLEEP(ifnet_create, ifp, ifp->if_label); 306 MAC_IFNET_UNLOCK(ifp); 307 } 308 309 void 310 mac_bpfdesc_create(struct ucred *cred, struct bpf_d *d) 311 { 312 313 MAC_POLICY_PERFORM_NOSLEEP(bpfdesc_create, cred, d, d->bd_label); 314 } 315 316 void 317 mac_bpfdesc_create_mbuf(struct bpf_d *d, struct mbuf *m) 318 { 319 struct label *label; 320 321 /* Assume reader lock is enough. */ 322 BPFD_LOCK_ASSERT(d); 323 324 if (mac_policy_count == 0) 325 return; 326 327 label = mac_mbuf_to_label(m); 328 329 MAC_POLICY_PERFORM_NOSLEEP(bpfdesc_create_mbuf, d, d->bd_label, m, 330 label); 331 } 332 333 void 334 mac_ifnet_create_mbuf(struct ifnet *ifp, struct mbuf *m) 335 { 336 struct label *label; 337 338 if (mac_policy_count == 0) 339 return; 340 341 label = mac_mbuf_to_label(m); 342 343 MAC_IFNET_LOCK(ifp); 344 MAC_POLICY_PERFORM_NOSLEEP(ifnet_create_mbuf, ifp, ifp->if_label, m, 345 label); 346 MAC_IFNET_UNLOCK(ifp); 347 } 348 349 MAC_CHECK_PROBE_DEFINE2(bpfdesc_check_receive, "struct bpf_d *", 350 "struct ifnet *"); 351 352 int 353 mac_bpfdesc_check_receive(struct bpf_d *d, struct ifnet *ifp) 354 { 355 int error; 356 357 /* Assume reader lock is enough. */ 358 BPFD_LOCK_ASSERT(d); 359 360 if (mac_policy_count == 0) 361 return (0); 362 363 MAC_IFNET_LOCK(ifp); 364 MAC_POLICY_CHECK_NOSLEEP(bpfdesc_check_receive, d, d->bd_label, ifp, 365 ifp->if_label); 366 MAC_CHECK_PROBE2(bpfdesc_check_receive, error, d, ifp); 367 MAC_IFNET_UNLOCK(ifp); 368 369 return (error); 370 } 371 372 MAC_CHECK_PROBE_DEFINE2(ifnet_check_transmit, "struct ifnet *", 373 "struct mbuf *"); 374 375 int 376 mac_ifnet_check_transmit(struct ifnet *ifp, struct mbuf *m) 377 { 378 struct label *label; 379 int error; 380 381 M_ASSERTPKTHDR(m); 382 383 if (mac_policy_count == 0) 384 return (0); 385 386 label = mac_mbuf_to_label(m); 387 388 MAC_IFNET_LOCK(ifp); 389 MAC_POLICY_CHECK_NOSLEEP(ifnet_check_transmit, ifp, ifp->if_label, m, 390 label); 391 MAC_CHECK_PROBE2(ifnet_check_transmit, error, ifp, m); 392 MAC_IFNET_UNLOCK(ifp); 393 394 return (error); 395 } 396 397 int 398 mac_ifnet_ioctl_get(struct ucred *cred, struct ifreq *ifr, 399 struct ifnet *ifp) 400 { 401 char *elements, *buffer; 402 struct label *intlabel; 403 struct mac mac; 404 int error; 405 406 if (!(mac_labeled & MPC_OBJECT_IFNET)) 407 return (EINVAL); 408 409 error = copyin(ifr_data_get_ptr(ifr), &mac, sizeof(mac)); 410 if (error) 411 return (error); 412 413 error = mac_check_structmac_consistent(&mac); 414 if (error) 415 return (error); 416 417 elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 418 error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL); 419 if (error) { 420 free(elements, M_MACTEMP); 421 return (error); 422 } 423 424 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); 425 intlabel = mac_ifnet_label_alloc(); 426 MAC_IFNET_LOCK(ifp); 427 mac_ifnet_copy_label(ifp->if_label, intlabel); 428 MAC_IFNET_UNLOCK(ifp); 429 error = mac_ifnet_externalize_label(intlabel, elements, buffer, 430 mac.m_buflen); 431 mac_ifnet_label_free(intlabel); 432 if (error == 0) 433 error = copyout(buffer, mac.m_string, strlen(buffer)+1); 434 435 free(buffer, M_MACTEMP); 436 free(elements, M_MACTEMP); 437 438 return (error); 439 } 440 441 int 442 mac_ifnet_ioctl_set(struct ucred *cred, struct ifreq *ifr, struct ifnet *ifp) 443 { 444 struct label *intlabel; 445 struct mac mac; 446 char *buffer; 447 int error; 448 449 if (!(mac_labeled & MPC_OBJECT_IFNET)) 450 return (EINVAL); 451 452 error = copyin(ifr_data_get_ptr(ifr), &mac, sizeof(mac)); 453 if (error) 454 return (error); 455 456 error = mac_check_structmac_consistent(&mac); 457 if (error) 458 return (error); 459 460 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 461 error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL); 462 if (error) { 463 free(buffer, M_MACTEMP); 464 return (error); 465 } 466 467 intlabel = mac_ifnet_label_alloc(); 468 error = mac_ifnet_internalize_label(intlabel, buffer); 469 free(buffer, M_MACTEMP); 470 if (error) { 471 mac_ifnet_label_free(intlabel); 472 return (error); 473 } 474 475 /* 476 * XXX: Note that this is a redundant privilege check, since policies 477 * impose this check themselves if required by the policy 478 * Eventually, this should go away. 479 */ 480 error = priv_check_cred(cred, PRIV_NET_SETIFMAC); 481 if (error) { 482 mac_ifnet_label_free(intlabel); 483 return (error); 484 } 485 486 MAC_IFNET_LOCK(ifp); 487 MAC_POLICY_CHECK_NOSLEEP(ifnet_check_relabel, cred, ifp, 488 ifp->if_label, intlabel); 489 if (error) { 490 MAC_IFNET_UNLOCK(ifp); 491 mac_ifnet_label_free(intlabel); 492 return (error); 493 } 494 495 MAC_POLICY_PERFORM_NOSLEEP(ifnet_relabel, cred, ifp, ifp->if_label, 496 intlabel); 497 MAC_IFNET_UNLOCK(ifp); 498 499 mac_ifnet_label_free(intlabel); 500 return (0); 501 } 502