1 /*- 2 * Copyright (c) 1999-2002, 2009, 2019 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 #include "opt_mac.h" 47 48 #include <sys/param.h> 49 #include <sys/kernel.h> 50 #include <sys/lock.h> 51 #include <sys/malloc.h> 52 #include <sys/mutex.h> 53 #include <sys/mac.h> 54 #include <sys/priv.h> 55 #include <sys/sbuf.h> 56 #include <sys/sdt.h> 57 #include <sys/systm.h> 58 #include <sys/mount.h> 59 #include <sys/file.h> 60 #include <sys/namei.h> 61 #include <sys/protosw.h> 62 #include <sys/socket.h> 63 #include <sys/socketvar.h> 64 #include <sys/sysctl.h> 65 66 #include <net/bpfdesc.h> 67 #include <net/if.h> 68 #include <net/if_var.h> 69 70 #include <security/mac/mac_framework.h> 71 #include <security/mac/mac_internal.h> 72 #include <security/mac/mac_policy.h> 73 74 /* 75 * XXXRW: struct ifnet locking is incomplete in the network code, so we use 76 * our own global mutex for struct ifnet. Non-ideal, but should help in the 77 * SMP environment. 78 * 79 * This lock is acquired only if a loaded policy is using ifnet labeling. 80 * This should not ever change during a MAC policy check, itself, but could 81 * change during setup/return from a check, so we have to condition unlock on 82 * previous lock. 83 */ 84 struct mtx mac_ifnet_mtx; 85 MTX_SYSINIT(mac_ifnet_mtx, &mac_ifnet_mtx, "mac_ifnet", MTX_DEF); 86 87 /* 88 * Retrieve the label associated with an mbuf by searching for the tag. 89 * Depending on the value of mac_labelmbufs, it's possible that a label will 90 * not be present, in which case NULL is returned. Policies must handle the 91 * possibility of an mbuf not having label storage if they do not enforce 92 * early loading. 93 */ 94 struct label * 95 mac_mbuf_to_label(struct mbuf *m) 96 { 97 struct m_tag *tag; 98 struct label *label; 99 100 if (m == NULL) 101 return (NULL); 102 tag = m_tag_find(m, PACKET_TAG_MACLABEL, NULL); 103 if (tag == NULL) 104 return (NULL); 105 label = (struct label *)(tag+1); 106 return (label); 107 } 108 109 static struct label * 110 mac_bpfdesc_label_alloc(void) 111 { 112 struct label *label; 113 114 label = mac_labelzone_alloc(M_WAITOK); 115 MAC_POLICY_PERFORM(bpfdesc_init_label, label); 116 return (label); 117 } 118 119 void 120 mac_bpfdesc_init(struct bpf_d *d) 121 { 122 123 if (mac_labeled & MPC_OBJECT_BPFDESC) 124 d->bd_label = mac_bpfdesc_label_alloc(); 125 else 126 d->bd_label = NULL; 127 } 128 129 static struct label * 130 mac_ifnet_label_alloc(void) 131 { 132 struct label *label; 133 134 label = mac_labelzone_alloc(M_WAITOK); 135 MAC_POLICY_PERFORM(ifnet_init_label, label); 136 return (label); 137 } 138 139 void 140 mac_ifnet_init(struct ifnet *ifp) 141 { 142 143 if (mac_labeled & MPC_OBJECT_IFNET) 144 if_setmaclabel(ifp, mac_ifnet_label_alloc()); 145 else 146 if_setmaclabel(ifp, NULL); 147 } 148 149 int 150 mac_mbuf_tag_init(struct m_tag *tag, int flag) 151 { 152 struct label *label; 153 int error; 154 155 label = (struct label *) (tag + 1); 156 mac_init_label(label); 157 158 if (flag & M_WAITOK) 159 MAC_POLICY_CHECK(mbuf_init_label, label, flag); 160 else 161 MAC_POLICY_CHECK_NOSLEEP(mbuf_init_label, label, flag); 162 if (error) { 163 MAC_POLICY_PERFORM_NOSLEEP(mbuf_destroy_label, label); 164 mac_destroy_label(label); 165 } 166 return (error); 167 } 168 169 int 170 mac_mbuf_init(struct mbuf *m, int flag) 171 { 172 struct m_tag *tag; 173 int error; 174 175 M_ASSERTPKTHDR(m); 176 177 if (mac_labeled & MPC_OBJECT_MBUF) { 178 tag = m_tag_get(PACKET_TAG_MACLABEL, sizeof(struct label), 179 flag); 180 if (tag == NULL) 181 return (ENOMEM); 182 error = mac_mbuf_tag_init(tag, flag); 183 if (error) { 184 m_tag_free(tag); 185 return (error); 186 } 187 m_tag_prepend(m, tag); 188 } 189 return (0); 190 } 191 192 static void 193 mac_bpfdesc_label_free(struct label *label) 194 { 195 196 MAC_POLICY_PERFORM_NOSLEEP(bpfdesc_destroy_label, label); 197 mac_labelzone_free(label); 198 } 199 200 void 201 mac_bpfdesc_destroy(struct bpf_d *d) 202 { 203 204 if (d->bd_label != NULL) { 205 mac_bpfdesc_label_free(d->bd_label); 206 d->bd_label = NULL; 207 } 208 } 209 210 static void 211 mac_ifnet_label_free(struct label *label) 212 { 213 214 MAC_POLICY_PERFORM_NOSLEEP(ifnet_destroy_label, label); 215 mac_labelzone_free(label); 216 } 217 218 void 219 mac_ifnet_destroy(struct ifnet *ifp) 220 { 221 struct label *label = if_getmaclabel(ifp); 222 if (label != NULL) { 223 mac_ifnet_label_free(label); 224 if_setmaclabel(ifp, NULL); 225 } 226 } 227 228 void 229 mac_mbuf_tag_destroy(struct m_tag *tag) 230 { 231 struct label *label; 232 233 label = (struct label *)(tag+1); 234 235 MAC_POLICY_PERFORM_NOSLEEP(mbuf_destroy_label, label); 236 mac_destroy_label(label); 237 } 238 239 /* 240 * mac_mbuf_tag_copy is called when an mbuf header is duplicated, in which 241 * case the labels must also be duplicated. 242 */ 243 void 244 mac_mbuf_tag_copy(struct m_tag *src, struct m_tag *dest) 245 { 246 struct label *src_label, *dest_label; 247 248 src_label = (struct label *)(src+1); 249 dest_label = (struct label *)(dest+1); 250 251 /* 252 * mac_mbuf_tag_init() is called on the target tag in m_tag_copy(), 253 * so we don't need to call it here. 254 */ 255 MAC_POLICY_PERFORM_NOSLEEP(mbuf_copy_label, src_label, dest_label); 256 } 257 258 void 259 mac_mbuf_copy(struct mbuf *m_from, struct mbuf *m_to) 260 { 261 struct label *src_label, *dest_label; 262 263 if (mac_policy_count == 0) 264 return; 265 266 src_label = mac_mbuf_to_label(m_from); 267 dest_label = mac_mbuf_to_label(m_to); 268 269 MAC_POLICY_PERFORM_NOSLEEP(mbuf_copy_label, src_label, dest_label); 270 } 271 272 static void 273 mac_ifnet_copy_label(struct label *src, struct label *dest) 274 { 275 276 MAC_POLICY_PERFORM_NOSLEEP(ifnet_copy_label, src, dest); 277 } 278 279 static int 280 mac_ifnet_externalize_label(struct label *label, char *elements, 281 char *outbuf, size_t outbuflen) 282 { 283 int error; 284 285 MAC_POLICY_EXTERNALIZE(ifnet, label, elements, outbuf, outbuflen); 286 287 return (error); 288 } 289 290 static int 291 mac_ifnet_internalize_label(struct label *label, char *string) 292 { 293 int error; 294 295 MAC_POLICY_INTERNALIZE(ifnet, label, string); 296 297 return (error); 298 } 299 300 void 301 mac_ifnet_create(struct ifnet *ifp) 302 { 303 int locked; 304 305 if (mac_policy_count == 0) 306 return; 307 308 MAC_IFNET_LOCK(ifp, locked); 309 MAC_POLICY_PERFORM_NOSLEEP(ifnet_create, ifp, if_getmaclabel(ifp)); 310 MAC_IFNET_UNLOCK(ifp, locked); 311 } 312 313 void 314 mac_bpfdesc_create(struct ucred *cred, struct bpf_d *d) 315 { 316 317 MAC_POLICY_PERFORM_NOSLEEP(bpfdesc_create, cred, d, d->bd_label); 318 } 319 320 void 321 mac_bpfdesc_create_mbuf(struct bpf_d *d, struct mbuf *m) 322 { 323 struct label *label; 324 325 /* Assume reader lock is enough. */ 326 BPFD_LOCK_ASSERT(d); 327 328 if (mac_policy_count == 0) 329 return; 330 331 label = mac_mbuf_to_label(m); 332 333 MAC_POLICY_PERFORM_NOSLEEP(bpfdesc_create_mbuf, d, d->bd_label, m, 334 label); 335 } 336 337 void 338 mac_ifnet_create_mbuf_impl(struct ifnet *ifp, struct mbuf *m) 339 { 340 struct label *label; 341 int locked; 342 343 label = mac_mbuf_to_label(m); 344 345 MAC_IFNET_LOCK(ifp, locked); 346 MAC_POLICY_PERFORM_NOSLEEP(ifnet_create_mbuf, ifp, if_getmaclabel(ifp), m, 347 label); 348 MAC_IFNET_UNLOCK(ifp, locked); 349 } 350 351 MAC_CHECK_PROBE_DEFINE2(bpfdesc_check_receive, "struct bpf_d *", 352 "struct ifnet *"); 353 354 int 355 mac_bpfdesc_check_receive(struct bpf_d *d, struct ifnet *ifp) 356 { 357 int error, locked; 358 359 /* Assume reader lock is enough. */ 360 BPFD_LOCK_ASSERT(d); 361 362 if (mac_policy_count == 0) 363 return (0); 364 365 MAC_IFNET_LOCK(ifp, locked); 366 MAC_POLICY_CHECK_NOSLEEP(bpfdesc_check_receive, d, d->bd_label, ifp, 367 if_getmaclabel(ifp)); 368 MAC_CHECK_PROBE2(bpfdesc_check_receive, error, d, ifp); 369 MAC_IFNET_UNLOCK(ifp, locked); 370 371 return (error); 372 } 373 374 MAC_CHECK_PROBE_DEFINE2(ifnet_check_transmit, "struct ifnet *", 375 "struct mbuf *"); 376 377 int 378 mac_ifnet_check_transmit_impl(struct ifnet *ifp, struct mbuf *m) 379 { 380 struct label *label; 381 int error, locked; 382 383 M_ASSERTPKTHDR(m); 384 385 label = mac_mbuf_to_label(m); 386 387 MAC_IFNET_LOCK(ifp, locked); 388 MAC_POLICY_CHECK_NOSLEEP(ifnet_check_transmit, ifp, if_getmaclabel(ifp), m, 389 label); 390 MAC_CHECK_PROBE2(ifnet_check_transmit, error, ifp, m); 391 MAC_IFNET_UNLOCK(ifp, locked); 392 393 return (error); 394 } 395 396 int 397 mac_ifnet_ioctl_get(struct ucred *cred, struct ifreq *ifr, 398 struct ifnet *ifp) 399 { 400 char *elements, *buffer; 401 struct label *intlabel; 402 struct mac mac; 403 int error, locked; 404 405 if (!(mac_labeled & MPC_OBJECT_IFNET)) 406 return (EINVAL); 407 408 error = copyin(ifr_data_get_ptr(ifr), &mac, sizeof(mac)); 409 if (error) 410 return (error); 411 412 error = mac_check_structmac_consistent(&mac); 413 if (error) 414 return (error); 415 416 elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 417 error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL); 418 if (error) { 419 free(elements, M_MACTEMP); 420 return (error); 421 } 422 423 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); 424 intlabel = mac_ifnet_label_alloc(); 425 MAC_IFNET_LOCK(ifp, locked); 426 mac_ifnet_copy_label(if_getmaclabel(ifp), intlabel); 427 MAC_IFNET_UNLOCK(ifp, locked); 428 error = mac_ifnet_externalize_label(intlabel, elements, buffer, 429 mac.m_buflen); 430 mac_ifnet_label_free(intlabel); 431 if (error == 0) 432 error = copyout(buffer, mac.m_string, strlen(buffer)+1); 433 434 free(buffer, M_MACTEMP); 435 free(elements, M_MACTEMP); 436 437 return (error); 438 } 439 440 int 441 mac_ifnet_ioctl_set(struct ucred *cred, struct ifreq *ifr, struct ifnet *ifp) 442 { 443 struct label *intlabel; 444 struct mac mac; 445 char *buffer; 446 int error, locked; 447 448 if (!(mac_labeled & MPC_OBJECT_IFNET)) 449 return (EINVAL); 450 451 error = copyin(ifr_data_get_ptr(ifr), &mac, sizeof(mac)); 452 if (error) 453 return (error); 454 455 error = mac_check_structmac_consistent(&mac); 456 if (error) 457 return (error); 458 459 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 460 error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL); 461 if (error) { 462 free(buffer, M_MACTEMP); 463 return (error); 464 } 465 466 intlabel = mac_ifnet_label_alloc(); 467 error = mac_ifnet_internalize_label(intlabel, buffer); 468 free(buffer, M_MACTEMP); 469 if (error) { 470 mac_ifnet_label_free(intlabel); 471 return (error); 472 } 473 474 /* 475 * XXX: Note that this is a redundant privilege check, since policies 476 * impose this check themselves if required by the policy 477 * Eventually, this should go away. 478 */ 479 error = priv_check_cred(cred, PRIV_NET_SETIFMAC); 480 if (error) { 481 mac_ifnet_label_free(intlabel); 482 return (error); 483 } 484 485 MAC_IFNET_LOCK(ifp, locked); 486 MAC_POLICY_CHECK_NOSLEEP(ifnet_check_relabel, cred, ifp, 487 if_getmaclabel(ifp), intlabel); 488 if (error) { 489 MAC_IFNET_UNLOCK(ifp, locked); 490 mac_ifnet_label_free(intlabel); 491 return (error); 492 } 493 494 MAC_POLICY_PERFORM_NOSLEEP(ifnet_relabel, cred, ifp, if_getmaclabel(ifp), 495 intlabel); 496 MAC_IFNET_UNLOCK(ifp, locked); 497 498 mac_ifnet_label_free(intlabel); 499 return (0); 500 } 501