1a9643ea8Slogwang /*- 2*22ce4affSfengbojiang * Copyright (c) 1999-2002, 2006, 2009, 2019 Robert N. M. Watson 3a9643ea8Slogwang * Copyright (c) 2001 Ilmar S. Habibulin 4a9643ea8Slogwang * Copyright (c) 2001-2004 Networks Associates Technology, Inc. 5a9643ea8Slogwang * Copyright (c) 2006 nCircle Network Security, Inc. 6a9643ea8Slogwang * Copyright (c) 2006 SPARTA, Inc. 7a9643ea8Slogwang * Copyright (c) 2009 Apple, Inc. 8a9643ea8Slogwang * All rights reserved. 9a9643ea8Slogwang * 10a9643ea8Slogwang * This software was developed by Robert Watson and Ilmar Habibulin for the 11a9643ea8Slogwang * TrustedBSD Project. 12a9643ea8Slogwang * 13a9643ea8Slogwang * This software was developed for the FreeBSD Project in part by Network 14a9643ea8Slogwang * Associates Laboratories, the Security Research Division of Network 15a9643ea8Slogwang * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), 16a9643ea8Slogwang * as part of the DARPA CHATS research program. 17a9643ea8Slogwang * 18a9643ea8Slogwang * This software was developed by Robert N. M. Watson for the TrustedBSD 19a9643ea8Slogwang * Project under contract to nCircle Network Security, Inc. 20a9643ea8Slogwang * 21a9643ea8Slogwang * This software was enhanced by SPARTA ISSO under SPAWAR contract 22a9643ea8Slogwang * N66001-04-C-6019 ("SEFOS"). 23a9643ea8Slogwang * 24a9643ea8Slogwang * This software was developed at the University of Cambridge Computer 25a9643ea8Slogwang * Laboratory with support from a grant from Google, Inc. 26a9643ea8Slogwang * 27a9643ea8Slogwang * Redistribution and use in source and binary forms, with or without 28a9643ea8Slogwang * modification, are permitted provided that the following conditions 29a9643ea8Slogwang * are met: 30a9643ea8Slogwang * 1. Redistributions of source code must retain the above copyright 31a9643ea8Slogwang * notice, this list of conditions and the following disclaimer. 32a9643ea8Slogwang * 2. Redistributions in binary form must reproduce the above copyright 33a9643ea8Slogwang * notice, this list of conditions and the following disclaimer in the 34a9643ea8Slogwang * documentation and/or other materials provided with the distribution. 35a9643ea8Slogwang * 36a9643ea8Slogwang * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 37a9643ea8Slogwang * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 38a9643ea8Slogwang * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 39a9643ea8Slogwang * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 40a9643ea8Slogwang * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 41a9643ea8Slogwang * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 42a9643ea8Slogwang * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 43a9643ea8Slogwang * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 44a9643ea8Slogwang * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 45a9643ea8Slogwang * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 46a9643ea8Slogwang * SUCH DAMAGE. 47a9643ea8Slogwang * 48a9643ea8Slogwang * $FreeBSD$ 49a9643ea8Slogwang */ 50a9643ea8Slogwang 51a9643ea8Slogwang #ifndef _SECURITY_MAC_MAC_INTERNAL_H_ 52a9643ea8Slogwang #define _SECURITY_MAC_MAC_INTERNAL_H_ 53a9643ea8Slogwang 54a9643ea8Slogwang #ifndef _KERNEL 55a9643ea8Slogwang #error "no user-serviceable parts inside" 56a9643ea8Slogwang #endif 57a9643ea8Slogwang 58a9643ea8Slogwang #include <sys/lock.h> 59a9643ea8Slogwang #include <sys/rmlock.h> 60a9643ea8Slogwang 61a9643ea8Slogwang /* 62a9643ea8Slogwang * MAC Framework sysctl namespace. 63a9643ea8Slogwang */ 64a9643ea8Slogwang #ifdef SYSCTL_DECL 65a9643ea8Slogwang SYSCTL_DECL(_security_mac); 66a9643ea8Slogwang #endif /* SYSCTL_DECL */ 67a9643ea8Slogwang 68a9643ea8Slogwang /* 69a9643ea8Slogwang * MAC Framework SDT DTrace probe namespace, macros for declaring entry 70a9643ea8Slogwang * point probes, macros for invoking them. 71a9643ea8Slogwang */ 72a9643ea8Slogwang #ifdef SDT_PROVIDER_DECLARE 73a9643ea8Slogwang SDT_PROVIDER_DECLARE(mac); /* MAC Framework-level events. */ 74a9643ea8Slogwang SDT_PROVIDER_DECLARE(mac_framework); /* Entry points to MAC. */ 75a9643ea8Slogwang 76a9643ea8Slogwang #define MAC_CHECK_PROBE_DEFINE4(name, arg0, arg1, arg2, arg3) \ 77a9643ea8Slogwang SDT_PROBE_DEFINE5(mac_framework, , name, mac__check__err, \ 78a9643ea8Slogwang "int", arg0, arg1, arg2, arg3); \ 79a9643ea8Slogwang SDT_PROBE_DEFINE5(mac_framework, , name, mac__check__ok, \ 80a9643ea8Slogwang "int", arg0, arg1, arg2, arg3); 81a9643ea8Slogwang 82a9643ea8Slogwang #define MAC_CHECK_PROBE_DEFINE3(name, arg0, arg1, arg2) \ 83a9643ea8Slogwang SDT_PROBE_DEFINE4(mac_framework, , name, mac__check__err, \ 84a9643ea8Slogwang "int", arg0, arg1, arg2); \ 85a9643ea8Slogwang SDT_PROBE_DEFINE4(mac_framework, , name, mac__check__ok, \ 86a9643ea8Slogwang "int", arg0, arg1, arg2); 87a9643ea8Slogwang 88a9643ea8Slogwang #define MAC_CHECK_PROBE_DEFINE2(name, arg0, arg1) \ 89a9643ea8Slogwang SDT_PROBE_DEFINE3(mac_framework, , name, mac__check__err, \ 90a9643ea8Slogwang "int", arg0, arg1); \ 91a9643ea8Slogwang SDT_PROBE_DEFINE3(mac_framework, , name, mac__check__ok, \ 92a9643ea8Slogwang "int", arg0, arg1); 93a9643ea8Slogwang 94a9643ea8Slogwang #define MAC_CHECK_PROBE_DEFINE1(name, arg0) \ 95a9643ea8Slogwang SDT_PROBE_DEFINE2(mac_framework, , name, mac__check__err, \ 96a9643ea8Slogwang "int", arg0); \ 97a9643ea8Slogwang SDT_PROBE_DEFINE2(mac_framework, , name, mac__check__ok, \ 98a9643ea8Slogwang "int", arg0); 99a9643ea8Slogwang 100a9643ea8Slogwang #define MAC_CHECK_PROBE4(name, error, arg0, arg1, arg2, arg3) do { \ 101*22ce4affSfengbojiang if (SDT_PROBES_ENABLED()) { \ 102a9643ea8Slogwang if (error) { \ 103a9643ea8Slogwang SDT_PROBE5(mac_framework, , name, mac__check__err,\ 104a9643ea8Slogwang error, arg0, arg1, arg2, arg3); \ 105a9643ea8Slogwang } else { \ 106a9643ea8Slogwang SDT_PROBE5(mac_framework, , name, mac__check__ok,\ 107a9643ea8Slogwang 0, arg0, arg1, arg2, arg3); \ 108a9643ea8Slogwang } \ 109*22ce4affSfengbojiang } \ 110a9643ea8Slogwang } while (0) 111a9643ea8Slogwang 112a9643ea8Slogwang #define MAC_CHECK_PROBE3(name, error, arg0, arg1, arg2) \ 113a9643ea8Slogwang MAC_CHECK_PROBE4(name, error, arg0, arg1, arg2, 0) 114a9643ea8Slogwang #define MAC_CHECK_PROBE2(name, error, arg0, arg1) \ 115a9643ea8Slogwang MAC_CHECK_PROBE3(name, error, arg0, arg1, 0) 116a9643ea8Slogwang #define MAC_CHECK_PROBE1(name, error, arg0) \ 117a9643ea8Slogwang MAC_CHECK_PROBE2(name, error, arg0, 0) 118a9643ea8Slogwang #endif 119a9643ea8Slogwang 120a9643ea8Slogwang #define MAC_GRANT_PROBE_DEFINE2(name, arg0, arg1) \ 121a9643ea8Slogwang SDT_PROBE_DEFINE3(mac_framework, , name, mac__grant__err, \ 122a9643ea8Slogwang "int", arg0, arg1); \ 123a9643ea8Slogwang SDT_PROBE_DEFINE3(mac_framework, , name, mac__grant__ok, \ 124a9643ea8Slogwang "int", arg0, arg1); 125a9643ea8Slogwang 126a9643ea8Slogwang #define MAC_GRANT_PROBE2(name, error, arg0, arg1) do { \ 127*22ce4affSfengbojiang if (SDT_PROBES_ENABLED()) { \ 128a9643ea8Slogwang if (error) { \ 129a9643ea8Slogwang SDT_PROBE3(mac_framework, , name, mac__grant__err,\ 130a9643ea8Slogwang error, arg0, arg1); \ 131a9643ea8Slogwang } else { \ 132a9643ea8Slogwang SDT_PROBE3(mac_framework, , name, mac__grant__ok,\ 133a9643ea8Slogwang error, arg0, arg1); \ 134a9643ea8Slogwang } \ 135*22ce4affSfengbojiang } \ 136a9643ea8Slogwang } while (0) 137a9643ea8Slogwang 138a9643ea8Slogwang /* 139a9643ea8Slogwang * MAC Framework global types and typedefs. 140a9643ea8Slogwang */ 141a9643ea8Slogwang LIST_HEAD(mac_policy_list_head, mac_policy_conf); 142a9643ea8Slogwang #ifdef MALLOC_DECLARE 143a9643ea8Slogwang MALLOC_DECLARE(M_MACTEMP); 144a9643ea8Slogwang #endif 145a9643ea8Slogwang 146a9643ea8Slogwang /* 147a9643ea8Slogwang * MAC labels -- in-kernel storage format. 148a9643ea8Slogwang * 149a9643ea8Slogwang * In general, struct label pointers are embedded in kernel data structures 150a9643ea8Slogwang * representing objects that may be labeled (and protected). Struct label is 151a9643ea8Slogwang * opaque to both kernel services that invoke the MAC Framework and MAC 152a9643ea8Slogwang * policy modules. In particular, we do not wish to encode the layout of the 153a9643ea8Slogwang * label structure into any ABIs. Historically, the slot array contained 154a9643ea8Slogwang * unions of {long, void} but now contains uintptr_t. 155a9643ea8Slogwang */ 156a9643ea8Slogwang #define MAC_MAX_SLOTS 4 157a9643ea8Slogwang #define MAC_FLAG_INITIALIZED 0x0000001 /* Is initialized for use. */ 158a9643ea8Slogwang struct label { 159a9643ea8Slogwang int l_flags; 160a9643ea8Slogwang intptr_t l_perpolicy[MAC_MAX_SLOTS]; 161a9643ea8Slogwang }; 162a9643ea8Slogwang 163a9643ea8Slogwang /* 164a9643ea8Slogwang * Flags for mac_labeled, a bitmask of object types need across the union of 165a9643ea8Slogwang * all policies currently registered with the MAC Framework, used to key 166a9643ea8Slogwang * whether or not labels are allocated and constructors for the type are 167a9643ea8Slogwang * invoked. 168a9643ea8Slogwang */ 169a9643ea8Slogwang #define MPC_OBJECT_CRED 0x0000000000000001 170a9643ea8Slogwang #define MPC_OBJECT_PROC 0x0000000000000002 171a9643ea8Slogwang #define MPC_OBJECT_VNODE 0x0000000000000004 172a9643ea8Slogwang #define MPC_OBJECT_INPCB 0x0000000000000008 173a9643ea8Slogwang #define MPC_OBJECT_SOCKET 0x0000000000000010 174a9643ea8Slogwang #define MPC_OBJECT_DEVFS 0x0000000000000020 175a9643ea8Slogwang #define MPC_OBJECT_MBUF 0x0000000000000040 176a9643ea8Slogwang #define MPC_OBJECT_IPQ 0x0000000000000080 177a9643ea8Slogwang #define MPC_OBJECT_IFNET 0x0000000000000100 178a9643ea8Slogwang #define MPC_OBJECT_BPFDESC 0x0000000000000200 179a9643ea8Slogwang #define MPC_OBJECT_PIPE 0x0000000000000400 180a9643ea8Slogwang #define MPC_OBJECT_MOUNT 0x0000000000000800 181a9643ea8Slogwang #define MPC_OBJECT_POSIXSEM 0x0000000000001000 182a9643ea8Slogwang #define MPC_OBJECT_POSIXSHM 0x0000000000002000 183a9643ea8Slogwang #define MPC_OBJECT_SYSVMSG 0x0000000000004000 184a9643ea8Slogwang #define MPC_OBJECT_SYSVMSQ 0x0000000000008000 185a9643ea8Slogwang #define MPC_OBJECT_SYSVSEM 0x0000000000010000 186a9643ea8Slogwang #define MPC_OBJECT_SYSVSHM 0x0000000000020000 187a9643ea8Slogwang #define MPC_OBJECT_SYNCACHE 0x0000000000040000 188a9643ea8Slogwang #define MPC_OBJECT_IP6Q 0x0000000000080000 189a9643ea8Slogwang 190a9643ea8Slogwang /* 191a9643ea8Slogwang * MAC Framework global variables. 192a9643ea8Slogwang */ 193a9643ea8Slogwang extern struct mac_policy_list_head mac_policy_list; 194a9643ea8Slogwang extern struct mac_policy_list_head mac_static_policy_list; 195a9643ea8Slogwang extern u_int mac_policy_count; 196a9643ea8Slogwang extern uint64_t mac_labeled; 197a9643ea8Slogwang extern struct mtx mac_ifnet_mtx; 198a9643ea8Slogwang 199a9643ea8Slogwang /* 200a9643ea8Slogwang * MAC Framework infrastructure functions. 201a9643ea8Slogwang */ 202a9643ea8Slogwang int mac_error_select(int error1, int error2); 203a9643ea8Slogwang 204a9643ea8Slogwang void mac_policy_slock_nosleep(struct rm_priotracker *tracker); 205a9643ea8Slogwang void mac_policy_slock_sleep(void); 206a9643ea8Slogwang void mac_policy_sunlock_nosleep(struct rm_priotracker *tracker); 207a9643ea8Slogwang void mac_policy_sunlock_sleep(void); 208a9643ea8Slogwang 209a9643ea8Slogwang struct label *mac_labelzone_alloc(int flags); 210a9643ea8Slogwang void mac_labelzone_free(struct label *label); 211a9643ea8Slogwang void mac_labelzone_init(void); 212a9643ea8Slogwang 213a9643ea8Slogwang void mac_init_label(struct label *label); 214a9643ea8Slogwang void mac_destroy_label(struct label *label); 215a9643ea8Slogwang int mac_check_structmac_consistent(struct mac *mac); 216a9643ea8Slogwang int mac_allocate_slot(void); 217a9643ea8Slogwang 218*22ce4affSfengbojiang /* 219*22ce4affSfengbojiang * Lock ifnets to protect labels only if ifnet labels are in use. 220*22ce4affSfengbojiang */ 221*22ce4affSfengbojiang #define MAC_IFNET_LOCK(ifp, locked) do { \ 222*22ce4affSfengbojiang if (mac_labeled & MPC_OBJECT_IFNET) { \ 223*22ce4affSfengbojiang mtx_lock(&mac_ifnet_mtx); \ 224*22ce4affSfengbojiang locked = 1; \ 225*22ce4affSfengbojiang } else { \ 226*22ce4affSfengbojiang locked = 0; \ 227*22ce4affSfengbojiang } \ 228*22ce4affSfengbojiang } while (0) 229*22ce4affSfengbojiang 230*22ce4affSfengbojiang #define MAC_IFNET_UNLOCK(ifp, locked) do { \ 231*22ce4affSfengbojiang if (locked) { \ 232*22ce4affSfengbojiang mtx_unlock(&mac_ifnet_mtx); \ 233*22ce4affSfengbojiang locked = 0; \ 234*22ce4affSfengbojiang } \ 235*22ce4affSfengbojiang } while (0) 236a9643ea8Slogwang 237a9643ea8Slogwang /* 238a9643ea8Slogwang * MAC Framework per-object type functions. It's not yet clear how the 239a9643ea8Slogwang * namespaces, etc, should work for these, so for now, sort by object type. 240a9643ea8Slogwang */ 241a9643ea8Slogwang struct label *mac_cred_label_alloc(void); 242a9643ea8Slogwang void mac_cred_label_free(struct label *label); 243a9643ea8Slogwang struct label *mac_pipe_label_alloc(void); 244a9643ea8Slogwang void mac_pipe_label_free(struct label *label); 245a9643ea8Slogwang struct label *mac_socket_label_alloc(int flag); 246a9643ea8Slogwang void mac_socket_label_free(struct label *label); 247a9643ea8Slogwang struct label *mac_vnode_label_alloc(void); 248a9643ea8Slogwang void mac_vnode_label_free(struct label *label); 249a9643ea8Slogwang 250a9643ea8Slogwang int mac_cred_check_relabel(struct ucred *cred, struct label *newlabel); 251a9643ea8Slogwang int mac_cred_externalize_label(struct label *label, char *elements, 252a9643ea8Slogwang char *outbuf, size_t outbuflen); 253a9643ea8Slogwang int mac_cred_internalize_label(struct label *label, char *string); 254a9643ea8Slogwang void mac_cred_relabel(struct ucred *cred, struct label *newlabel); 255a9643ea8Slogwang 256a9643ea8Slogwang struct label *mac_mbuf_to_label(struct mbuf *m); 257a9643ea8Slogwang 258a9643ea8Slogwang void mac_pipe_copy_label(struct label *src, struct label *dest); 259a9643ea8Slogwang int mac_pipe_externalize_label(struct label *label, char *elements, 260a9643ea8Slogwang char *outbuf, size_t outbuflen); 261a9643ea8Slogwang int mac_pipe_internalize_label(struct label *label, char *string); 262a9643ea8Slogwang 263a9643ea8Slogwang int mac_socket_label_set(struct ucred *cred, struct socket *so, 264a9643ea8Slogwang struct label *label); 265a9643ea8Slogwang void mac_socket_copy_label(struct label *src, struct label *dest); 266a9643ea8Slogwang int mac_socket_externalize_label(struct label *label, char *elements, 267a9643ea8Slogwang char *outbuf, size_t outbuflen); 268a9643ea8Slogwang int mac_socket_internalize_label(struct label *label, char *string); 269a9643ea8Slogwang 270a9643ea8Slogwang int mac_vnode_externalize_label(struct label *label, char *elements, 271a9643ea8Slogwang char *outbuf, size_t outbuflen); 272a9643ea8Slogwang int mac_vnode_internalize_label(struct label *label, char *string); 273a9643ea8Slogwang void mac_vnode_check_mmap_downgrade(struct ucred *cred, struct vnode *vp, 274a9643ea8Slogwang int *prot); 275a9643ea8Slogwang int vn_setlabel(struct vnode *vp, struct label *intlabel, 276a9643ea8Slogwang struct ucred *cred); 277a9643ea8Slogwang 278a9643ea8Slogwang /* 279a9643ea8Slogwang * MAC Framework composition macros invoke all registered MAC policies for a 280a9643ea8Slogwang * specific entry point. They come in two forms: one which permits policies 281a9643ea8Slogwang * to sleep/block, and another that does not. 282a9643ea8Slogwang * 283a9643ea8Slogwang * MAC_POLICY_CHECK performs the designated check by walking the policy 284a9643ea8Slogwang * module list and checking with each as to how it feels about the request. 285a9643ea8Slogwang * Note that it returns its value via 'error' in the scope of the caller. 286a9643ea8Slogwang */ 287a9643ea8Slogwang #define MAC_POLICY_CHECK(check, args...) do { \ 288a9643ea8Slogwang struct mac_policy_conf *mpc; \ 289a9643ea8Slogwang \ 290a9643ea8Slogwang error = 0; \ 291a9643ea8Slogwang LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) { \ 292a9643ea8Slogwang if (mpc->mpc_ops->mpo_ ## check != NULL) \ 293a9643ea8Slogwang error = mac_error_select( \ 294a9643ea8Slogwang mpc->mpc_ops->mpo_ ## check (args), \ 295a9643ea8Slogwang error); \ 296a9643ea8Slogwang } \ 297a9643ea8Slogwang if (!LIST_EMPTY(&mac_policy_list)) { \ 298a9643ea8Slogwang mac_policy_slock_sleep(); \ 299a9643ea8Slogwang LIST_FOREACH(mpc, &mac_policy_list, mpc_list) { \ 300a9643ea8Slogwang if (mpc->mpc_ops->mpo_ ## check != NULL) \ 301a9643ea8Slogwang error = mac_error_select( \ 302a9643ea8Slogwang mpc->mpc_ops->mpo_ ## check (args), \ 303a9643ea8Slogwang error); \ 304a9643ea8Slogwang } \ 305a9643ea8Slogwang mac_policy_sunlock_sleep(); \ 306a9643ea8Slogwang } \ 307a9643ea8Slogwang } while (0) 308a9643ea8Slogwang 309a9643ea8Slogwang #define MAC_POLICY_CHECK_NOSLEEP(check, args...) do { \ 310a9643ea8Slogwang struct mac_policy_conf *mpc; \ 311a9643ea8Slogwang \ 312a9643ea8Slogwang error = 0; \ 313a9643ea8Slogwang LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) { \ 314a9643ea8Slogwang if (mpc->mpc_ops->mpo_ ## check != NULL) \ 315a9643ea8Slogwang error = mac_error_select( \ 316a9643ea8Slogwang mpc->mpc_ops->mpo_ ## check (args), \ 317a9643ea8Slogwang error); \ 318a9643ea8Slogwang } \ 319a9643ea8Slogwang if (!LIST_EMPTY(&mac_policy_list)) { \ 320a9643ea8Slogwang struct rm_priotracker tracker; \ 321a9643ea8Slogwang \ 322a9643ea8Slogwang mac_policy_slock_nosleep(&tracker); \ 323a9643ea8Slogwang LIST_FOREACH(mpc, &mac_policy_list, mpc_list) { \ 324a9643ea8Slogwang if (mpc->mpc_ops->mpo_ ## check != NULL) \ 325a9643ea8Slogwang error = mac_error_select( \ 326a9643ea8Slogwang mpc->mpc_ops->mpo_ ## check (args), \ 327a9643ea8Slogwang error); \ 328a9643ea8Slogwang } \ 329a9643ea8Slogwang mac_policy_sunlock_nosleep(&tracker); \ 330a9643ea8Slogwang } \ 331a9643ea8Slogwang } while (0) 332a9643ea8Slogwang 333a9643ea8Slogwang /* 334a9643ea8Slogwang * MAC_POLICY_GRANT performs the designated check by walking the policy 335a9643ea8Slogwang * module list and checking with each as to how it feels about the request. 336a9643ea8Slogwang * Unlike MAC_POLICY_CHECK, it grants if any policies return '0', and 337a9643ea8Slogwang * otherwise returns EPERM. Note that it returns its value via 'error' in 338a9643ea8Slogwang * the scope of the caller. 339a9643ea8Slogwang */ 340a9643ea8Slogwang #define MAC_POLICY_GRANT_NOSLEEP(check, args...) do { \ 341a9643ea8Slogwang struct mac_policy_conf *mpc; \ 342a9643ea8Slogwang \ 343a9643ea8Slogwang error = EPERM; \ 344a9643ea8Slogwang LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) { \ 345a9643ea8Slogwang if (mpc->mpc_ops->mpo_ ## check != NULL) { \ 346a9643ea8Slogwang if (mpc->mpc_ops->mpo_ ## check(args) == 0) \ 347a9643ea8Slogwang error = 0; \ 348a9643ea8Slogwang } \ 349a9643ea8Slogwang } \ 350a9643ea8Slogwang if (!LIST_EMPTY(&mac_policy_list)) { \ 351a9643ea8Slogwang struct rm_priotracker tracker; \ 352a9643ea8Slogwang \ 353a9643ea8Slogwang mac_policy_slock_nosleep(&tracker); \ 354a9643ea8Slogwang LIST_FOREACH(mpc, &mac_policy_list, mpc_list) { \ 355a9643ea8Slogwang if (mpc->mpc_ops->mpo_ ## check != NULL) { \ 356a9643ea8Slogwang if (mpc->mpc_ops->mpo_ ## check (args) \ 357a9643ea8Slogwang == 0) \ 358a9643ea8Slogwang error = 0; \ 359a9643ea8Slogwang } \ 360a9643ea8Slogwang } \ 361a9643ea8Slogwang mac_policy_sunlock_nosleep(&tracker); \ 362a9643ea8Slogwang } \ 363a9643ea8Slogwang } while (0) 364a9643ea8Slogwang 365a9643ea8Slogwang /* 366a9643ea8Slogwang * MAC_POLICY_BOOLEAN performs the designated boolean composition by walking 367a9643ea8Slogwang * the module list, invoking each instance of the operation, and combining 368a9643ea8Slogwang * the results using the passed C operator. Note that it returns its value 369a9643ea8Slogwang * via 'result' in the scope of the caller, which should be initialized by 370a9643ea8Slogwang * the caller in a meaningful way to get a meaningful result. 371a9643ea8Slogwang */ 372a9643ea8Slogwang #define MAC_POLICY_BOOLEAN(operation, composition, args...) do { \ 373a9643ea8Slogwang struct mac_policy_conf *mpc; \ 374a9643ea8Slogwang \ 375a9643ea8Slogwang LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) { \ 376a9643ea8Slogwang if (mpc->mpc_ops->mpo_ ## operation != NULL) \ 377a9643ea8Slogwang result = result composition \ 378a9643ea8Slogwang mpc->mpc_ops->mpo_ ## operation (args); \ 379a9643ea8Slogwang } \ 380a9643ea8Slogwang if (!LIST_EMPTY(&mac_policy_list)) { \ 381a9643ea8Slogwang mac_policy_slock_sleep(); \ 382a9643ea8Slogwang LIST_FOREACH(mpc, &mac_policy_list, mpc_list) { \ 383a9643ea8Slogwang if (mpc->mpc_ops->mpo_ ## operation != NULL) \ 384a9643ea8Slogwang result = result composition \ 385a9643ea8Slogwang mpc->mpc_ops->mpo_ ## operation \ 386a9643ea8Slogwang (args); \ 387a9643ea8Slogwang } \ 388a9643ea8Slogwang mac_policy_sunlock_sleep(); \ 389a9643ea8Slogwang } \ 390a9643ea8Slogwang } while (0) 391a9643ea8Slogwang 392a9643ea8Slogwang #define MAC_POLICY_BOOLEAN_NOSLEEP(operation, composition, args...) do {\ 393a9643ea8Slogwang struct mac_policy_conf *mpc; \ 394a9643ea8Slogwang \ 395a9643ea8Slogwang LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) { \ 396a9643ea8Slogwang if (mpc->mpc_ops->mpo_ ## operation != NULL) \ 397a9643ea8Slogwang result = result composition \ 398a9643ea8Slogwang mpc->mpc_ops->mpo_ ## operation (args); \ 399a9643ea8Slogwang } \ 400a9643ea8Slogwang if (!LIST_EMPTY(&mac_policy_list)) { \ 401a9643ea8Slogwang struct rm_priotracker tracker; \ 402a9643ea8Slogwang \ 403a9643ea8Slogwang mac_policy_slock_nosleep(&tracker); \ 404a9643ea8Slogwang LIST_FOREACH(mpc, &mac_policy_list, mpc_list) { \ 405a9643ea8Slogwang if (mpc->mpc_ops->mpo_ ## operation != NULL) \ 406a9643ea8Slogwang result = result composition \ 407a9643ea8Slogwang mpc->mpc_ops->mpo_ ## operation \ 408a9643ea8Slogwang (args); \ 409a9643ea8Slogwang } \ 410a9643ea8Slogwang mac_policy_sunlock_nosleep(&tracker); \ 411a9643ea8Slogwang } \ 412a9643ea8Slogwang } while (0) 413a9643ea8Slogwang 414a9643ea8Slogwang /* 415a9643ea8Slogwang * MAC_POLICY_EXTERNALIZE queries each policy to see if it can generate an 416a9643ea8Slogwang * externalized version of a label element by name. Policies declare whether 417a9643ea8Slogwang * they have matched a particular element name, parsed from the string by 418a9643ea8Slogwang * MAC_POLICY_EXTERNALIZE, and an error is returned if any element is matched 419a9643ea8Slogwang * by no policy. 420a9643ea8Slogwang */ 421a9643ea8Slogwang #define MAC_POLICY_EXTERNALIZE(type, label, elementlist, outbuf, \ 422a9643ea8Slogwang outbuflen) do { \ 423a9643ea8Slogwang int claimed, first, ignorenotfound, savedlen; \ 424a9643ea8Slogwang char *element_name, *element_temp; \ 425a9643ea8Slogwang struct sbuf sb; \ 426a9643ea8Slogwang \ 427a9643ea8Slogwang error = 0; \ 428a9643ea8Slogwang first = 1; \ 429a9643ea8Slogwang sbuf_new(&sb, outbuf, outbuflen, SBUF_FIXEDLEN); \ 430a9643ea8Slogwang element_temp = elementlist; \ 431a9643ea8Slogwang while ((element_name = strsep(&element_temp, ",")) != NULL) { \ 432a9643ea8Slogwang if (element_name[0] == '?') { \ 433a9643ea8Slogwang element_name++; \ 434a9643ea8Slogwang ignorenotfound = 1; \ 435a9643ea8Slogwang } else \ 436a9643ea8Slogwang ignorenotfound = 0; \ 437a9643ea8Slogwang savedlen = sbuf_len(&sb); \ 438a9643ea8Slogwang if (first) \ 439a9643ea8Slogwang error = sbuf_printf(&sb, "%s/", element_name); \ 440a9643ea8Slogwang else \ 441a9643ea8Slogwang error = sbuf_printf(&sb, ",%s/", element_name); \ 442a9643ea8Slogwang if (error == -1) { \ 443a9643ea8Slogwang error = EINVAL; /* XXX: E2BIG? */ \ 444a9643ea8Slogwang break; \ 445a9643ea8Slogwang } \ 446a9643ea8Slogwang claimed = 0; \ 447a9643ea8Slogwang MAC_POLICY_CHECK(type ## _externalize_label, label, \ 448a9643ea8Slogwang element_name, &sb, &claimed); \ 449a9643ea8Slogwang if (error) \ 450a9643ea8Slogwang break; \ 451a9643ea8Slogwang if (claimed == 0 && ignorenotfound) { \ 452a9643ea8Slogwang /* Revert last label name. */ \ 453a9643ea8Slogwang sbuf_setpos(&sb, savedlen); \ 454a9643ea8Slogwang } else if (claimed != 1) { \ 455a9643ea8Slogwang error = EINVAL; /* XXX: ENOLABEL? */ \ 456a9643ea8Slogwang break; \ 457a9643ea8Slogwang } else { \ 458a9643ea8Slogwang first = 0; \ 459a9643ea8Slogwang } \ 460a9643ea8Slogwang } \ 461a9643ea8Slogwang sbuf_finish(&sb); \ 462a9643ea8Slogwang } while (0) 463a9643ea8Slogwang 464a9643ea8Slogwang /* 465a9643ea8Slogwang * MAC_POLICY_INTERNALIZE presents parsed element names and data to each 466a9643ea8Slogwang * policy to see if any is willing to claim it and internalize the label 467a9643ea8Slogwang * data. If no policies match, an error is returned. 468a9643ea8Slogwang */ 469a9643ea8Slogwang #define MAC_POLICY_INTERNALIZE(type, label, instring) do { \ 470a9643ea8Slogwang char *element, *element_name, *element_data; \ 471a9643ea8Slogwang int claimed; \ 472a9643ea8Slogwang \ 473a9643ea8Slogwang error = 0; \ 474a9643ea8Slogwang element = instring; \ 475a9643ea8Slogwang while ((element_name = strsep(&element, ",")) != NULL) { \ 476a9643ea8Slogwang element_data = element_name; \ 477a9643ea8Slogwang element_name = strsep(&element_data, "/"); \ 478a9643ea8Slogwang if (element_data == NULL) { \ 479a9643ea8Slogwang error = EINVAL; \ 480a9643ea8Slogwang break; \ 481a9643ea8Slogwang } \ 482a9643ea8Slogwang claimed = 0; \ 483a9643ea8Slogwang MAC_POLICY_CHECK(type ## _internalize_label, label, \ 484a9643ea8Slogwang element_name, element_data, &claimed); \ 485a9643ea8Slogwang if (error) \ 486a9643ea8Slogwang break; \ 487a9643ea8Slogwang if (claimed != 1) { \ 488a9643ea8Slogwang /* XXXMAC: Another error here? */ \ 489a9643ea8Slogwang error = EINVAL; \ 490a9643ea8Slogwang break; \ 491a9643ea8Slogwang } \ 492a9643ea8Slogwang } \ 493a9643ea8Slogwang } while (0) 494a9643ea8Slogwang 495a9643ea8Slogwang /* 496a9643ea8Slogwang * MAC_POLICY_PERFORM performs the designated operation by walking the policy 497a9643ea8Slogwang * module list and invoking that operation for each policy. 498a9643ea8Slogwang */ 499a9643ea8Slogwang #define MAC_POLICY_PERFORM(operation, args...) do { \ 500a9643ea8Slogwang struct mac_policy_conf *mpc; \ 501a9643ea8Slogwang \ 502a9643ea8Slogwang LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) { \ 503a9643ea8Slogwang if (mpc->mpc_ops->mpo_ ## operation != NULL) \ 504a9643ea8Slogwang mpc->mpc_ops->mpo_ ## operation (args); \ 505a9643ea8Slogwang } \ 506a9643ea8Slogwang if (!LIST_EMPTY(&mac_policy_list)) { \ 507a9643ea8Slogwang mac_policy_slock_sleep(); \ 508a9643ea8Slogwang LIST_FOREACH(mpc, &mac_policy_list, mpc_list) { \ 509a9643ea8Slogwang if (mpc->mpc_ops->mpo_ ## operation != NULL) \ 510a9643ea8Slogwang mpc->mpc_ops->mpo_ ## operation (args); \ 511a9643ea8Slogwang } \ 512a9643ea8Slogwang mac_policy_sunlock_sleep(); \ 513a9643ea8Slogwang } \ 514a9643ea8Slogwang } while (0) 515a9643ea8Slogwang 516a9643ea8Slogwang #define MAC_POLICY_PERFORM_NOSLEEP(operation, args...) do { \ 517a9643ea8Slogwang struct mac_policy_conf *mpc; \ 518a9643ea8Slogwang \ 519a9643ea8Slogwang LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) { \ 520a9643ea8Slogwang if (mpc->mpc_ops->mpo_ ## operation != NULL) \ 521a9643ea8Slogwang mpc->mpc_ops->mpo_ ## operation (args); \ 522a9643ea8Slogwang } \ 523a9643ea8Slogwang if (!LIST_EMPTY(&mac_policy_list)) { \ 524a9643ea8Slogwang struct rm_priotracker tracker; \ 525a9643ea8Slogwang \ 526a9643ea8Slogwang mac_policy_slock_nosleep(&tracker); \ 527a9643ea8Slogwang LIST_FOREACH(mpc, &mac_policy_list, mpc_list) { \ 528a9643ea8Slogwang if (mpc->mpc_ops->mpo_ ## operation != NULL) \ 529a9643ea8Slogwang mpc->mpc_ops->mpo_ ## operation (args); \ 530a9643ea8Slogwang } \ 531a9643ea8Slogwang mac_policy_sunlock_nosleep(&tracker); \ 532a9643ea8Slogwang } \ 533a9643ea8Slogwang } while (0) 534a9643ea8Slogwang 535a9643ea8Slogwang #endif /* !_SECURITY_MAC_MAC_INTERNAL_H_ */ 536