1 /*- 2 * Copyright (c) 1999, 2000, 2001, 2002 Robert N. M. Watson 3 * Copyright (c) 2001 Ilmar S. Habibulin 4 * Copyright (c) 2001, 2002 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 * $FreeBSD$ 37 */ 38 /* 39 * Developed by the TrustedBSD Project. 40 * 41 * Framework for extensible kernel access control. Kernel and userland 42 * interface to the framework, policy registration and composition. 43 */ 44 45 #include "opt_mac.h" 46 #include "opt_devfs.h" 47 48 #include <sys/param.h> 49 #include <sys/condvar.h> 50 #include <sys/extattr.h> 51 #include <sys/imgact.h> 52 #include <sys/kernel.h> 53 #include <sys/lock.h> 54 #include <sys/malloc.h> 55 #include <sys/mutex.h> 56 #include <sys/mac.h> 57 #include <sys/module.h> 58 #include <sys/proc.h> 59 #include <sys/systm.h> 60 #include <sys/sysproto.h> 61 #include <sys/sysent.h> 62 #include <sys/vnode.h> 63 #include <sys/mount.h> 64 #include <sys/file.h> 65 #include <sys/namei.h> 66 #include <sys/socket.h> 67 #include <sys/pipe.h> 68 #include <sys/socketvar.h> 69 #include <sys/sysctl.h> 70 71 #include <vm/vm.h> 72 #include <vm/pmap.h> 73 #include <vm/vm_map.h> 74 #include <vm/vm_object.h> 75 76 #include <sys/mac_policy.h> 77 78 #include <fs/devfs/devfs.h> 79 80 #include <net/bpfdesc.h> 81 #include <net/if.h> 82 #include <net/if_var.h> 83 84 #include <netinet/in.h> 85 #include <netinet/ip_var.h> 86 87 #ifdef MAC 88 89 /* 90 * Declare that the kernel provides MAC support, version 1. This permits 91 * modules to refuse to be loaded if the necessary support isn't present, 92 * even if it's pre-boot. 93 */ 94 MODULE_VERSION(kernel_mac_support, 1); 95 96 SYSCTL_DECL(_security); 97 98 SYSCTL_NODE(_security, OID_AUTO, mac, CTLFLAG_RW, 0, 99 "TrustedBSD MAC policy controls"); 100 101 #if MAC_MAX_POLICIES > 32 102 #error "MAC_MAX_POLICIES too large" 103 #endif 104 105 static unsigned int mac_max_policies = MAC_MAX_POLICIES; 106 static unsigned int mac_policy_offsets_free = (1 << MAC_MAX_POLICIES) - 1; 107 SYSCTL_UINT(_security_mac, OID_AUTO, max_policies, CTLFLAG_RD, 108 &mac_max_policies, 0, ""); 109 110 /* 111 * Has the kernel started generating labeled objects yet? All read/write 112 * access to this variable is serialized during the boot process. Following 113 * the end of serialization, we don't update this flag; no locking. 114 */ 115 static int mac_late = 0; 116 117 /* 118 * Warn about EA transactions only the first time they happen. 119 * Weak coherency, no locking. 120 */ 121 static int ea_warn_once = 0; 122 123 static int mac_enforce_fs = 1; 124 SYSCTL_INT(_security_mac, OID_AUTO, enforce_fs, CTLFLAG_RW, 125 &mac_enforce_fs, 0, "Enforce MAC policy on file system objects"); 126 TUNABLE_INT("security.mac.enforce_fs", &mac_enforce_fs); 127 128 static int mac_enforce_kld = 1; 129 SYSCTL_INT(_security_mac, OID_AUTO, enforce_kld, CTLFLAG_RW, 130 &mac_enforce_kld, 0, "Enforce MAC policy on kld operations"); 131 TUNABLE_INT("security.mac.enforce_kld", &mac_enforce_kld); 132 133 static int mac_enforce_network = 1; 134 SYSCTL_INT(_security_mac, OID_AUTO, enforce_network, CTLFLAG_RW, 135 &mac_enforce_network, 0, "Enforce MAC policy on network packets"); 136 TUNABLE_INT("security.mac.enforce_network", &mac_enforce_network); 137 138 static int mac_enforce_pipe = 1; 139 SYSCTL_INT(_security_mac, OID_AUTO, enforce_pipe, CTLFLAG_RW, 140 &mac_enforce_pipe, 0, "Enforce MAC policy on pipe operations"); 141 TUNABLE_INT("security.mac.enforce_pipe", &mac_enforce_pipe); 142 143 static int mac_enforce_process = 1; 144 SYSCTL_INT(_security_mac, OID_AUTO, enforce_process, CTLFLAG_RW, 145 &mac_enforce_process, 0, "Enforce MAC policy on inter-process operations"); 146 TUNABLE_INT("security.mac.enforce_process", &mac_enforce_process); 147 148 static int mac_enforce_socket = 1; 149 SYSCTL_INT(_security_mac, OID_AUTO, enforce_socket, CTLFLAG_RW, 150 &mac_enforce_socket, 0, "Enforce MAC policy on socket operations"); 151 TUNABLE_INT("security.mac.enforce_socket", &mac_enforce_socket); 152 153 static int mac_enforce_system = 1; 154 SYSCTL_INT(_security_mac, OID_AUTO, enforce_system, CTLFLAG_RW, 155 &mac_enforce_system, 0, "Enforce MAC policy on system operations"); 156 TUNABLE_INT("security.mac.enforce_system", &mac_enforce_system); 157 158 static int mac_enforce_vm = 1; 159 SYSCTL_INT(_security_mac, OID_AUTO, enforce_vm, CTLFLAG_RW, 160 &mac_enforce_vm, 0, "Enforce MAC policy on vm operations"); 161 TUNABLE_INT("security.mac.enforce_vm", &mac_enforce_vm); 162 163 static int mac_mmap_revocation = 1; 164 SYSCTL_INT(_security_mac, OID_AUTO, mmap_revocation, CTLFLAG_RW, 165 &mac_mmap_revocation, 0, "Revoke mmap access to files on subject " 166 "relabel"); 167 static int mac_mmap_revocation_via_cow = 0; 168 SYSCTL_INT(_security_mac, OID_AUTO, mmap_revocation_via_cow, CTLFLAG_RW, 169 &mac_mmap_revocation_via_cow, 0, "Revoke mmap access to files via " 170 "copy-on-write semantics, or by removing all write access"); 171 172 #ifdef MAC_DEBUG 173 SYSCTL_NODE(_security_mac, OID_AUTO, debug, CTLFLAG_RW, 0, 174 "TrustedBSD MAC debug info"); 175 176 static int mac_debug_label_fallback = 0; 177 SYSCTL_INT(_security_mac_debug, OID_AUTO, label_fallback, CTLFLAG_RW, 178 &mac_debug_label_fallback, 0, "Filesystems should fall back to fs label" 179 "when label is corrupted."); 180 TUNABLE_INT("security.mac.debug_label_fallback", 181 &mac_debug_label_fallback); 182 183 SYSCTL_NODE(_security_mac_debug, OID_AUTO, counters, CTLFLAG_RW, 0, 184 "TrustedBSD MAC object counters"); 185 186 static unsigned int nmacmbufs, nmaccreds, nmacifnets, nmacbpfdescs, 187 nmacsockets, nmacmounts, nmactemp, nmacvnodes, nmacdevfsdirents, 188 nmacipqs, nmacpipes, nmacprocs; 189 190 SYSCTL_UINT(_security_mac_debug_counters, OID_AUTO, mbufs, CTLFLAG_RD, 191 &nmacmbufs, 0, "number of mbufs in use"); 192 SYSCTL_UINT(_security_mac_debug_counters, OID_AUTO, creds, CTLFLAG_RD, 193 &nmaccreds, 0, "number of ucreds in use"); 194 SYSCTL_UINT(_security_mac_debug_counters, OID_AUTO, ifnets, CTLFLAG_RD, 195 &nmacifnets, 0, "number of ifnets in use"); 196 SYSCTL_UINT(_security_mac_debug_counters, OID_AUTO, ipqs, CTLFLAG_RD, 197 &nmacipqs, 0, "number of ipqs in use"); 198 SYSCTL_UINT(_security_mac_debug_counters, OID_AUTO, bpfdescs, CTLFLAG_RD, 199 &nmacbpfdescs, 0, "number of bpfdescs in use"); 200 SYSCTL_UINT(_security_mac_debug_counters, OID_AUTO, sockets, CTLFLAG_RD, 201 &nmacsockets, 0, "number of sockets in use"); 202 SYSCTL_UINT(_security_mac_debug_counters, OID_AUTO, pipes, CTLFLAG_RD, 203 &nmacpipes, 0, "number of pipes in use"); 204 SYSCTL_UINT(_security_mac_debug_counters, OID_AUTO, procs, CTLFLAG_RD, 205 &nmacprocs, 0, "number of procs in use"); 206 SYSCTL_UINT(_security_mac_debug_counters, OID_AUTO, mounts, CTLFLAG_RD, 207 &nmacmounts, 0, "number of mounts in use"); 208 SYSCTL_UINT(_security_mac_debug_counters, OID_AUTO, temp, CTLFLAG_RD, 209 &nmactemp, 0, "number of temporary labels in use"); 210 SYSCTL_UINT(_security_mac_debug_counters, OID_AUTO, vnodes, CTLFLAG_RD, 211 &nmacvnodes, 0, "number of vnodes in use"); 212 SYSCTL_UINT(_security_mac_debug_counters, OID_AUTO, devfsdirents, CTLFLAG_RD, 213 &nmacdevfsdirents, 0, "number of devfs dirents inuse"); 214 #endif 215 216 static int error_select(int error1, int error2); 217 static int mac_policy_register(struct mac_policy_conf *mpc); 218 static int mac_policy_unregister(struct mac_policy_conf *mpc); 219 220 static void mac_check_vnode_mmap_downgrade(struct ucred *cred, 221 struct vnode *vp, int *prot); 222 static void mac_cred_mmapped_drop_perms_recurse(struct thread *td, 223 struct ucred *cred, struct vm_map *map); 224 225 static void mac_destroy_socket_label(struct label *label); 226 227 static int mac_setlabel_vnode_extattr(struct ucred *cred, 228 struct vnode *vp, struct label *intlabel); 229 230 MALLOC_DEFINE(M_MACPIPELABEL, "macpipelabel", "MAC labels for pipes"); 231 MALLOC_DEFINE(M_MACTEMP, "mactemp", "MAC temporary label storage"); 232 233 /* 234 * mac_policy_list stores the list of active policies. A busy count is 235 * maintained for the list, stored in mac_policy_busy. The busy count 236 * is protected by mac_policy_list_lock; the list may be modified only 237 * while the busy count is 0, requiring that the lock be held to 238 * prevent new references to the list from being acquired. For almost 239 * all operations, incrementing the busy count is sufficient to 240 * guarantee consistency, as the list cannot be modified while the 241 * busy count is elevated. For a few special operations involving a 242 * change to the list of active policies, the lock itself must be held. 243 * A condition variable, mac_policy_list_not_busy, is used to signal 244 * potential exclusive consumers that they should try to acquire the 245 * lock if a first attempt at exclusive access fails. 246 */ 247 static struct mtx mac_policy_list_lock; 248 static struct cv mac_policy_list_not_busy; 249 static LIST_HEAD(, mac_policy_conf) mac_policy_list; 250 static int mac_policy_list_busy; 251 252 #define MAC_POLICY_LIST_LOCKINIT() do { \ 253 mtx_init(&mac_policy_list_lock, "mac_policy_list_lock", NULL, \ 254 MTX_DEF); \ 255 cv_init(&mac_policy_list_not_busy, "mac_policy_list_not_busy"); \ 256 } while (0) 257 258 #define MAC_POLICY_LIST_LOCK() do { \ 259 mtx_lock(&mac_policy_list_lock); \ 260 } while (0) 261 262 #define MAC_POLICY_LIST_UNLOCK() do { \ 263 mtx_unlock(&mac_policy_list_lock); \ 264 } while (0) 265 266 /* 267 * We manually invoke WITNESS_WARN() to allow Witness to generate 268 * warnings even if we don't end up ever triggering the wait at 269 * run-time. The consumer of the exclusive interface must not hold 270 * any locks (other than potentially Giant) since we may sleep for 271 * long (potentially indefinite) periods of time waiting for the 272 * framework to become quiescent so that a policy list change may 273 * be made. 274 */ 275 #define MAC_POLICY_LIST_EXCLUSIVE() do { \ 276 WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, \ 277 "mac_policy_list_exclusive() at %s:%d", __FILE__, __LINE__);\ 278 mtx_lock(&mac_policy_list_lock); \ 279 while (mac_policy_list_busy != 0) \ 280 cv_wait(&mac_policy_list_not_busy, \ 281 &mac_policy_list_lock); \ 282 } while (0) 283 284 #define MAC_POLICY_LIST_BUSY() do { \ 285 MAC_POLICY_LIST_LOCK(); \ 286 mac_policy_list_busy++; \ 287 MAC_POLICY_LIST_UNLOCK(); \ 288 } while (0) 289 290 #define MAC_POLICY_LIST_UNBUSY() do { \ 291 MAC_POLICY_LIST_LOCK(); \ 292 mac_policy_list_busy--; \ 293 KASSERT(mac_policy_list_busy >= 0, ("MAC_POLICY_LIST_LOCK")); \ 294 if (mac_policy_list_busy == 0) \ 295 cv_signal(&mac_policy_list_not_busy); \ 296 MAC_POLICY_LIST_UNLOCK(); \ 297 } while (0) 298 299 /* 300 * MAC_CHECK performs the designated check by walking the policy 301 * module list and checking with each as to how it feels about the 302 * request. Note that it returns its value via 'error' in the scope 303 * of the caller. 304 */ 305 #define MAC_CHECK(check, args...) do { \ 306 struct mac_policy_conf *mpc; \ 307 \ 308 error = 0; \ 309 MAC_POLICY_LIST_BUSY(); \ 310 LIST_FOREACH(mpc, &mac_policy_list, mpc_list) { \ 311 if (mpc->mpc_ops->mpo_ ## check != NULL) \ 312 error = error_select( \ 313 mpc->mpc_ops->mpo_ ## check (args), \ 314 error); \ 315 } \ 316 MAC_POLICY_LIST_UNBUSY(); \ 317 } while (0) 318 319 /* 320 * MAC_BOOLEAN performs the designated boolean composition by walking 321 * the module list, invoking each instance of the operation, and 322 * combining the results using the passed C operator. Note that it 323 * returns its value via 'result' in the scope of the caller, which 324 * should be initialized by the caller in a meaningful way to get 325 * a meaningful result. 326 */ 327 #define MAC_BOOLEAN(operation, composition, args...) do { \ 328 struct mac_policy_conf *mpc; \ 329 \ 330 MAC_POLICY_LIST_BUSY(); \ 331 LIST_FOREACH(mpc, &mac_policy_list, mpc_list) { \ 332 if (mpc->mpc_ops->mpo_ ## operation != NULL) \ 333 result = result composition \ 334 mpc->mpc_ops->mpo_ ## operation (args); \ 335 } \ 336 MAC_POLICY_LIST_UNBUSY(); \ 337 } while (0) 338 339 #define MAC_EXTERNALIZE(type, label, elementlist, outbuf, \ 340 outbuflen) do { \ 341 char *curptr, *curptr_start, *element_name, *element_temp; \ 342 size_t left, left_start, len; \ 343 int claimed, first, first_start, ignorenotfound; \ 344 \ 345 error = 0; \ 346 element_temp = elementlist; \ 347 curptr = outbuf; \ 348 curptr[0] = '\0'; \ 349 left = outbuflen; \ 350 first = 1; \ 351 while ((element_name = strsep(&element_temp, ",")) != NULL) { \ 352 curptr_start = curptr; \ 353 left_start = left; \ 354 first_start = first; \ 355 if (element_name[0] == '?') { \ 356 element_name++; \ 357 ignorenotfound = 1; \ 358 } else \ 359 ignorenotfound = 0; \ 360 claimed = 0; \ 361 if (first) { \ 362 len = snprintf(curptr, left, "%s/", \ 363 element_name); \ 364 first = 0; \ 365 } else \ 366 len = snprintf(curptr, left, ",%s/", \ 367 element_name); \ 368 if (len >= left) { \ 369 error = EINVAL; /* XXXMAC: E2BIG */ \ 370 break; \ 371 } \ 372 curptr += len; \ 373 left -= len; \ 374 \ 375 MAC_CHECK(externalize_ ## type, label, element_name, \ 376 curptr, left, &len, &claimed); \ 377 if (error) \ 378 break; \ 379 if (claimed == 1) { \ 380 if (len >= outbuflen) { \ 381 error = EINVAL; /* XXXMAC: E2BIG */ \ 382 break; \ 383 } \ 384 curptr += len; \ 385 left -= len; \ 386 } else if (claimed == 0 && ignorenotfound) { \ 387 /* \ 388 * Revert addition of the label element \ 389 * name. \ 390 */ \ 391 curptr = curptr_start; \ 392 *curptr = '\0'; \ 393 left = left_start; \ 394 first = first_start; \ 395 } else { \ 396 error = EINVAL; /* XXXMAC: ENOLABEL */ \ 397 break; \ 398 } \ 399 } \ 400 } while (0) 401 402 #define MAC_INTERNALIZE(type, label, instring) do { \ 403 char *element, *element_name, *element_data; \ 404 int claimed; \ 405 \ 406 error = 0; \ 407 element = instring; \ 408 while ((element_name = strsep(&element, ",")) != NULL) { \ 409 element_data = element_name; \ 410 element_name = strsep(&element_data, "/"); \ 411 if (element_data == NULL) { \ 412 error = EINVAL; \ 413 break; \ 414 } \ 415 claimed = 0; \ 416 MAC_CHECK(internalize_ ## type, label, element_name, \ 417 element_data, &claimed); \ 418 if (error) \ 419 break; \ 420 if (claimed != 1) { \ 421 /* XXXMAC: Another error here? */ \ 422 error = EINVAL; \ 423 break; \ 424 } \ 425 } \ 426 } while (0) 427 428 /* 429 * MAC_PERFORM performs the designated operation by walking the policy 430 * module list and invoking that operation for each policy. 431 */ 432 #define MAC_PERFORM(operation, args...) do { \ 433 struct mac_policy_conf *mpc; \ 434 \ 435 MAC_POLICY_LIST_BUSY(); \ 436 LIST_FOREACH(mpc, &mac_policy_list, mpc_list) { \ 437 if (mpc->mpc_ops->mpo_ ## operation != NULL) \ 438 mpc->mpc_ops->mpo_ ## operation (args); \ 439 } \ 440 MAC_POLICY_LIST_UNBUSY(); \ 441 } while (0) 442 443 /* 444 * Initialize the MAC subsystem, including appropriate SMP locks. 445 */ 446 static void 447 mac_init(void) 448 { 449 450 LIST_INIT(&mac_policy_list); 451 MAC_POLICY_LIST_LOCKINIT(); 452 } 453 454 /* 455 * For the purposes of modules that want to know if they were loaded 456 * "early", set the mac_late flag once we've processed modules either 457 * linked into the kernel, or loaded before the kernel startup. 458 */ 459 static void 460 mac_late_init(void) 461 { 462 463 mac_late = 1; 464 } 465 466 /* 467 * Allow MAC policy modules to register during boot, etc. 468 */ 469 int 470 mac_policy_modevent(module_t mod, int type, void *data) 471 { 472 struct mac_policy_conf *mpc; 473 int error; 474 475 error = 0; 476 mpc = (struct mac_policy_conf *) data; 477 478 switch (type) { 479 case MOD_LOAD: 480 if (mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_NOTLATE && 481 mac_late) { 482 printf("mac_policy_modevent: can't load %s policy " 483 "after booting\n", mpc->mpc_name); 484 error = EBUSY; 485 break; 486 } 487 error = mac_policy_register(mpc); 488 break; 489 case MOD_UNLOAD: 490 /* Don't unregister the module if it was never registered. */ 491 if ((mpc->mpc_runtime_flags & MPC_RUNTIME_FLAG_REGISTERED) 492 != 0) 493 error = mac_policy_unregister(mpc); 494 else 495 error = 0; 496 break; 497 default: 498 break; 499 } 500 501 return (error); 502 } 503 504 static int 505 mac_policy_register(struct mac_policy_conf *mpc) 506 { 507 struct mac_policy_conf *tmpc; 508 int slot; 509 510 MAC_POLICY_LIST_EXCLUSIVE(); 511 LIST_FOREACH(tmpc, &mac_policy_list, mpc_list) { 512 if (strcmp(tmpc->mpc_name, mpc->mpc_name) == 0) { 513 MAC_POLICY_LIST_UNLOCK(); 514 return (EEXIST); 515 } 516 } 517 if (mpc->mpc_field_off != NULL) { 518 slot = ffs(mac_policy_offsets_free); 519 if (slot == 0) { 520 MAC_POLICY_LIST_UNLOCK(); 521 return (ENOMEM); 522 } 523 slot--; 524 mac_policy_offsets_free &= ~(1 << slot); 525 *mpc->mpc_field_off = slot; 526 } 527 mpc->mpc_runtime_flags |= MPC_RUNTIME_FLAG_REGISTERED; 528 LIST_INSERT_HEAD(&mac_policy_list, mpc, mpc_list); 529 530 /* Per-policy initialization. */ 531 if (mpc->mpc_ops->mpo_init != NULL) 532 (*(mpc->mpc_ops->mpo_init))(mpc); 533 MAC_POLICY_LIST_UNLOCK(); 534 535 printf("Security policy loaded: %s (%s)\n", mpc->mpc_fullname, 536 mpc->mpc_name); 537 538 return (0); 539 } 540 541 static int 542 mac_policy_unregister(struct mac_policy_conf *mpc) 543 { 544 545 /* 546 * If we fail the load, we may get a request to unload. Check 547 * to see if we did the run-time registration, and if not, 548 * silently succeed. 549 */ 550 MAC_POLICY_LIST_EXCLUSIVE(); 551 if ((mpc->mpc_runtime_flags & MPC_RUNTIME_FLAG_REGISTERED) == 0) { 552 MAC_POLICY_LIST_UNLOCK(); 553 return (0); 554 } 555 #if 0 556 /* 557 * Don't allow unloading modules with private data. 558 */ 559 if (mpc->mpc_field_off != NULL) { 560 MAC_POLICY_LIST_UNLOCK(); 561 return (EBUSY); 562 } 563 #endif 564 /* 565 * Only allow the unload to proceed if the module is unloadable 566 * by its own definition. 567 */ 568 if ((mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_UNLOADOK) == 0) { 569 MAC_POLICY_LIST_UNLOCK(); 570 return (EBUSY); 571 } 572 if (mpc->mpc_ops->mpo_destroy != NULL) 573 (*(mpc->mpc_ops->mpo_destroy))(mpc); 574 575 LIST_REMOVE(mpc, mpc_list); 576 mpc->mpc_runtime_flags &= ~MPC_RUNTIME_FLAG_REGISTERED; 577 578 MAC_POLICY_LIST_UNLOCK(); 579 580 printf("Security policy unload: %s (%s)\n", mpc->mpc_fullname, 581 mpc->mpc_name); 582 583 return (0); 584 } 585 586 /* 587 * Define an error value precedence, and given two arguments, selects the 588 * value with the higher precedence. 589 */ 590 static int 591 error_select(int error1, int error2) 592 { 593 594 /* Certain decision-making errors take top priority. */ 595 if (error1 == EDEADLK || error2 == EDEADLK) 596 return (EDEADLK); 597 598 /* Invalid arguments should be reported where possible. */ 599 if (error1 == EINVAL || error2 == EINVAL) 600 return (EINVAL); 601 602 /* Precedence goes to "visibility", with both process and file. */ 603 if (error1 == ESRCH || error2 == ESRCH) 604 return (ESRCH); 605 606 if (error1 == ENOENT || error2 == ENOENT) 607 return (ENOENT); 608 609 /* Precedence goes to DAC/MAC protections. */ 610 if (error1 == EACCES || error2 == EACCES) 611 return (EACCES); 612 613 /* Precedence goes to privilege. */ 614 if (error1 == EPERM || error2 == EPERM) 615 return (EPERM); 616 617 /* Precedence goes to error over success; otherwise, arbitrary. */ 618 if (error1 != 0) 619 return (error1); 620 return (error2); 621 } 622 623 static void 624 mac_init_label(struct label *label) 625 { 626 627 bzero(label, sizeof(*label)); 628 label->l_flags = MAC_FLAG_INITIALIZED; 629 } 630 631 static void 632 mac_destroy_label(struct label *label) 633 { 634 635 KASSERT(label->l_flags & MAC_FLAG_INITIALIZED, 636 ("destroying uninitialized label")); 637 638 bzero(label, sizeof(*label)); 639 /* implicit: label->l_flags &= ~MAC_FLAG_INITIALIZED; */ 640 } 641 642 void 643 mac_init_bpfdesc(struct bpf_d *bpf_d) 644 { 645 646 mac_init_label(&bpf_d->bd_label); 647 MAC_PERFORM(init_bpfdesc_label, &bpf_d->bd_label); 648 #ifdef MAC_DEBUG 649 atomic_add_int(&nmacbpfdescs, 1); 650 #endif 651 } 652 653 static void 654 mac_init_cred_label(struct label *label) 655 { 656 657 mac_init_label(label); 658 MAC_PERFORM(init_cred_label, label); 659 #ifdef MAC_DEBUG 660 atomic_add_int(&nmaccreds, 1); 661 #endif 662 } 663 664 void 665 mac_init_cred(struct ucred *cred) 666 { 667 668 mac_init_cred_label(&cred->cr_label); 669 } 670 671 void 672 mac_init_devfsdirent(struct devfs_dirent *de) 673 { 674 675 mac_init_label(&de->de_label); 676 MAC_PERFORM(init_devfsdirent_label, &de->de_label); 677 #ifdef MAC_DEBUG 678 atomic_add_int(&nmacdevfsdirents, 1); 679 #endif 680 } 681 682 static void 683 mac_init_ifnet_label(struct label *label) 684 { 685 686 mac_init_label(label); 687 MAC_PERFORM(init_ifnet_label, label); 688 #ifdef MAC_DEBUG 689 atomic_add_int(&nmacifnets, 1); 690 #endif 691 } 692 693 void 694 mac_init_ifnet(struct ifnet *ifp) 695 { 696 697 mac_init_ifnet_label(&ifp->if_label); 698 } 699 700 int 701 mac_init_ipq(struct ipq *ipq, int flag) 702 { 703 int error; 704 705 mac_init_label(&ipq->ipq_label); 706 707 MAC_CHECK(init_ipq_label, &ipq->ipq_label, flag); 708 if (error) { 709 MAC_PERFORM(destroy_ipq_label, &ipq->ipq_label); 710 mac_destroy_label(&ipq->ipq_label); 711 } 712 #ifdef MAC_DEBUG 713 if (error == 0) 714 atomic_add_int(&nmacipqs, 1); 715 #endif 716 return (error); 717 } 718 719 int 720 mac_init_mbuf(struct mbuf *m, int flag) 721 { 722 int error; 723 724 KASSERT(m->m_flags & M_PKTHDR, ("mac_init_mbuf on non-header mbuf")); 725 726 mac_init_label(&m->m_pkthdr.label); 727 728 MAC_CHECK(init_mbuf_label, &m->m_pkthdr.label, flag); 729 if (error) { 730 MAC_PERFORM(destroy_mbuf_label, &m->m_pkthdr.label); 731 mac_destroy_label(&m->m_pkthdr.label); 732 } 733 734 #ifdef MAC_DEBUG 735 if (error == 0) 736 atomic_add_int(&nmacmbufs, 1); 737 #endif 738 return (error); 739 } 740 741 void 742 mac_init_mount(struct mount *mp) 743 { 744 745 mac_init_label(&mp->mnt_mntlabel); 746 mac_init_label(&mp->mnt_fslabel); 747 MAC_PERFORM(init_mount_label, &mp->mnt_mntlabel); 748 MAC_PERFORM(init_mount_fs_label, &mp->mnt_fslabel); 749 #ifdef MAC_DEBUG 750 atomic_add_int(&nmacmounts, 1); 751 #endif 752 } 753 754 static void 755 mac_init_pipe_label(struct label *label) 756 { 757 758 mac_init_label(label); 759 MAC_PERFORM(init_pipe_label, label); 760 #ifdef MAC_DEBUG 761 atomic_add_int(&nmacpipes, 1); 762 #endif 763 } 764 765 void 766 mac_init_pipe(struct pipe *pipe) 767 { 768 struct label *label; 769 770 label = malloc(sizeof(struct label), M_MACPIPELABEL, M_ZERO|M_WAITOK); 771 pipe->pipe_label = label; 772 pipe->pipe_peer->pipe_label = label; 773 mac_init_pipe_label(label); 774 } 775 776 void 777 mac_init_proc(struct proc *p) 778 { 779 780 mac_init_label(&p->p_label); 781 MAC_PERFORM(init_proc_label, &p->p_label); 782 #ifdef MAC_DEBUG 783 atomic_add_int(&nmacprocs, 1); 784 #endif 785 } 786 787 static int 788 mac_init_socket_label(struct label *label, int flag) 789 { 790 int error; 791 792 mac_init_label(label); 793 794 MAC_CHECK(init_socket_label, label, flag); 795 if (error) { 796 MAC_PERFORM(destroy_socket_label, label); 797 mac_destroy_label(label); 798 } 799 800 #ifdef MAC_DEBUG 801 if (error == 0) 802 atomic_add_int(&nmacsockets, 1); 803 #endif 804 805 return (error); 806 } 807 808 static int 809 mac_init_socket_peer_label(struct label *label, int flag) 810 { 811 int error; 812 813 mac_init_label(label); 814 815 MAC_CHECK(init_socket_peer_label, label, flag); 816 if (error) { 817 MAC_PERFORM(destroy_socket_label, label); 818 mac_destroy_label(label); 819 } 820 821 return (error); 822 } 823 824 int 825 mac_init_socket(struct socket *socket, int flag) 826 { 827 int error; 828 829 error = mac_init_socket_label(&socket->so_label, flag); 830 if (error) 831 return (error); 832 833 error = mac_init_socket_peer_label(&socket->so_peerlabel, flag); 834 if (error) 835 mac_destroy_socket_label(&socket->so_label); 836 837 return (error); 838 } 839 840 void 841 mac_init_vnode_label(struct label *label) 842 { 843 844 mac_init_label(label); 845 MAC_PERFORM(init_vnode_label, label); 846 #ifdef MAC_DEBUG 847 atomic_add_int(&nmacvnodes, 1); 848 #endif 849 } 850 851 void 852 mac_init_vnode(struct vnode *vp) 853 { 854 855 mac_init_vnode_label(&vp->v_label); 856 } 857 858 void 859 mac_destroy_bpfdesc(struct bpf_d *bpf_d) 860 { 861 862 MAC_PERFORM(destroy_bpfdesc_label, &bpf_d->bd_label); 863 mac_destroy_label(&bpf_d->bd_label); 864 #ifdef MAC_DEBUG 865 atomic_subtract_int(&nmacbpfdescs, 1); 866 #endif 867 } 868 869 static void 870 mac_destroy_cred_label(struct label *label) 871 { 872 873 MAC_PERFORM(destroy_cred_label, label); 874 mac_destroy_label(label); 875 #ifdef MAC_DEBUG 876 atomic_subtract_int(&nmaccreds, 1); 877 #endif 878 } 879 880 void 881 mac_destroy_cred(struct ucred *cred) 882 { 883 884 mac_destroy_cred_label(&cred->cr_label); 885 } 886 887 void 888 mac_destroy_devfsdirent(struct devfs_dirent *de) 889 { 890 891 MAC_PERFORM(destroy_devfsdirent_label, &de->de_label); 892 mac_destroy_label(&de->de_label); 893 #ifdef MAC_DEBUG 894 atomic_subtract_int(&nmacdevfsdirents, 1); 895 #endif 896 } 897 898 static void 899 mac_destroy_ifnet_label(struct label *label) 900 { 901 902 MAC_PERFORM(destroy_ifnet_label, label); 903 mac_destroy_label(label); 904 #ifdef MAC_DEBUG 905 atomic_subtract_int(&nmacifnets, 1); 906 #endif 907 } 908 909 void 910 mac_destroy_ifnet(struct ifnet *ifp) 911 { 912 913 mac_destroy_ifnet_label(&ifp->if_label); 914 } 915 916 void 917 mac_destroy_ipq(struct ipq *ipq) 918 { 919 920 MAC_PERFORM(destroy_ipq_label, &ipq->ipq_label); 921 mac_destroy_label(&ipq->ipq_label); 922 #ifdef MAC_DEBUG 923 atomic_subtract_int(&nmacipqs, 1); 924 #endif 925 } 926 927 void 928 mac_destroy_mbuf(struct mbuf *m) 929 { 930 931 MAC_PERFORM(destroy_mbuf_label, &m->m_pkthdr.label); 932 mac_destroy_label(&m->m_pkthdr.label); 933 #ifdef MAC_DEBUG 934 atomic_subtract_int(&nmacmbufs, 1); 935 #endif 936 } 937 938 void 939 mac_destroy_mount(struct mount *mp) 940 { 941 942 MAC_PERFORM(destroy_mount_label, &mp->mnt_mntlabel); 943 MAC_PERFORM(destroy_mount_fs_label, &mp->mnt_fslabel); 944 mac_destroy_label(&mp->mnt_fslabel); 945 mac_destroy_label(&mp->mnt_mntlabel); 946 #ifdef MAC_DEBUG 947 atomic_subtract_int(&nmacmounts, 1); 948 #endif 949 } 950 951 static void 952 mac_destroy_pipe_label(struct label *label) 953 { 954 955 MAC_PERFORM(destroy_pipe_label, label); 956 mac_destroy_label(label); 957 #ifdef MAC_DEBUG 958 atomic_subtract_int(&nmacpipes, 1); 959 #endif 960 } 961 962 void 963 mac_destroy_pipe(struct pipe *pipe) 964 { 965 966 mac_destroy_pipe_label(pipe->pipe_label); 967 free(pipe->pipe_label, M_MACPIPELABEL); 968 } 969 970 void 971 mac_destroy_proc(struct proc *p) 972 { 973 974 MAC_PERFORM(destroy_proc_label, &p->p_label); 975 mac_destroy_label(&p->p_label); 976 #ifdef MAC_DEBUG 977 atomic_subtract_int(&nmacprocs, 1); 978 #endif 979 } 980 981 static void 982 mac_destroy_socket_label(struct label *label) 983 { 984 985 MAC_PERFORM(destroy_socket_label, label); 986 mac_destroy_label(label); 987 #ifdef MAC_DEBUG 988 atomic_subtract_int(&nmacsockets, 1); 989 #endif 990 } 991 992 static void 993 mac_destroy_socket_peer_label(struct label *label) 994 { 995 996 MAC_PERFORM(destroy_socket_peer_label, label); 997 mac_destroy_label(label); 998 } 999 1000 void 1001 mac_destroy_socket(struct socket *socket) 1002 { 1003 1004 mac_destroy_socket_label(&socket->so_label); 1005 mac_destroy_socket_peer_label(&socket->so_peerlabel); 1006 } 1007 1008 void 1009 mac_destroy_vnode_label(struct label *label) 1010 { 1011 1012 MAC_PERFORM(destroy_vnode_label, label); 1013 mac_destroy_label(label); 1014 #ifdef MAC_DEBUG 1015 atomic_subtract_int(&nmacvnodes, 1); 1016 #endif 1017 } 1018 1019 void 1020 mac_destroy_vnode(struct vnode *vp) 1021 { 1022 1023 mac_destroy_vnode_label(&vp->v_label); 1024 } 1025 1026 static void 1027 mac_copy_pipe_label(struct label *src, struct label *dest) 1028 { 1029 1030 MAC_PERFORM(copy_pipe_label, src, dest); 1031 } 1032 1033 void 1034 mac_copy_vnode_label(struct label *src, struct label *dest) 1035 { 1036 1037 MAC_PERFORM(copy_vnode_label, src, dest); 1038 } 1039 1040 static int 1041 mac_check_structmac_consistent(struct mac *mac) 1042 { 1043 1044 if (mac->m_buflen > MAC_MAX_LABEL_BUF_LEN) 1045 return (EINVAL); 1046 1047 return (0); 1048 } 1049 1050 static int 1051 mac_externalize_cred_label(struct label *label, char *elements, 1052 char *outbuf, size_t outbuflen, int flags) 1053 { 1054 int error; 1055 1056 MAC_EXTERNALIZE(cred_label, label, elements, outbuf, outbuflen); 1057 1058 return (error); 1059 } 1060 1061 static int 1062 mac_externalize_ifnet_label(struct label *label, char *elements, 1063 char *outbuf, size_t outbuflen, int flags) 1064 { 1065 int error; 1066 1067 MAC_EXTERNALIZE(ifnet_label, label, elements, outbuf, outbuflen); 1068 1069 return (error); 1070 } 1071 1072 static int 1073 mac_externalize_pipe_label(struct label *label, char *elements, 1074 char *outbuf, size_t outbuflen, int flags) 1075 { 1076 int error; 1077 1078 MAC_EXTERNALIZE(pipe_label, label, elements, outbuf, outbuflen); 1079 1080 return (error); 1081 } 1082 1083 static int 1084 mac_externalize_socket_label(struct label *label, char *elements, 1085 char *outbuf, size_t outbuflen, int flags) 1086 { 1087 int error; 1088 1089 MAC_EXTERNALIZE(socket_label, label, elements, outbuf, outbuflen); 1090 1091 return (error); 1092 } 1093 1094 static int 1095 mac_externalize_socket_peer_label(struct label *label, char *elements, 1096 char *outbuf, size_t outbuflen, int flags) 1097 { 1098 int error; 1099 1100 MAC_EXTERNALIZE(socket_peer_label, label, elements, outbuf, outbuflen); 1101 1102 return (error); 1103 } 1104 1105 static int 1106 mac_externalize_vnode_label(struct label *label, char *elements, 1107 char *outbuf, size_t outbuflen, int flags) 1108 { 1109 int error; 1110 1111 MAC_EXTERNALIZE(vnode_label, label, elements, outbuf, outbuflen); 1112 1113 return (error); 1114 } 1115 1116 static int 1117 mac_internalize_cred_label(struct label *label, char *string) 1118 { 1119 int error; 1120 1121 MAC_INTERNALIZE(cred_label, label, string); 1122 1123 return (error); 1124 } 1125 1126 static int 1127 mac_internalize_ifnet_label(struct label *label, char *string) 1128 { 1129 int error; 1130 1131 MAC_INTERNALIZE(ifnet_label, label, string); 1132 1133 return (error); 1134 } 1135 1136 static int 1137 mac_internalize_pipe_label(struct label *label, char *string) 1138 { 1139 int error; 1140 1141 MAC_INTERNALIZE(pipe_label, label, string); 1142 1143 return (error); 1144 } 1145 1146 static int 1147 mac_internalize_socket_label(struct label *label, char *string) 1148 { 1149 int error; 1150 1151 MAC_INTERNALIZE(socket_label, label, string); 1152 1153 return (error); 1154 } 1155 1156 static int 1157 mac_internalize_vnode_label(struct label *label, char *string) 1158 { 1159 int error; 1160 1161 MAC_INTERNALIZE(vnode_label, label, string); 1162 1163 return (error); 1164 } 1165 1166 /* 1167 * Initialize MAC label for the first kernel process, from which other 1168 * kernel processes and threads are spawned. 1169 */ 1170 void 1171 mac_create_proc0(struct ucred *cred) 1172 { 1173 1174 MAC_PERFORM(create_proc0, cred); 1175 } 1176 1177 /* 1178 * Initialize MAC label for the first userland process, from which other 1179 * userland processes and threads are spawned. 1180 */ 1181 void 1182 mac_create_proc1(struct ucred *cred) 1183 { 1184 1185 MAC_PERFORM(create_proc1, cred); 1186 } 1187 1188 void 1189 mac_thread_userret(struct thread *td) 1190 { 1191 1192 MAC_PERFORM(thread_userret, td); 1193 } 1194 1195 /* 1196 * When a new process is created, its label must be initialized. Generally, 1197 * this involves inheritence from the parent process, modulo possible 1198 * deltas. This function allows that processing to take place. 1199 */ 1200 void 1201 mac_create_cred(struct ucred *parent_cred, struct ucred *child_cred) 1202 { 1203 1204 MAC_PERFORM(create_cred, parent_cred, child_cred); 1205 } 1206 1207 void 1208 mac_update_devfsdirent(struct mount *mp, struct devfs_dirent *de, 1209 struct vnode *vp) 1210 { 1211 1212 MAC_PERFORM(update_devfsdirent, mp, de, &de->de_label, vp, 1213 &vp->v_label); 1214 } 1215 1216 void 1217 mac_associate_vnode_devfs(struct mount *mp, struct devfs_dirent *de, 1218 struct vnode *vp) 1219 { 1220 1221 MAC_PERFORM(associate_vnode_devfs, mp, &mp->mnt_fslabel, de, 1222 &de->de_label, vp, &vp->v_label); 1223 } 1224 1225 int 1226 mac_associate_vnode_extattr(struct mount *mp, struct vnode *vp) 1227 { 1228 int error; 1229 1230 ASSERT_VOP_LOCKED(vp, "mac_associate_vnode_extattr"); 1231 1232 MAC_CHECK(associate_vnode_extattr, mp, &mp->mnt_fslabel, vp, 1233 &vp->v_label); 1234 1235 return (error); 1236 } 1237 1238 void 1239 mac_associate_vnode_singlelabel(struct mount *mp, struct vnode *vp) 1240 { 1241 1242 MAC_PERFORM(associate_vnode_singlelabel, mp, &mp->mnt_fslabel, vp, 1243 &vp->v_label); 1244 } 1245 1246 int 1247 mac_create_vnode_extattr(struct ucred *cred, struct mount *mp, 1248 struct vnode *dvp, struct vnode *vp, struct componentname *cnp) 1249 { 1250 int error; 1251 1252 ASSERT_VOP_LOCKED(dvp, "mac_create_vnode_extattr"); 1253 ASSERT_VOP_LOCKED(vp, "mac_create_vnode_extattr"); 1254 1255 error = VOP_OPENEXTATTR(vp, cred, curthread); 1256 if (error == EOPNOTSUPP) { 1257 /* XXX: Optionally abort if transactions not supported. */ 1258 if (ea_warn_once == 0) { 1259 printf("Warning: transactions not supported " 1260 "in EA write.\n"); 1261 ea_warn_once = 1; 1262 } 1263 } else if (error) 1264 return (error); 1265 1266 MAC_CHECK(create_vnode_extattr, cred, mp, &mp->mnt_fslabel, 1267 dvp, &dvp->v_label, vp, &vp->v_label, cnp); 1268 1269 if (error) { 1270 VOP_CLOSEEXTATTR(vp, 0, NOCRED, curthread); 1271 return (error); 1272 } 1273 1274 error = VOP_CLOSEEXTATTR(vp, 1, NOCRED, curthread); 1275 1276 if (error == EOPNOTSUPP) 1277 error = 0; /* XXX */ 1278 1279 return (error); 1280 } 1281 1282 static int 1283 mac_setlabel_vnode_extattr(struct ucred *cred, struct vnode *vp, 1284 struct label *intlabel) 1285 { 1286 int error; 1287 1288 ASSERT_VOP_LOCKED(vp, "mac_setlabel_vnode_extattr"); 1289 1290 error = VOP_OPENEXTATTR(vp, cred, curthread); 1291 if (error == EOPNOTSUPP) { 1292 /* XXX: Optionally abort if transactions not supported. */ 1293 if (ea_warn_once == 0) { 1294 printf("Warning: transactions not supported " 1295 "in EA write.\n"); 1296 ea_warn_once = 1; 1297 } 1298 } else if (error) 1299 return (error); 1300 1301 MAC_CHECK(setlabel_vnode_extattr, cred, vp, &vp->v_label, intlabel); 1302 1303 if (error) { 1304 VOP_CLOSEEXTATTR(vp, 0, NOCRED, curthread); 1305 return (error); 1306 } 1307 1308 error = VOP_CLOSEEXTATTR(vp, 1, NOCRED, curthread); 1309 1310 if (error == EOPNOTSUPP) 1311 error = 0; /* XXX */ 1312 1313 return (error); 1314 } 1315 1316 int 1317 mac_execve_enter(struct image_params *imgp, struct mac *mac_p, 1318 struct label *execlabelstorage) 1319 { 1320 struct mac mac; 1321 char *buffer; 1322 int error; 1323 1324 if (mac_p == NULL) 1325 return (0); 1326 1327 error = copyin(mac_p, &mac, sizeof(mac)); 1328 if (error) 1329 return (error); 1330 1331 error = mac_check_structmac_consistent(&mac); 1332 if (error) 1333 return (error); 1334 1335 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 1336 error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL); 1337 if (error) { 1338 free(buffer, M_MACTEMP); 1339 return (error); 1340 } 1341 1342 mac_init_cred_label(execlabelstorage); 1343 error = mac_internalize_cred_label(execlabelstorage, buffer); 1344 free(buffer, M_MACTEMP); 1345 if (error) { 1346 mac_destroy_cred_label(execlabelstorage); 1347 return (error); 1348 } 1349 imgp->execlabel = execlabelstorage; 1350 return (0); 1351 } 1352 1353 void 1354 mac_execve_exit(struct image_params *imgp) 1355 { 1356 if (imgp->execlabel != NULL) 1357 mac_destroy_cred_label(imgp->execlabel); 1358 } 1359 1360 void 1361 mac_execve_transition(struct ucred *old, struct ucred *new, struct vnode *vp, 1362 struct label *interpvnodelabel, struct image_params *imgp) 1363 { 1364 1365 ASSERT_VOP_LOCKED(vp, "mac_execve_transition"); 1366 1367 if (!mac_enforce_process && !mac_enforce_fs) 1368 return; 1369 1370 MAC_PERFORM(execve_transition, old, new, vp, &vp->v_label, 1371 interpvnodelabel, imgp, imgp->execlabel); 1372 } 1373 1374 int 1375 mac_execve_will_transition(struct ucred *old, struct vnode *vp, 1376 struct label *interpvnodelabel, struct image_params *imgp) 1377 { 1378 int result; 1379 1380 ASSERT_VOP_LOCKED(vp, "mac_execve_will_transition"); 1381 1382 if (!mac_enforce_process && !mac_enforce_fs) 1383 return (0); 1384 1385 result = 0; 1386 MAC_BOOLEAN(execve_will_transition, ||, old, vp, &vp->v_label, 1387 interpvnodelabel, imgp, imgp->execlabel); 1388 1389 return (result); 1390 } 1391 1392 int 1393 mac_check_vnode_access(struct ucred *cred, struct vnode *vp, int acc_mode) 1394 { 1395 int error; 1396 1397 ASSERT_VOP_LOCKED(vp, "mac_check_vnode_access"); 1398 1399 if (!mac_enforce_fs) 1400 return (0); 1401 1402 MAC_CHECK(check_vnode_access, cred, vp, &vp->v_label, acc_mode); 1403 return (error); 1404 } 1405 1406 int 1407 mac_check_vnode_chdir(struct ucred *cred, struct vnode *dvp) 1408 { 1409 int error; 1410 1411 ASSERT_VOP_LOCKED(dvp, "mac_check_vnode_chdir"); 1412 1413 if (!mac_enforce_fs) 1414 return (0); 1415 1416 MAC_CHECK(check_vnode_chdir, cred, dvp, &dvp->v_label); 1417 return (error); 1418 } 1419 1420 int 1421 mac_check_vnode_chroot(struct ucred *cred, struct vnode *dvp) 1422 { 1423 int error; 1424 1425 ASSERT_VOP_LOCKED(dvp, "mac_check_vnode_chroot"); 1426 1427 if (!mac_enforce_fs) 1428 return (0); 1429 1430 MAC_CHECK(check_vnode_chroot, cred, dvp, &dvp->v_label); 1431 return (error); 1432 } 1433 1434 int 1435 mac_check_vnode_create(struct ucred *cred, struct vnode *dvp, 1436 struct componentname *cnp, struct vattr *vap) 1437 { 1438 int error; 1439 1440 ASSERT_VOP_LOCKED(dvp, "mac_check_vnode_create"); 1441 1442 if (!mac_enforce_fs) 1443 return (0); 1444 1445 MAC_CHECK(check_vnode_create, cred, dvp, &dvp->v_label, cnp, vap); 1446 return (error); 1447 } 1448 1449 int 1450 mac_check_vnode_delete(struct ucred *cred, struct vnode *dvp, struct vnode *vp, 1451 struct componentname *cnp) 1452 { 1453 int error; 1454 1455 ASSERT_VOP_LOCKED(dvp, "mac_check_vnode_delete"); 1456 ASSERT_VOP_LOCKED(vp, "mac_check_vnode_delete"); 1457 1458 if (!mac_enforce_fs) 1459 return (0); 1460 1461 MAC_CHECK(check_vnode_delete, cred, dvp, &dvp->v_label, vp, 1462 &vp->v_label, cnp); 1463 return (error); 1464 } 1465 1466 int 1467 mac_check_vnode_deleteacl(struct ucred *cred, struct vnode *vp, 1468 acl_type_t type) 1469 { 1470 int error; 1471 1472 ASSERT_VOP_LOCKED(vp, "mac_check_vnode_deleteacl"); 1473 1474 if (!mac_enforce_fs) 1475 return (0); 1476 1477 MAC_CHECK(check_vnode_deleteacl, cred, vp, &vp->v_label, type); 1478 return (error); 1479 } 1480 1481 int 1482 mac_check_vnode_exec(struct ucred *cred, struct vnode *vp, 1483 struct image_params *imgp) 1484 { 1485 int error; 1486 1487 ASSERT_VOP_LOCKED(vp, "mac_check_vnode_exec"); 1488 1489 if (!mac_enforce_process && !mac_enforce_fs) 1490 return (0); 1491 1492 MAC_CHECK(check_vnode_exec, cred, vp, &vp->v_label, imgp, 1493 imgp->execlabel); 1494 1495 return (error); 1496 } 1497 1498 int 1499 mac_check_vnode_getacl(struct ucred *cred, struct vnode *vp, acl_type_t type) 1500 { 1501 int error; 1502 1503 ASSERT_VOP_LOCKED(vp, "mac_check_vnode_getacl"); 1504 1505 if (!mac_enforce_fs) 1506 return (0); 1507 1508 MAC_CHECK(check_vnode_getacl, cred, vp, &vp->v_label, type); 1509 return (error); 1510 } 1511 1512 int 1513 mac_check_vnode_getextattr(struct ucred *cred, struct vnode *vp, 1514 int attrnamespace, const char *name, struct uio *uio) 1515 { 1516 int error; 1517 1518 ASSERT_VOP_LOCKED(vp, "mac_check_vnode_getextattr"); 1519 1520 if (!mac_enforce_fs) 1521 return (0); 1522 1523 MAC_CHECK(check_vnode_getextattr, cred, vp, &vp->v_label, 1524 attrnamespace, name, uio); 1525 return (error); 1526 } 1527 1528 int 1529 mac_check_vnode_link(struct ucred *cred, struct vnode *dvp, 1530 struct vnode *vp, struct componentname *cnp) 1531 { 1532 int error; 1533 1534 ASSERT_VOP_LOCKED(dvp, "mac_check_vnode_link"); 1535 ASSERT_VOP_LOCKED(vp, "mac_check_vnode_link"); 1536 1537 if (!mac_enforce_fs) 1538 return (0); 1539 1540 MAC_CHECK(check_vnode_link, cred, dvp, &dvp->v_label, vp, 1541 &vp->v_label, cnp); 1542 return (error); 1543 } 1544 1545 int 1546 mac_check_vnode_lookup(struct ucred *cred, struct vnode *dvp, 1547 struct componentname *cnp) 1548 { 1549 int error; 1550 1551 ASSERT_VOP_LOCKED(dvp, "mac_check_vnode_lookup"); 1552 1553 if (!mac_enforce_fs) 1554 return (0); 1555 1556 MAC_CHECK(check_vnode_lookup, cred, dvp, &dvp->v_label, cnp); 1557 return (error); 1558 } 1559 1560 int 1561 mac_check_vnode_mmap(struct ucred *cred, struct vnode *vp, int prot) 1562 { 1563 int error; 1564 1565 ASSERT_VOP_LOCKED(vp, "mac_check_vnode_mmap"); 1566 1567 if (!mac_enforce_fs || !mac_enforce_vm) 1568 return (0); 1569 1570 MAC_CHECK(check_vnode_mmap, cred, vp, &vp->v_label, prot); 1571 return (error); 1572 } 1573 1574 void 1575 mac_check_vnode_mmap_downgrade(struct ucred *cred, struct vnode *vp, int *prot) 1576 { 1577 int result = *prot; 1578 1579 ASSERT_VOP_LOCKED(vp, "mac_check_vnode_mmap_downgrade"); 1580 1581 if (!mac_enforce_fs || !mac_enforce_vm) 1582 return; 1583 1584 MAC_PERFORM(check_vnode_mmap_downgrade, cred, vp, &vp->v_label, 1585 &result); 1586 1587 *prot = result; 1588 } 1589 1590 int 1591 mac_check_vnode_mprotect(struct ucred *cred, struct vnode *vp, int prot) 1592 { 1593 int error; 1594 1595 ASSERT_VOP_LOCKED(vp, "mac_check_vnode_mprotect"); 1596 1597 if (!mac_enforce_fs || !mac_enforce_vm) 1598 return (0); 1599 1600 MAC_CHECK(check_vnode_mprotect, cred, vp, &vp->v_label, prot); 1601 return (error); 1602 } 1603 1604 int 1605 mac_check_vnode_open(struct ucred *cred, struct vnode *vp, int acc_mode) 1606 { 1607 int error; 1608 1609 ASSERT_VOP_LOCKED(vp, "mac_check_vnode_open"); 1610 1611 if (!mac_enforce_fs) 1612 return (0); 1613 1614 MAC_CHECK(check_vnode_open, cred, vp, &vp->v_label, acc_mode); 1615 return (error); 1616 } 1617 1618 int 1619 mac_check_vnode_poll(struct ucred *active_cred, struct ucred *file_cred, 1620 struct vnode *vp) 1621 { 1622 int error; 1623 1624 ASSERT_VOP_LOCKED(vp, "mac_check_vnode_poll"); 1625 1626 if (!mac_enforce_fs) 1627 return (0); 1628 1629 MAC_CHECK(check_vnode_poll, active_cred, file_cred, vp, 1630 &vp->v_label); 1631 1632 return (error); 1633 } 1634 1635 int 1636 mac_check_vnode_read(struct ucred *active_cred, struct ucred *file_cred, 1637 struct vnode *vp) 1638 { 1639 int error; 1640 1641 ASSERT_VOP_LOCKED(vp, "mac_check_vnode_read"); 1642 1643 if (!mac_enforce_fs) 1644 return (0); 1645 1646 MAC_CHECK(check_vnode_read, active_cred, file_cred, vp, 1647 &vp->v_label); 1648 1649 return (error); 1650 } 1651 1652 int 1653 mac_check_vnode_readdir(struct ucred *cred, struct vnode *dvp) 1654 { 1655 int error; 1656 1657 ASSERT_VOP_LOCKED(dvp, "mac_check_vnode_readdir"); 1658 1659 if (!mac_enforce_fs) 1660 return (0); 1661 1662 MAC_CHECK(check_vnode_readdir, cred, dvp, &dvp->v_label); 1663 return (error); 1664 } 1665 1666 int 1667 mac_check_vnode_readlink(struct ucred *cred, struct vnode *vp) 1668 { 1669 int error; 1670 1671 ASSERT_VOP_LOCKED(vp, "mac_check_vnode_readlink"); 1672 1673 if (!mac_enforce_fs) 1674 return (0); 1675 1676 MAC_CHECK(check_vnode_readlink, cred, vp, &vp->v_label); 1677 return (error); 1678 } 1679 1680 static int 1681 mac_check_vnode_relabel(struct ucred *cred, struct vnode *vp, 1682 struct label *newlabel) 1683 { 1684 int error; 1685 1686 ASSERT_VOP_LOCKED(vp, "mac_check_vnode_relabel"); 1687 1688 MAC_CHECK(check_vnode_relabel, cred, vp, &vp->v_label, newlabel); 1689 1690 return (error); 1691 } 1692 1693 int 1694 mac_check_vnode_rename_from(struct ucred *cred, struct vnode *dvp, 1695 struct vnode *vp, struct componentname *cnp) 1696 { 1697 int error; 1698 1699 ASSERT_VOP_LOCKED(dvp, "mac_check_vnode_rename_from"); 1700 ASSERT_VOP_LOCKED(vp, "mac_check_vnode_rename_from"); 1701 1702 if (!mac_enforce_fs) 1703 return (0); 1704 1705 MAC_CHECK(check_vnode_rename_from, cred, dvp, &dvp->v_label, vp, 1706 &vp->v_label, cnp); 1707 return (error); 1708 } 1709 1710 int 1711 mac_check_vnode_rename_to(struct ucred *cred, struct vnode *dvp, 1712 struct vnode *vp, int samedir, struct componentname *cnp) 1713 { 1714 int error; 1715 1716 ASSERT_VOP_LOCKED(dvp, "mac_check_vnode_rename_to"); 1717 ASSERT_VOP_LOCKED(vp, "mac_check_vnode_rename_to"); 1718 1719 if (!mac_enforce_fs) 1720 return (0); 1721 1722 MAC_CHECK(check_vnode_rename_to, cred, dvp, &dvp->v_label, vp, 1723 vp != NULL ? &vp->v_label : NULL, samedir, cnp); 1724 return (error); 1725 } 1726 1727 int 1728 mac_check_vnode_revoke(struct ucred *cred, struct vnode *vp) 1729 { 1730 int error; 1731 1732 ASSERT_VOP_LOCKED(vp, "mac_check_vnode_revoke"); 1733 1734 if (!mac_enforce_fs) 1735 return (0); 1736 1737 MAC_CHECK(check_vnode_revoke, cred, vp, &vp->v_label); 1738 return (error); 1739 } 1740 1741 int 1742 mac_check_vnode_setacl(struct ucred *cred, struct vnode *vp, acl_type_t type, 1743 struct acl *acl) 1744 { 1745 int error; 1746 1747 ASSERT_VOP_LOCKED(vp, "mac_check_vnode_setacl"); 1748 1749 if (!mac_enforce_fs) 1750 return (0); 1751 1752 MAC_CHECK(check_vnode_setacl, cred, vp, &vp->v_label, type, acl); 1753 return (error); 1754 } 1755 1756 int 1757 mac_check_vnode_setextattr(struct ucred *cred, struct vnode *vp, 1758 int attrnamespace, const char *name, struct uio *uio) 1759 { 1760 int error; 1761 1762 ASSERT_VOP_LOCKED(vp, "mac_check_vnode_setextattr"); 1763 1764 if (!mac_enforce_fs) 1765 return (0); 1766 1767 MAC_CHECK(check_vnode_setextattr, cred, vp, &vp->v_label, 1768 attrnamespace, name, uio); 1769 return (error); 1770 } 1771 1772 int 1773 mac_check_vnode_setflags(struct ucred *cred, struct vnode *vp, u_long flags) 1774 { 1775 int error; 1776 1777 ASSERT_VOP_LOCKED(vp, "mac_check_vnode_setflags"); 1778 1779 if (!mac_enforce_fs) 1780 return (0); 1781 1782 MAC_CHECK(check_vnode_setflags, cred, vp, &vp->v_label, flags); 1783 return (error); 1784 } 1785 1786 int 1787 mac_check_vnode_setmode(struct ucred *cred, struct vnode *vp, mode_t mode) 1788 { 1789 int error; 1790 1791 ASSERT_VOP_LOCKED(vp, "mac_check_vnode_setmode"); 1792 1793 if (!mac_enforce_fs) 1794 return (0); 1795 1796 MAC_CHECK(check_vnode_setmode, cred, vp, &vp->v_label, mode); 1797 return (error); 1798 } 1799 1800 int 1801 mac_check_vnode_setowner(struct ucred *cred, struct vnode *vp, uid_t uid, 1802 gid_t gid) 1803 { 1804 int error; 1805 1806 ASSERT_VOP_LOCKED(vp, "mac_check_vnode_setowner"); 1807 1808 if (!mac_enforce_fs) 1809 return (0); 1810 1811 MAC_CHECK(check_vnode_setowner, cred, vp, &vp->v_label, uid, gid); 1812 return (error); 1813 } 1814 1815 int 1816 mac_check_vnode_setutimes(struct ucred *cred, struct vnode *vp, 1817 struct timespec atime, struct timespec mtime) 1818 { 1819 int error; 1820 1821 ASSERT_VOP_LOCKED(vp, "mac_check_vnode_setutimes"); 1822 1823 if (!mac_enforce_fs) 1824 return (0); 1825 1826 MAC_CHECK(check_vnode_setutimes, cred, vp, &vp->v_label, atime, 1827 mtime); 1828 return (error); 1829 } 1830 1831 int 1832 mac_check_vnode_stat(struct ucred *active_cred, struct ucred *file_cred, 1833 struct vnode *vp) 1834 { 1835 int error; 1836 1837 ASSERT_VOP_LOCKED(vp, "mac_check_vnode_stat"); 1838 1839 if (!mac_enforce_fs) 1840 return (0); 1841 1842 MAC_CHECK(check_vnode_stat, active_cred, file_cred, vp, 1843 &vp->v_label); 1844 return (error); 1845 } 1846 1847 int 1848 mac_check_vnode_write(struct ucred *active_cred, struct ucred *file_cred, 1849 struct vnode *vp) 1850 { 1851 int error; 1852 1853 ASSERT_VOP_LOCKED(vp, "mac_check_vnode_write"); 1854 1855 if (!mac_enforce_fs) 1856 return (0); 1857 1858 MAC_CHECK(check_vnode_write, active_cred, file_cred, vp, 1859 &vp->v_label); 1860 1861 return (error); 1862 } 1863 1864 /* 1865 * When relabeling a process, call out to the policies for the maximum 1866 * permission allowed for each object type we know about in its 1867 * memory space, and revoke access (in the least surprising ways we 1868 * know) when necessary. The process lock is not held here. 1869 */ 1870 void 1871 mac_cred_mmapped_drop_perms(struct thread *td, struct ucred *cred) 1872 { 1873 1874 /* XXX freeze all other threads */ 1875 mac_cred_mmapped_drop_perms_recurse(td, cred, 1876 &td->td_proc->p_vmspace->vm_map); 1877 /* XXX allow other threads to continue */ 1878 } 1879 1880 static __inline const char * 1881 prot2str(vm_prot_t prot) 1882 { 1883 1884 switch (prot & VM_PROT_ALL) { 1885 case VM_PROT_READ: 1886 return ("r--"); 1887 case VM_PROT_READ | VM_PROT_WRITE: 1888 return ("rw-"); 1889 case VM_PROT_READ | VM_PROT_EXECUTE: 1890 return ("r-x"); 1891 case VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE: 1892 return ("rwx"); 1893 case VM_PROT_WRITE: 1894 return ("-w-"); 1895 case VM_PROT_EXECUTE: 1896 return ("--x"); 1897 case VM_PROT_WRITE | VM_PROT_EXECUTE: 1898 return ("-wx"); 1899 default: 1900 return ("---"); 1901 } 1902 } 1903 1904 static void 1905 mac_cred_mmapped_drop_perms_recurse(struct thread *td, struct ucred *cred, 1906 struct vm_map *map) 1907 { 1908 struct vm_map_entry *vme; 1909 int result; 1910 vm_prot_t revokeperms; 1911 vm_object_t object; 1912 vm_ooffset_t offset; 1913 struct vnode *vp; 1914 1915 if (!mac_mmap_revocation) 1916 return; 1917 1918 vm_map_lock_read(map); 1919 for (vme = map->header.next; vme != &map->header; vme = vme->next) { 1920 if (vme->eflags & MAP_ENTRY_IS_SUB_MAP) { 1921 mac_cred_mmapped_drop_perms_recurse(td, cred, 1922 vme->object.sub_map); 1923 continue; 1924 } 1925 /* 1926 * Skip over entries that obviously are not shared. 1927 */ 1928 if (vme->eflags & (MAP_ENTRY_COW | MAP_ENTRY_NOSYNC) || 1929 !vme->max_protection) 1930 continue; 1931 /* 1932 * Drill down to the deepest backing object. 1933 */ 1934 offset = vme->offset; 1935 object = vme->object.vm_object; 1936 if (object == NULL) 1937 continue; 1938 while (object->backing_object != NULL) { 1939 object = object->backing_object; 1940 offset += object->backing_object_offset; 1941 } 1942 /* 1943 * At the moment, vm_maps and objects aren't considered 1944 * by the MAC system, so only things with backing by a 1945 * normal object (read: vnodes) are checked. 1946 */ 1947 if (object->type != OBJT_VNODE) 1948 continue; 1949 vp = (struct vnode *)object->handle; 1950 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); 1951 result = vme->max_protection; 1952 mac_check_vnode_mmap_downgrade(cred, vp, &result); 1953 VOP_UNLOCK(vp, 0, td); 1954 /* 1955 * Find out what maximum protection we may be allowing 1956 * now but a policy needs to get removed. 1957 */ 1958 revokeperms = vme->max_protection & ~result; 1959 if (!revokeperms) 1960 continue; 1961 printf("pid %ld: revoking %s perms from %#lx:%ld " 1962 "(max %s/cur %s)\n", (long)td->td_proc->p_pid, 1963 prot2str(revokeperms), (u_long)vme->start, 1964 (long)(vme->end - vme->start), 1965 prot2str(vme->max_protection), prot2str(vme->protection)); 1966 vm_map_lock_upgrade(map); 1967 /* 1968 * This is the really simple case: if a map has more 1969 * max_protection than is allowed, but it's not being 1970 * actually used (that is, the current protection is 1971 * still allowed), we can just wipe it out and do 1972 * nothing more. 1973 */ 1974 if ((vme->protection & revokeperms) == 0) { 1975 vme->max_protection -= revokeperms; 1976 } else { 1977 if (revokeperms & VM_PROT_WRITE) { 1978 /* 1979 * In the more complicated case, flush out all 1980 * pending changes to the object then turn it 1981 * copy-on-write. 1982 */ 1983 vm_object_reference(object); 1984 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); 1985 vm_object_page_clean(object, 1986 OFF_TO_IDX(offset), 1987 OFF_TO_IDX(offset + vme->end - vme->start + 1988 PAGE_MASK), 1989 OBJPC_SYNC); 1990 VOP_UNLOCK(vp, 0, td); 1991 vm_object_deallocate(object); 1992 /* 1993 * Why bother if there's no read permissions 1994 * anymore? For the rest, we need to leave 1995 * the write permissions on for COW, or 1996 * remove them entirely if configured to. 1997 */ 1998 if (!mac_mmap_revocation_via_cow) { 1999 vme->max_protection &= ~VM_PROT_WRITE; 2000 vme->protection &= ~VM_PROT_WRITE; 2001 } if ((revokeperms & VM_PROT_READ) == 0) 2002 vme->eflags |= MAP_ENTRY_COW | 2003 MAP_ENTRY_NEEDS_COPY; 2004 } 2005 if (revokeperms & VM_PROT_EXECUTE) { 2006 vme->max_protection &= ~VM_PROT_EXECUTE; 2007 vme->protection &= ~VM_PROT_EXECUTE; 2008 } 2009 if (revokeperms & VM_PROT_READ) { 2010 vme->max_protection = 0; 2011 vme->protection = 0; 2012 } 2013 pmap_protect(map->pmap, vme->start, vme->end, 2014 vme->protection & ~revokeperms); 2015 vm_map_simplify_entry(map, vme); 2016 } 2017 vm_map_lock_downgrade(map); 2018 } 2019 vm_map_unlock_read(map); 2020 } 2021 2022 /* 2023 * When the subject's label changes, it may require revocation of privilege 2024 * to mapped objects. This can't be done on-the-fly later with a unified 2025 * buffer cache. 2026 */ 2027 static void 2028 mac_relabel_cred(struct ucred *cred, struct label *newlabel) 2029 { 2030 2031 MAC_PERFORM(relabel_cred, cred, newlabel); 2032 } 2033 2034 void 2035 mac_relabel_vnode(struct ucred *cred, struct vnode *vp, struct label *newlabel) 2036 { 2037 2038 MAC_PERFORM(relabel_vnode, cred, vp, &vp->v_label, newlabel); 2039 } 2040 2041 void 2042 mac_create_ifnet(struct ifnet *ifnet) 2043 { 2044 2045 MAC_PERFORM(create_ifnet, ifnet, &ifnet->if_label); 2046 } 2047 2048 void 2049 mac_create_bpfdesc(struct ucred *cred, struct bpf_d *bpf_d) 2050 { 2051 2052 MAC_PERFORM(create_bpfdesc, cred, bpf_d, &bpf_d->bd_label); 2053 } 2054 2055 void 2056 mac_create_socket(struct ucred *cred, struct socket *socket) 2057 { 2058 2059 MAC_PERFORM(create_socket, cred, socket, &socket->so_label); 2060 } 2061 2062 void 2063 mac_create_pipe(struct ucred *cred, struct pipe *pipe) 2064 { 2065 2066 MAC_PERFORM(create_pipe, cred, pipe, pipe->pipe_label); 2067 } 2068 2069 void 2070 mac_create_socket_from_socket(struct socket *oldsocket, 2071 struct socket *newsocket) 2072 { 2073 2074 MAC_PERFORM(create_socket_from_socket, oldsocket, &oldsocket->so_label, 2075 newsocket, &newsocket->so_label); 2076 } 2077 2078 static void 2079 mac_relabel_socket(struct ucred *cred, struct socket *socket, 2080 struct label *newlabel) 2081 { 2082 2083 MAC_PERFORM(relabel_socket, cred, socket, &socket->so_label, newlabel); 2084 } 2085 2086 static void 2087 mac_relabel_pipe(struct ucred *cred, struct pipe *pipe, struct label *newlabel) 2088 { 2089 2090 MAC_PERFORM(relabel_pipe, cred, pipe, pipe->pipe_label, newlabel); 2091 } 2092 2093 void 2094 mac_set_socket_peer_from_mbuf(struct mbuf *mbuf, struct socket *socket) 2095 { 2096 2097 MAC_PERFORM(set_socket_peer_from_mbuf, mbuf, &mbuf->m_pkthdr.label, 2098 socket, &socket->so_peerlabel); 2099 } 2100 2101 void 2102 mac_set_socket_peer_from_socket(struct socket *oldsocket, 2103 struct socket *newsocket) 2104 { 2105 2106 MAC_PERFORM(set_socket_peer_from_socket, oldsocket, 2107 &oldsocket->so_label, newsocket, &newsocket->so_peerlabel); 2108 } 2109 2110 void 2111 mac_create_datagram_from_ipq(struct ipq *ipq, struct mbuf *datagram) 2112 { 2113 2114 MAC_PERFORM(create_datagram_from_ipq, ipq, &ipq->ipq_label, 2115 datagram, &datagram->m_pkthdr.label); 2116 } 2117 2118 void 2119 mac_create_fragment(struct mbuf *datagram, struct mbuf *fragment) 2120 { 2121 2122 MAC_PERFORM(create_fragment, datagram, &datagram->m_pkthdr.label, 2123 fragment, &fragment->m_pkthdr.label); 2124 } 2125 2126 void 2127 mac_create_ipq(struct mbuf *fragment, struct ipq *ipq) 2128 { 2129 2130 MAC_PERFORM(create_ipq, fragment, &fragment->m_pkthdr.label, ipq, 2131 &ipq->ipq_label); 2132 } 2133 2134 void 2135 mac_create_mbuf_from_mbuf(struct mbuf *oldmbuf, struct mbuf *newmbuf) 2136 { 2137 2138 MAC_PERFORM(create_mbuf_from_mbuf, oldmbuf, &oldmbuf->m_pkthdr.label, 2139 newmbuf, &newmbuf->m_pkthdr.label); 2140 } 2141 2142 void 2143 mac_create_mbuf_from_bpfdesc(struct bpf_d *bpf_d, struct mbuf *mbuf) 2144 { 2145 2146 MAC_PERFORM(create_mbuf_from_bpfdesc, bpf_d, &bpf_d->bd_label, mbuf, 2147 &mbuf->m_pkthdr.label); 2148 } 2149 2150 void 2151 mac_create_mbuf_linklayer(struct ifnet *ifnet, struct mbuf *mbuf) 2152 { 2153 2154 MAC_PERFORM(create_mbuf_linklayer, ifnet, &ifnet->if_label, mbuf, 2155 &mbuf->m_pkthdr.label); 2156 } 2157 2158 void 2159 mac_create_mbuf_from_ifnet(struct ifnet *ifnet, struct mbuf *mbuf) 2160 { 2161 2162 MAC_PERFORM(create_mbuf_from_ifnet, ifnet, &ifnet->if_label, mbuf, 2163 &mbuf->m_pkthdr.label); 2164 } 2165 2166 void 2167 mac_create_mbuf_multicast_encap(struct mbuf *oldmbuf, struct ifnet *ifnet, 2168 struct mbuf *newmbuf) 2169 { 2170 2171 MAC_PERFORM(create_mbuf_multicast_encap, oldmbuf, 2172 &oldmbuf->m_pkthdr.label, ifnet, &ifnet->if_label, newmbuf, 2173 &newmbuf->m_pkthdr.label); 2174 } 2175 2176 void 2177 mac_create_mbuf_netlayer(struct mbuf *oldmbuf, struct mbuf *newmbuf) 2178 { 2179 2180 MAC_PERFORM(create_mbuf_netlayer, oldmbuf, &oldmbuf->m_pkthdr.label, 2181 newmbuf, &newmbuf->m_pkthdr.label); 2182 } 2183 2184 int 2185 mac_fragment_match(struct mbuf *fragment, struct ipq *ipq) 2186 { 2187 int result; 2188 2189 result = 1; 2190 MAC_BOOLEAN(fragment_match, &&, fragment, &fragment->m_pkthdr.label, 2191 ipq, &ipq->ipq_label); 2192 2193 return (result); 2194 } 2195 2196 void 2197 mac_update_ipq(struct mbuf *fragment, struct ipq *ipq) 2198 { 2199 2200 MAC_PERFORM(update_ipq, fragment, &fragment->m_pkthdr.label, ipq, 2201 &ipq->ipq_label); 2202 } 2203 2204 void 2205 mac_create_mbuf_from_socket(struct socket *socket, struct mbuf *mbuf) 2206 { 2207 2208 MAC_PERFORM(create_mbuf_from_socket, socket, &socket->so_label, mbuf, 2209 &mbuf->m_pkthdr.label); 2210 } 2211 2212 void 2213 mac_create_mount(struct ucred *cred, struct mount *mp) 2214 { 2215 2216 MAC_PERFORM(create_mount, cred, mp, &mp->mnt_mntlabel, 2217 &mp->mnt_fslabel); 2218 } 2219 2220 void 2221 mac_create_root_mount(struct ucred *cred, struct mount *mp) 2222 { 2223 2224 MAC_PERFORM(create_root_mount, cred, mp, &mp->mnt_mntlabel, 2225 &mp->mnt_fslabel); 2226 } 2227 2228 int 2229 mac_check_bpfdesc_receive(struct bpf_d *bpf_d, struct ifnet *ifnet) 2230 { 2231 int error; 2232 2233 if (!mac_enforce_network) 2234 return (0); 2235 2236 MAC_CHECK(check_bpfdesc_receive, bpf_d, &bpf_d->bd_label, ifnet, 2237 &ifnet->if_label); 2238 2239 return (error); 2240 } 2241 2242 static int 2243 mac_check_cred_relabel(struct ucred *cred, struct label *newlabel) 2244 { 2245 int error; 2246 2247 MAC_CHECK(check_cred_relabel, cred, newlabel); 2248 2249 return (error); 2250 } 2251 2252 int 2253 mac_check_cred_visible(struct ucred *u1, struct ucred *u2) 2254 { 2255 int error; 2256 2257 if (!mac_enforce_process) 2258 return (0); 2259 2260 MAC_CHECK(check_cred_visible, u1, u2); 2261 2262 return (error); 2263 } 2264 2265 int 2266 mac_check_ifnet_transmit(struct ifnet *ifnet, struct mbuf *mbuf) 2267 { 2268 int error; 2269 2270 if (!mac_enforce_network) 2271 return (0); 2272 2273 KASSERT(mbuf->m_flags & M_PKTHDR, ("packet has no pkthdr")); 2274 if (!(mbuf->m_pkthdr.label.l_flags & MAC_FLAG_INITIALIZED)) 2275 if_printf(ifnet, "not initialized\n"); 2276 2277 MAC_CHECK(check_ifnet_transmit, ifnet, &ifnet->if_label, mbuf, 2278 &mbuf->m_pkthdr.label); 2279 2280 return (error); 2281 } 2282 2283 int 2284 mac_check_kenv_dump(struct ucred *cred) 2285 { 2286 int error; 2287 2288 if (!mac_enforce_system) 2289 return (0); 2290 2291 MAC_CHECK(check_kenv_dump, cred); 2292 2293 return (error); 2294 } 2295 2296 int 2297 mac_check_kenv_get(struct ucred *cred, char *name) 2298 { 2299 int error; 2300 2301 if (!mac_enforce_system) 2302 return (0); 2303 2304 MAC_CHECK(check_kenv_get, cred, name); 2305 2306 return (error); 2307 } 2308 2309 int 2310 mac_check_kenv_set(struct ucred *cred, char *name, char *value) 2311 { 2312 int error; 2313 2314 if (!mac_enforce_system) 2315 return (0); 2316 2317 MAC_CHECK(check_kenv_set, cred, name, value); 2318 2319 return (error); 2320 } 2321 2322 int 2323 mac_check_kenv_unset(struct ucred *cred, char *name) 2324 { 2325 int error; 2326 2327 if (!mac_enforce_system) 2328 return (0); 2329 2330 MAC_CHECK(check_kenv_unset, cred, name); 2331 2332 return (error); 2333 } 2334 2335 int 2336 mac_check_kld_load(struct ucred *cred, struct vnode *vp) 2337 { 2338 int error; 2339 2340 ASSERT_VOP_LOCKED(vp, "mac_check_kld_load"); 2341 2342 if (!mac_enforce_kld) 2343 return (0); 2344 2345 MAC_CHECK(check_kld_load, cred, vp, &vp->v_label); 2346 2347 return (error); 2348 } 2349 2350 int 2351 mac_check_kld_stat(struct ucred *cred) 2352 { 2353 int error; 2354 2355 if (!mac_enforce_kld) 2356 return (0); 2357 2358 MAC_CHECK(check_kld_stat, cred); 2359 2360 return (error); 2361 } 2362 2363 int 2364 mac_check_kld_unload(struct ucred *cred) 2365 { 2366 int error; 2367 2368 if (!mac_enforce_kld) 2369 return (0); 2370 2371 MAC_CHECK(check_kld_unload, cred); 2372 2373 return (error); 2374 } 2375 2376 int 2377 mac_check_mount_stat(struct ucred *cred, struct mount *mount) 2378 { 2379 int error; 2380 2381 if (!mac_enforce_fs) 2382 return (0); 2383 2384 MAC_CHECK(check_mount_stat, cred, mount, &mount->mnt_mntlabel); 2385 2386 return (error); 2387 } 2388 2389 int 2390 mac_check_pipe_ioctl(struct ucred *cred, struct pipe *pipe, unsigned long cmd, 2391 void *data) 2392 { 2393 int error; 2394 2395 PIPE_LOCK_ASSERT(pipe, MA_OWNED); 2396 2397 if (!mac_enforce_pipe) 2398 return (0); 2399 2400 MAC_CHECK(check_pipe_ioctl, cred, pipe, pipe->pipe_label, cmd, data); 2401 2402 return (error); 2403 } 2404 2405 int 2406 mac_check_pipe_poll(struct ucred *cred, struct pipe *pipe) 2407 { 2408 int error; 2409 2410 PIPE_LOCK_ASSERT(pipe, MA_OWNED); 2411 2412 if (!mac_enforce_pipe) 2413 return (0); 2414 2415 MAC_CHECK(check_pipe_poll, cred, pipe, pipe->pipe_label); 2416 2417 return (error); 2418 } 2419 2420 int 2421 mac_check_pipe_read(struct ucred *cred, struct pipe *pipe) 2422 { 2423 int error; 2424 2425 PIPE_LOCK_ASSERT(pipe, MA_OWNED); 2426 2427 if (!mac_enforce_pipe) 2428 return (0); 2429 2430 MAC_CHECK(check_pipe_read, cred, pipe, pipe->pipe_label); 2431 2432 return (error); 2433 } 2434 2435 static int 2436 mac_check_pipe_relabel(struct ucred *cred, struct pipe *pipe, 2437 struct label *newlabel) 2438 { 2439 int error; 2440 2441 PIPE_LOCK_ASSERT(pipe, MA_OWNED); 2442 2443 if (!mac_enforce_pipe) 2444 return (0); 2445 2446 MAC_CHECK(check_pipe_relabel, cred, pipe, pipe->pipe_label, newlabel); 2447 2448 return (error); 2449 } 2450 2451 int 2452 mac_check_pipe_stat(struct ucred *cred, struct pipe *pipe) 2453 { 2454 int error; 2455 2456 PIPE_LOCK_ASSERT(pipe, MA_OWNED); 2457 2458 if (!mac_enforce_pipe) 2459 return (0); 2460 2461 MAC_CHECK(check_pipe_stat, cred, pipe, pipe->pipe_label); 2462 2463 return (error); 2464 } 2465 2466 int 2467 mac_check_pipe_write(struct ucred *cred, struct pipe *pipe) 2468 { 2469 int error; 2470 2471 PIPE_LOCK_ASSERT(pipe, MA_OWNED); 2472 2473 if (!mac_enforce_pipe) 2474 return (0); 2475 2476 MAC_CHECK(check_pipe_write, cred, pipe, pipe->pipe_label); 2477 2478 return (error); 2479 } 2480 2481 int 2482 mac_check_proc_debug(struct ucred *cred, struct proc *proc) 2483 { 2484 int error; 2485 2486 PROC_LOCK_ASSERT(proc, MA_OWNED); 2487 2488 if (!mac_enforce_process) 2489 return (0); 2490 2491 MAC_CHECK(check_proc_debug, cred, proc); 2492 2493 return (error); 2494 } 2495 2496 int 2497 mac_check_proc_sched(struct ucred *cred, struct proc *proc) 2498 { 2499 int error; 2500 2501 PROC_LOCK_ASSERT(proc, MA_OWNED); 2502 2503 if (!mac_enforce_process) 2504 return (0); 2505 2506 MAC_CHECK(check_proc_sched, cred, proc); 2507 2508 return (error); 2509 } 2510 2511 int 2512 mac_check_proc_signal(struct ucred *cred, struct proc *proc, int signum) 2513 { 2514 int error; 2515 2516 PROC_LOCK_ASSERT(proc, MA_OWNED); 2517 2518 if (!mac_enforce_process) 2519 return (0); 2520 2521 MAC_CHECK(check_proc_signal, cred, proc, signum); 2522 2523 return (error); 2524 } 2525 2526 int 2527 mac_check_socket_bind(struct ucred *ucred, struct socket *socket, 2528 struct sockaddr *sockaddr) 2529 { 2530 int error; 2531 2532 if (!mac_enforce_socket) 2533 return (0); 2534 2535 MAC_CHECK(check_socket_bind, ucred, socket, &socket->so_label, 2536 sockaddr); 2537 2538 return (error); 2539 } 2540 2541 int 2542 mac_check_socket_connect(struct ucred *cred, struct socket *socket, 2543 struct sockaddr *sockaddr) 2544 { 2545 int error; 2546 2547 if (!mac_enforce_socket) 2548 return (0); 2549 2550 MAC_CHECK(check_socket_connect, cred, socket, &socket->so_label, 2551 sockaddr); 2552 2553 return (error); 2554 } 2555 2556 int 2557 mac_check_socket_deliver(struct socket *socket, struct mbuf *mbuf) 2558 { 2559 int error; 2560 2561 if (!mac_enforce_socket) 2562 return (0); 2563 2564 MAC_CHECK(check_socket_deliver, socket, &socket->so_label, mbuf, 2565 &mbuf->m_pkthdr.label); 2566 2567 return (error); 2568 } 2569 2570 int 2571 mac_check_socket_listen(struct ucred *cred, struct socket *socket) 2572 { 2573 int error; 2574 2575 if (!mac_enforce_socket) 2576 return (0); 2577 2578 MAC_CHECK(check_socket_listen, cred, socket, &socket->so_label); 2579 return (error); 2580 } 2581 2582 int 2583 mac_check_socket_receive(struct ucred *cred, struct socket *so) 2584 { 2585 int error; 2586 2587 if (!mac_enforce_socket) 2588 return (0); 2589 2590 MAC_CHECK(check_socket_receive, cred, so, &so->so_label); 2591 2592 return (error); 2593 } 2594 2595 static int 2596 mac_check_socket_relabel(struct ucred *cred, struct socket *socket, 2597 struct label *newlabel) 2598 { 2599 int error; 2600 2601 MAC_CHECK(check_socket_relabel, cred, socket, &socket->so_label, 2602 newlabel); 2603 2604 return (error); 2605 } 2606 2607 int 2608 mac_check_socket_send(struct ucred *cred, struct socket *so) 2609 { 2610 int error; 2611 2612 if (!mac_enforce_socket) 2613 return (0); 2614 2615 MAC_CHECK(check_socket_send, cred, so, &so->so_label); 2616 2617 return (error); 2618 } 2619 2620 int 2621 mac_check_socket_visible(struct ucred *cred, struct socket *socket) 2622 { 2623 int error; 2624 2625 if (!mac_enforce_socket) 2626 return (0); 2627 2628 MAC_CHECK(check_socket_visible, cred, socket, &socket->so_label); 2629 2630 return (error); 2631 } 2632 2633 int 2634 mac_check_sysarch_ioperm(struct ucred *cred) 2635 { 2636 int error; 2637 2638 if (!mac_enforce_system) 2639 return (0); 2640 2641 MAC_CHECK(check_sysarch_ioperm, cred); 2642 return (error); 2643 } 2644 2645 int 2646 mac_check_system_acct(struct ucred *cred, struct vnode *vp) 2647 { 2648 int error; 2649 2650 if (vp != NULL) { 2651 ASSERT_VOP_LOCKED(vp, "mac_check_system_acct"); 2652 } 2653 2654 if (!mac_enforce_system) 2655 return (0); 2656 2657 MAC_CHECK(check_system_acct, cred, vp, 2658 vp != NULL ? &vp->v_label : NULL); 2659 2660 return (error); 2661 } 2662 2663 int 2664 mac_check_system_nfsd(struct ucred *cred) 2665 { 2666 int error; 2667 2668 if (!mac_enforce_system) 2669 return (0); 2670 2671 MAC_CHECK(check_system_nfsd, cred); 2672 2673 return (error); 2674 } 2675 2676 int 2677 mac_check_system_reboot(struct ucred *cred, int howto) 2678 { 2679 int error; 2680 2681 if (!mac_enforce_system) 2682 return (0); 2683 2684 MAC_CHECK(check_system_reboot, cred, howto); 2685 2686 return (error); 2687 } 2688 2689 int 2690 mac_check_system_settime(struct ucred *cred) 2691 { 2692 int error; 2693 2694 if (!mac_enforce_system) 2695 return (0); 2696 2697 MAC_CHECK(check_system_settime, cred); 2698 2699 return (error); 2700 } 2701 2702 int 2703 mac_check_system_swapon(struct ucred *cred, struct vnode *vp) 2704 { 2705 int error; 2706 2707 ASSERT_VOP_LOCKED(vp, "mac_check_system_swapon"); 2708 2709 if (!mac_enforce_system) 2710 return (0); 2711 2712 MAC_CHECK(check_system_swapon, cred, vp, &vp->v_label); 2713 return (error); 2714 } 2715 2716 int 2717 mac_check_system_swapoff(struct ucred *cred, struct vnode *vp) 2718 { 2719 int error; 2720 2721 ASSERT_VOP_LOCKED(vp, "mac_check_system_swapoff"); 2722 2723 if (!mac_enforce_system) 2724 return (0); 2725 2726 MAC_CHECK(check_system_swapoff, cred, vp, &vp->v_label); 2727 return (error); 2728 } 2729 2730 int 2731 mac_check_system_sysctl(struct ucred *cred, int *name, u_int namelen, 2732 void *old, size_t *oldlenp, int inkernel, void *new, size_t newlen) 2733 { 2734 int error; 2735 2736 /* 2737 * XXXMAC: We're very much like to assert the SYSCTL_LOCK here, 2738 * but since it's not exported from kern_sysctl.c, we can't. 2739 */ 2740 if (!mac_enforce_system) 2741 return (0); 2742 2743 MAC_CHECK(check_system_sysctl, cred, name, namelen, old, oldlenp, 2744 inkernel, new, newlen); 2745 2746 return (error); 2747 } 2748 2749 int 2750 mac_ioctl_ifnet_get(struct ucred *cred, struct ifreq *ifr, 2751 struct ifnet *ifnet) 2752 { 2753 char *elements, *buffer; 2754 struct mac mac; 2755 int error; 2756 2757 error = copyin(ifr->ifr_ifru.ifru_data, &mac, sizeof(mac)); 2758 if (error) 2759 return (error); 2760 2761 error = mac_check_structmac_consistent(&mac); 2762 if (error) 2763 return (error); 2764 2765 elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 2766 error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL); 2767 if (error) { 2768 free(elements, M_MACTEMP); 2769 return (error); 2770 } 2771 2772 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); 2773 error = mac_externalize_ifnet_label(&ifnet->if_label, elements, 2774 buffer, mac.m_buflen, M_WAITOK); 2775 if (error == 0) 2776 error = copyout(buffer, mac.m_string, strlen(buffer)+1); 2777 2778 free(buffer, M_MACTEMP); 2779 free(elements, M_MACTEMP); 2780 2781 return (error); 2782 } 2783 2784 int 2785 mac_ioctl_ifnet_set(struct ucred *cred, struct ifreq *ifr, 2786 struct ifnet *ifnet) 2787 { 2788 struct label intlabel; 2789 struct mac mac; 2790 char *buffer; 2791 int error; 2792 2793 error = copyin(ifr->ifr_ifru.ifru_data, &mac, sizeof(mac)); 2794 if (error) 2795 return (error); 2796 2797 error = mac_check_structmac_consistent(&mac); 2798 if (error) 2799 return (error); 2800 2801 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 2802 error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL); 2803 if (error) { 2804 free(buffer, M_MACTEMP); 2805 return (error); 2806 } 2807 2808 mac_init_ifnet_label(&intlabel); 2809 error = mac_internalize_ifnet_label(&intlabel, buffer); 2810 free(buffer, M_MACTEMP); 2811 if (error) { 2812 mac_destroy_ifnet_label(&intlabel); 2813 return (error); 2814 } 2815 2816 /* 2817 * XXX: Note that this is a redundant privilege check, since 2818 * policies impose this check themselves if required by the 2819 * policy. Eventually, this should go away. 2820 */ 2821 error = suser_cred(cred, 0); 2822 if (error) { 2823 mac_destroy_ifnet_label(&intlabel); 2824 return (error); 2825 } 2826 2827 MAC_CHECK(check_ifnet_relabel, cred, ifnet, &ifnet->if_label, 2828 &intlabel); 2829 if (error) { 2830 mac_destroy_ifnet_label(&intlabel); 2831 return (error); 2832 } 2833 2834 MAC_PERFORM(relabel_ifnet, cred, ifnet, &ifnet->if_label, &intlabel); 2835 2836 mac_destroy_ifnet_label(&intlabel); 2837 return (0); 2838 } 2839 2840 void 2841 mac_create_devfs_device(struct mount *mp, dev_t dev, struct devfs_dirent *de) 2842 { 2843 2844 MAC_PERFORM(create_devfs_device, mp, dev, de, &de->de_label); 2845 } 2846 2847 void 2848 mac_create_devfs_symlink(struct ucred *cred, struct mount *mp, 2849 struct devfs_dirent *dd, struct devfs_dirent *de) 2850 { 2851 2852 MAC_PERFORM(create_devfs_symlink, cred, mp, dd, &dd->de_label, de, 2853 &de->de_label); 2854 } 2855 2856 void 2857 mac_create_devfs_directory(struct mount *mp, char *dirname, int dirnamelen, 2858 struct devfs_dirent *de) 2859 { 2860 2861 MAC_PERFORM(create_devfs_directory, mp, dirname, dirnamelen, de, 2862 &de->de_label); 2863 } 2864 2865 int 2866 mac_setsockopt_label_set(struct ucred *cred, struct socket *so, 2867 struct mac *mac) 2868 { 2869 struct label intlabel; 2870 char *buffer; 2871 int error; 2872 2873 error = mac_check_structmac_consistent(mac); 2874 if (error) 2875 return (error); 2876 2877 buffer = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK); 2878 error = copyinstr(mac->m_string, buffer, mac->m_buflen, NULL); 2879 if (error) { 2880 free(buffer, M_MACTEMP); 2881 return (error); 2882 } 2883 2884 mac_init_socket_label(&intlabel, M_WAITOK); 2885 error = mac_internalize_socket_label(&intlabel, buffer); 2886 free(buffer, M_MACTEMP); 2887 if (error) { 2888 mac_destroy_socket_label(&intlabel); 2889 return (error); 2890 } 2891 2892 mac_check_socket_relabel(cred, so, &intlabel); 2893 if (error) { 2894 mac_destroy_socket_label(&intlabel); 2895 return (error); 2896 } 2897 2898 mac_relabel_socket(cred, so, &intlabel); 2899 2900 mac_destroy_socket_label(&intlabel); 2901 return (0); 2902 } 2903 2904 int 2905 mac_pipe_label_set(struct ucred *cred, struct pipe *pipe, struct label *label) 2906 { 2907 int error; 2908 2909 PIPE_LOCK_ASSERT(pipe, MA_OWNED); 2910 2911 error = mac_check_pipe_relabel(cred, pipe, label); 2912 if (error) 2913 return (error); 2914 2915 mac_relabel_pipe(cred, pipe, label); 2916 2917 return (0); 2918 } 2919 2920 int 2921 mac_getsockopt_label_get(struct ucred *cred, struct socket *so, 2922 struct mac *mac) 2923 { 2924 char *buffer, *elements; 2925 int error; 2926 2927 error = mac_check_structmac_consistent(mac); 2928 if (error) 2929 return (error); 2930 2931 elements = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK); 2932 error = copyinstr(mac->m_string, elements, mac->m_buflen, NULL); 2933 if (error) { 2934 free(elements, M_MACTEMP); 2935 return (error); 2936 } 2937 2938 buffer = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); 2939 error = mac_externalize_socket_label(&so->so_label, elements, 2940 buffer, mac->m_buflen, M_WAITOK); 2941 if (error == 0) 2942 error = copyout(buffer, mac->m_string, strlen(buffer)+1); 2943 2944 free(buffer, M_MACTEMP); 2945 free(elements, M_MACTEMP); 2946 2947 return (error); 2948 } 2949 2950 int 2951 mac_getsockopt_peerlabel_get(struct ucred *cred, struct socket *so, 2952 struct mac *mac) 2953 { 2954 char *elements, *buffer; 2955 int error; 2956 2957 error = mac_check_structmac_consistent(mac); 2958 if (error) 2959 return (error); 2960 2961 elements = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK); 2962 error = copyinstr(mac->m_string, elements, mac->m_buflen, NULL); 2963 if (error) { 2964 free(elements, M_MACTEMP); 2965 return (error); 2966 } 2967 2968 buffer = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); 2969 error = mac_externalize_socket_peer_label(&so->so_peerlabel, 2970 elements, buffer, mac->m_buflen, M_WAITOK); 2971 if (error == 0) 2972 error = copyout(buffer, mac->m_string, strlen(buffer)+1); 2973 2974 free(buffer, M_MACTEMP); 2975 free(elements, M_MACTEMP); 2976 2977 return (error); 2978 } 2979 2980 /* 2981 * Implementation of VOP_SETLABEL() that relies on extended attributes 2982 * to store label data. Can be referenced by filesystems supporting 2983 * extended attributes. 2984 */ 2985 int 2986 vop_stdsetlabel_ea(struct vop_setlabel_args *ap) 2987 { 2988 struct vnode *vp = ap->a_vp; 2989 struct label *intlabel = ap->a_label; 2990 int error; 2991 2992 ASSERT_VOP_LOCKED(vp, "vop_stdsetlabel_ea"); 2993 2994 if ((vp->v_mount->mnt_flag & MNT_MULTILABEL) == 0) 2995 return (EOPNOTSUPP); 2996 2997 error = mac_setlabel_vnode_extattr(ap->a_cred, vp, intlabel); 2998 if (error) 2999 return (error); 3000 3001 mac_relabel_vnode(ap->a_cred, vp, intlabel); 3002 3003 return (0); 3004 } 3005 3006 static int 3007 vn_setlabel(struct vnode *vp, struct label *intlabel, struct ucred *cred) 3008 { 3009 int error; 3010 3011 if (vp->v_mount == NULL) { 3012 /* printf("vn_setlabel: null v_mount\n"); */ 3013 if (vp->v_type != VNON) 3014 printf("vn_setlabel: null v_mount with non-VNON\n"); 3015 return (EBADF); 3016 } 3017 3018 if ((vp->v_mount->mnt_flag & MNT_MULTILABEL) == 0) 3019 return (EOPNOTSUPP); 3020 3021 /* 3022 * Multi-phase commit. First check the policies to confirm the 3023 * change is OK. Then commit via the filesystem. Finally, 3024 * update the actual vnode label. Question: maybe the filesystem 3025 * should update the vnode at the end as part of VOP_SETLABEL()? 3026 */ 3027 error = mac_check_vnode_relabel(cred, vp, intlabel); 3028 if (error) 3029 return (error); 3030 3031 /* 3032 * VADMIN provides the opportunity for the filesystem to make 3033 * decisions about who is and is not able to modify labels 3034 * and protections on files. This might not be right. We can't 3035 * assume VOP_SETLABEL() will do it, because we might implement 3036 * that as part of vop_stdsetlabel_ea(). 3037 */ 3038 error = VOP_ACCESS(vp, VADMIN, cred, curthread); 3039 if (error) 3040 return (error); 3041 3042 error = VOP_SETLABEL(vp, intlabel, cred, curthread); 3043 if (error) 3044 return (error); 3045 3046 return (0); 3047 } 3048 3049 int 3050 __mac_get_pid(struct thread *td, struct __mac_get_pid_args *uap) 3051 { 3052 char *elements, *buffer; 3053 struct mac mac; 3054 struct proc *tproc; 3055 struct ucred *tcred; 3056 int error; 3057 3058 error = copyin(uap->mac_p, &mac, sizeof(mac)); 3059 if (error) 3060 return (error); 3061 3062 error = mac_check_structmac_consistent(&mac); 3063 if (error) 3064 return (error); 3065 3066 tproc = pfind(uap->pid); 3067 if (tproc == NULL) 3068 return (ESRCH); 3069 3070 tcred = NULL; /* Satisfy gcc. */ 3071 error = p_cansee(td, tproc); 3072 if (error == 0) 3073 tcred = crhold(tproc->p_ucred); 3074 PROC_UNLOCK(tproc); 3075 if (error) 3076 return (error); 3077 3078 elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 3079 error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL); 3080 if (error) { 3081 free(elements, M_MACTEMP); 3082 crfree(tcred); 3083 return (error); 3084 } 3085 3086 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); 3087 error = mac_externalize_cred_label(&tcred->cr_label, elements, 3088 buffer, mac.m_buflen, M_WAITOK); 3089 if (error == 0) 3090 error = copyout(buffer, mac.m_string, strlen(buffer)+1); 3091 3092 free(buffer, M_MACTEMP); 3093 free(elements, M_MACTEMP); 3094 crfree(tcred); 3095 return (error); 3096 } 3097 3098 /* 3099 * MPSAFE 3100 */ 3101 int 3102 __mac_get_proc(struct thread *td, struct __mac_get_proc_args *uap) 3103 { 3104 char *elements, *buffer; 3105 struct mac mac; 3106 int error; 3107 3108 error = copyin(uap->mac_p, &mac, sizeof(mac)); 3109 if (error) 3110 return (error); 3111 3112 error = mac_check_structmac_consistent(&mac); 3113 if (error) 3114 return (error); 3115 3116 elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 3117 error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL); 3118 if (error) { 3119 free(elements, M_MACTEMP); 3120 return (error); 3121 } 3122 3123 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); 3124 error = mac_externalize_cred_label(&td->td_ucred->cr_label, 3125 elements, buffer, mac.m_buflen, M_WAITOK); 3126 if (error == 0) 3127 error = copyout(buffer, mac.m_string, strlen(buffer)+1); 3128 3129 free(buffer, M_MACTEMP); 3130 free(elements, M_MACTEMP); 3131 return (error); 3132 } 3133 3134 /* 3135 * MPSAFE 3136 */ 3137 int 3138 __mac_set_proc(struct thread *td, struct __mac_set_proc_args *uap) 3139 { 3140 struct ucred *newcred, *oldcred; 3141 struct label intlabel; 3142 struct proc *p; 3143 struct mac mac; 3144 char *buffer; 3145 int error; 3146 3147 error = copyin(uap->mac_p, &mac, sizeof(mac)); 3148 if (error) 3149 return (error); 3150 3151 error = mac_check_structmac_consistent(&mac); 3152 if (error) 3153 return (error); 3154 3155 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 3156 error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL); 3157 if (error) { 3158 free(buffer, M_MACTEMP); 3159 return (error); 3160 } 3161 3162 mac_init_cred_label(&intlabel); 3163 error = mac_internalize_cred_label(&intlabel, buffer); 3164 free(buffer, M_MACTEMP); 3165 if (error) { 3166 mac_destroy_cred_label(&intlabel); 3167 return (error); 3168 } 3169 3170 newcred = crget(); 3171 3172 p = td->td_proc; 3173 PROC_LOCK(p); 3174 oldcred = p->p_ucred; 3175 3176 error = mac_check_cred_relabel(oldcred, &intlabel); 3177 if (error) { 3178 PROC_UNLOCK(p); 3179 crfree(newcred); 3180 goto out; 3181 } 3182 3183 setsugid(p); 3184 crcopy(newcred, oldcred); 3185 mac_relabel_cred(newcred, &intlabel); 3186 p->p_ucred = newcred; 3187 3188 /* 3189 * Grab additional reference for use while revoking mmaps, prior 3190 * to releasing the proc lock and sharing the cred. 3191 */ 3192 crhold(newcred); 3193 PROC_UNLOCK(p); 3194 3195 if (mac_enforce_vm) { 3196 mtx_lock(&Giant); 3197 mac_cred_mmapped_drop_perms(td, newcred); 3198 mtx_unlock(&Giant); 3199 } 3200 3201 crfree(newcred); /* Free revocation reference. */ 3202 crfree(oldcred); 3203 3204 out: 3205 mac_destroy_cred_label(&intlabel); 3206 return (error); 3207 } 3208 3209 /* 3210 * MPSAFE 3211 */ 3212 int 3213 __mac_get_fd(struct thread *td, struct __mac_get_fd_args *uap) 3214 { 3215 char *elements, *buffer; 3216 struct label intlabel; 3217 struct file *fp; 3218 struct mac mac; 3219 struct vnode *vp; 3220 struct pipe *pipe; 3221 short label_type; 3222 int error; 3223 3224 error = copyin(uap->mac_p, &mac, sizeof(mac)); 3225 if (error) 3226 return (error); 3227 3228 error = mac_check_structmac_consistent(&mac); 3229 if (error) 3230 return (error); 3231 3232 elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 3233 error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL); 3234 if (error) { 3235 free(elements, M_MACTEMP); 3236 return (error); 3237 } 3238 3239 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); 3240 mtx_lock(&Giant); /* VFS */ 3241 error = fget(td, uap->fd, &fp); 3242 if (error) 3243 goto out; 3244 3245 label_type = fp->f_type; 3246 switch (fp->f_type) { 3247 case DTYPE_FIFO: 3248 case DTYPE_VNODE: 3249 vp = fp->f_data; 3250 3251 mac_init_vnode_label(&intlabel); 3252 3253 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); 3254 mac_copy_vnode_label(&vp->v_label, &intlabel); 3255 VOP_UNLOCK(vp, 0, td); 3256 3257 break; 3258 case DTYPE_PIPE: 3259 pipe = fp->f_data; 3260 3261 mac_init_pipe_label(&intlabel); 3262 3263 PIPE_LOCK(pipe); 3264 mac_copy_pipe_label(pipe->pipe_label, &intlabel); 3265 PIPE_UNLOCK(pipe); 3266 break; 3267 default: 3268 error = EINVAL; 3269 fdrop(fp, td); 3270 goto out; 3271 } 3272 fdrop(fp, td); 3273 3274 switch (label_type) { 3275 case DTYPE_FIFO: 3276 case DTYPE_VNODE: 3277 if (error == 0) 3278 error = mac_externalize_vnode_label(&intlabel, 3279 elements, buffer, mac.m_buflen, M_WAITOK); 3280 mac_destroy_vnode_label(&intlabel); 3281 break; 3282 case DTYPE_PIPE: 3283 error = mac_externalize_pipe_label(&intlabel, elements, 3284 buffer, mac.m_buflen, M_WAITOK); 3285 mac_destroy_pipe_label(&intlabel); 3286 break; 3287 default: 3288 panic("__mac_get_fd: corrupted label_type"); 3289 } 3290 3291 if (error == 0) 3292 error = copyout(buffer, mac.m_string, strlen(buffer)+1); 3293 3294 out: 3295 mtx_unlock(&Giant); /* VFS */ 3296 free(buffer, M_MACTEMP); 3297 free(elements, M_MACTEMP); 3298 3299 return (error); 3300 } 3301 3302 /* 3303 * MPSAFE 3304 */ 3305 int 3306 __mac_get_file(struct thread *td, struct __mac_get_file_args *uap) 3307 { 3308 char *elements, *buffer; 3309 struct nameidata nd; 3310 struct label intlabel; 3311 struct mac mac; 3312 int error; 3313 3314 error = copyin(uap->mac_p, &mac, sizeof(mac)); 3315 if (error) 3316 return (error); 3317 3318 error = mac_check_structmac_consistent(&mac); 3319 if (error) 3320 return (error); 3321 3322 elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 3323 error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL); 3324 if (error) { 3325 free(elements, M_MACTEMP); 3326 return (error); 3327 } 3328 3329 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); 3330 mtx_lock(&Giant); /* VFS */ 3331 NDINIT(&nd, LOOKUP, LOCKLEAF | FOLLOW, UIO_USERSPACE, uap->path_p, 3332 td); 3333 error = namei(&nd); 3334 if (error) 3335 goto out; 3336 3337 mac_init_vnode_label(&intlabel); 3338 mac_copy_vnode_label(&nd.ni_vp->v_label, &intlabel); 3339 error = mac_externalize_vnode_label(&intlabel, elements, buffer, 3340 mac.m_buflen, M_WAITOK); 3341 3342 NDFREE(&nd, 0); 3343 mac_destroy_vnode_label(&intlabel); 3344 3345 if (error == 0) 3346 error = copyout(buffer, mac.m_string, strlen(buffer)+1); 3347 3348 out: 3349 mtx_unlock(&Giant); /* VFS */ 3350 3351 free(buffer, M_MACTEMP); 3352 free(elements, M_MACTEMP); 3353 3354 return (error); 3355 } 3356 3357 /* 3358 * MPSAFE 3359 */ 3360 int 3361 __mac_get_link(struct thread *td, struct __mac_get_link_args *uap) 3362 { 3363 char *elements, *buffer; 3364 struct nameidata nd; 3365 struct label intlabel; 3366 struct mac mac; 3367 int error; 3368 3369 error = copyin(uap->mac_p, &mac, sizeof(mac)); 3370 if (error) 3371 return (error); 3372 3373 error = mac_check_structmac_consistent(&mac); 3374 if (error) 3375 return (error); 3376 3377 elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 3378 error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL); 3379 if (error) { 3380 free(elements, M_MACTEMP); 3381 return (error); 3382 } 3383 3384 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); 3385 mtx_lock(&Giant); /* VFS */ 3386 NDINIT(&nd, LOOKUP, LOCKLEAF | NOFOLLOW, UIO_USERSPACE, uap->path_p, 3387 td); 3388 error = namei(&nd); 3389 if (error) 3390 goto out; 3391 3392 mac_init_vnode_label(&intlabel); 3393 mac_copy_vnode_label(&nd.ni_vp->v_label, &intlabel); 3394 error = mac_externalize_vnode_label(&intlabel, elements, buffer, 3395 mac.m_buflen, M_WAITOK); 3396 NDFREE(&nd, 0); 3397 mac_destroy_vnode_label(&intlabel); 3398 3399 if (error == 0) 3400 error = copyout(buffer, mac.m_string, strlen(buffer)+1); 3401 3402 out: 3403 mtx_unlock(&Giant); /* VFS */ 3404 3405 free(buffer, M_MACTEMP); 3406 free(elements, M_MACTEMP); 3407 3408 return (error); 3409 } 3410 3411 /* 3412 * MPSAFE 3413 */ 3414 int 3415 __mac_set_fd(struct thread *td, struct __mac_set_fd_args *uap) 3416 { 3417 struct label intlabel; 3418 struct pipe *pipe; 3419 struct file *fp; 3420 struct mount *mp; 3421 struct vnode *vp; 3422 struct mac mac; 3423 char *buffer; 3424 int error; 3425 3426 error = copyin(uap->mac_p, &mac, sizeof(mac)); 3427 if (error) 3428 return (error); 3429 3430 error = mac_check_structmac_consistent(&mac); 3431 if (error) 3432 return (error); 3433 3434 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 3435 error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL); 3436 if (error) { 3437 free(buffer, M_MACTEMP); 3438 return (error); 3439 } 3440 3441 mtx_lock(&Giant); /* VFS */ 3442 3443 error = fget(td, uap->fd, &fp); 3444 if (error) 3445 goto out; 3446 3447 switch (fp->f_type) { 3448 case DTYPE_FIFO: 3449 case DTYPE_VNODE: 3450 mac_init_vnode_label(&intlabel); 3451 error = mac_internalize_vnode_label(&intlabel, buffer); 3452 if (error) { 3453 mac_destroy_vnode_label(&intlabel); 3454 break; 3455 } 3456 3457 vp = fp->f_data; 3458 error = vn_start_write(vp, &mp, V_WAIT | PCATCH); 3459 if (error != 0) { 3460 mac_destroy_vnode_label(&intlabel); 3461 break; 3462 } 3463 3464 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); 3465 error = vn_setlabel(vp, &intlabel, td->td_ucred); 3466 VOP_UNLOCK(vp, 0, td); 3467 vn_finished_write(mp); 3468 3469 mac_destroy_vnode_label(&intlabel); 3470 break; 3471 3472 case DTYPE_PIPE: 3473 mac_init_pipe_label(&intlabel); 3474 error = mac_internalize_pipe_label(&intlabel, buffer); 3475 if (error == 0) { 3476 pipe = fp->f_data; 3477 PIPE_LOCK(pipe); 3478 error = mac_pipe_label_set(td->td_ucred, pipe, 3479 &intlabel); 3480 PIPE_UNLOCK(pipe); 3481 } 3482 3483 mac_destroy_pipe_label(&intlabel); 3484 break; 3485 3486 default: 3487 error = EINVAL; 3488 } 3489 3490 fdrop(fp, td); 3491 out: 3492 mtx_unlock(&Giant); /* VFS */ 3493 3494 free(buffer, M_MACTEMP); 3495 3496 return (error); 3497 } 3498 3499 /* 3500 * MPSAFE 3501 */ 3502 int 3503 __mac_set_file(struct thread *td, struct __mac_set_file_args *uap) 3504 { 3505 struct label intlabel; 3506 struct nameidata nd; 3507 struct mount *mp; 3508 struct mac mac; 3509 char *buffer; 3510 int error; 3511 3512 error = copyin(uap->mac_p, &mac, sizeof(mac)); 3513 if (error) 3514 return (error); 3515 3516 error = mac_check_structmac_consistent(&mac); 3517 if (error) 3518 return (error); 3519 3520 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 3521 error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL); 3522 if (error) { 3523 free(buffer, M_MACTEMP); 3524 return (error); 3525 } 3526 3527 mac_init_vnode_label(&intlabel); 3528 error = mac_internalize_vnode_label(&intlabel, buffer); 3529 free(buffer, M_MACTEMP); 3530 if (error) { 3531 mac_destroy_vnode_label(&intlabel); 3532 return (error); 3533 } 3534 3535 mtx_lock(&Giant); /* VFS */ 3536 3537 NDINIT(&nd, LOOKUP, LOCKLEAF | FOLLOW, UIO_USERSPACE, uap->path_p, 3538 td); 3539 error = namei(&nd); 3540 if (error == 0) { 3541 error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH); 3542 if (error == 0) 3543 error = vn_setlabel(nd.ni_vp, &intlabel, 3544 td->td_ucred); 3545 vn_finished_write(mp); 3546 } 3547 3548 NDFREE(&nd, 0); 3549 mtx_unlock(&Giant); /* VFS */ 3550 mac_destroy_vnode_label(&intlabel); 3551 3552 return (error); 3553 } 3554 3555 /* 3556 * MPSAFE 3557 */ 3558 int 3559 __mac_set_link(struct thread *td, struct __mac_set_link_args *uap) 3560 { 3561 struct label intlabel; 3562 struct nameidata nd; 3563 struct mount *mp; 3564 struct mac mac; 3565 char *buffer; 3566 int error; 3567 3568 error = copyin(uap->mac_p, &mac, sizeof(mac)); 3569 if (error) 3570 return (error); 3571 3572 error = mac_check_structmac_consistent(&mac); 3573 if (error) 3574 return (error); 3575 3576 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 3577 error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL); 3578 if (error) { 3579 free(buffer, M_MACTEMP); 3580 return (error); 3581 } 3582 3583 mac_init_vnode_label(&intlabel); 3584 error = mac_internalize_vnode_label(&intlabel, buffer); 3585 free(buffer, M_MACTEMP); 3586 if (error) { 3587 mac_destroy_vnode_label(&intlabel); 3588 return (error); 3589 } 3590 3591 mtx_lock(&Giant); /* VFS */ 3592 3593 NDINIT(&nd, LOOKUP, LOCKLEAF | NOFOLLOW, UIO_USERSPACE, uap->path_p, 3594 td); 3595 error = namei(&nd); 3596 if (error == 0) { 3597 error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH); 3598 if (error == 0) 3599 error = vn_setlabel(nd.ni_vp, &intlabel, 3600 td->td_ucred); 3601 vn_finished_write(mp); 3602 } 3603 3604 NDFREE(&nd, 0); 3605 mtx_unlock(&Giant); /* VFS */ 3606 mac_destroy_vnode_label(&intlabel); 3607 3608 return (error); 3609 } 3610 3611 /* 3612 * MPSAFE 3613 */ 3614 int 3615 mac_syscall(struct thread *td, struct mac_syscall_args *uap) 3616 { 3617 struct mac_policy_conf *mpc; 3618 char target[MAC_MAX_POLICY_NAME]; 3619 int error; 3620 3621 error = copyinstr(uap->policy, target, sizeof(target), NULL); 3622 if (error) 3623 return (error); 3624 3625 error = ENOSYS; 3626 MAC_POLICY_LIST_BUSY(); 3627 LIST_FOREACH(mpc, &mac_policy_list, mpc_list) { 3628 if (strcmp(mpc->mpc_name, target) == 0 && 3629 mpc->mpc_ops->mpo_syscall != NULL) { 3630 error = mpc->mpc_ops->mpo_syscall(td, 3631 uap->call, uap->arg); 3632 goto out; 3633 } 3634 } 3635 3636 out: 3637 MAC_POLICY_LIST_UNBUSY(); 3638 return (error); 3639 } 3640 3641 SYSINIT(mac, SI_SUB_MAC, SI_ORDER_FIRST, mac_init, NULL); 3642 SYSINIT(mac_late, SI_SUB_MAC_LATE, SI_ORDER_FIRST, mac_late_init, NULL); 3643 3644 #else /* !MAC */ 3645 3646 int 3647 __mac_get_pid(struct thread *td, struct __mac_get_pid_args *uap) 3648 { 3649 3650 return (ENOSYS); 3651 } 3652 3653 int 3654 __mac_get_proc(struct thread *td, struct __mac_get_proc_args *uap) 3655 { 3656 3657 return (ENOSYS); 3658 } 3659 3660 int 3661 __mac_set_proc(struct thread *td, struct __mac_set_proc_args *uap) 3662 { 3663 3664 return (ENOSYS); 3665 } 3666 3667 int 3668 __mac_get_fd(struct thread *td, struct __mac_get_fd_args *uap) 3669 { 3670 3671 return (ENOSYS); 3672 } 3673 3674 int 3675 __mac_get_file(struct thread *td, struct __mac_get_file_args *uap) 3676 { 3677 3678 return (ENOSYS); 3679 } 3680 3681 int 3682 __mac_get_link(struct thread *td, struct __mac_get_link_args *uap) 3683 { 3684 3685 return (ENOSYS); 3686 } 3687 3688 int 3689 __mac_set_fd(struct thread *td, struct __mac_set_fd_args *uap) 3690 { 3691 3692 return (ENOSYS); 3693 } 3694 3695 int 3696 __mac_set_file(struct thread *td, struct __mac_set_file_args *uap) 3697 { 3698 3699 return (ENOSYS); 3700 } 3701 3702 int 3703 __mac_set_link(struct thread *td, struct __mac_set_link_args *uap) 3704 { 3705 3706 return (ENOSYS); 3707 } 3708 3709 int 3710 mac_syscall(struct thread *td, struct mac_syscall_args *uap) 3711 { 3712 3713 return (ENOSYS); 3714 } 3715 3716 #endif 3717