1 /*- 2 * Copyright (c) 1999-2002, 2006 Robert N. M. Watson 3 * Copyright (c) 2001 Ilmar S. Habibulin 4 * Copyright (c) 2001-2004 Networks Associates Technology, Inc. 5 * Copyright (c) 2006 nCircle Network Security, Inc. 6 * Copyright (c) 2006 SPARTA, Inc. 7 * Copyright (c) 2009 Apple, Inc. 8 * All rights reserved. 9 * 10 * This software was developed by Robert Watson and Ilmar Habibulin for the 11 * TrustedBSD Project. 12 * 13 * This software was developed for the FreeBSD Project in part by Network 14 * Associates Laboratories, the Security Research Division of Network 15 * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), 16 * as part of the DARPA CHATS research program. 17 * 18 * This software was developed by Robert N. M. Watson for the TrustedBSD 19 * Project under contract to nCircle Network Security, Inc. 20 * 21 * This software was enhanced by SPARTA ISSO under SPAWAR contract 22 * N66001-04-C-6019 ("SEFOS"). 23 * 24 * Redistribution and use in source and binary forms, with or without 25 * modification, are permitted provided that the following conditions 26 * are met: 27 * 1. Redistributions of source code must retain the above copyright 28 * notice, this list of conditions and the following disclaimer. 29 * 2. Redistributions in binary form must reproduce the above copyright 30 * notice, this list of conditions and the following disclaimer in the 31 * documentation and/or other materials provided with the distribution. 32 * 33 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 34 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 35 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 36 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 37 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 38 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 39 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 40 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 41 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 42 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 43 * SUCH DAMAGE. 44 * 45 * $FreeBSD$ 46 */ 47 48 #ifndef _SECURITY_MAC_MAC_INTERNAL_H_ 49 #define _SECURITY_MAC_MAC_INTERNAL_H_ 50 51 #ifndef _KERNEL 52 #error "no user-serviceable parts inside" 53 #endif 54 55 /* 56 * MAC Framework sysctl namespace. 57 */ 58 #ifdef SYSCTL_DECL 59 SYSCTL_DECL(_security_mac); 60 #endif /* SYSCTL_DECL */ 61 62 /* 63 * MAC Framework global types and typedefs. 64 */ 65 LIST_HEAD(mac_policy_list_head, mac_policy_conf); 66 #ifdef MALLOC_DECLARE 67 MALLOC_DECLARE(M_MACTEMP); 68 #endif 69 70 /* 71 * MAC labels -- in-kernel storage format. 72 * 73 * In general, struct label pointers are embedded in kernel data structures 74 * representing objects that may be labeled (and protected). Struct label is 75 * opaque to both kernel services that invoke the MAC Framework and MAC 76 * policy modules. In particular, we do not wish to encode the layout of the 77 * label structure into any ABIs. Historically, the slot array contained 78 * unions of {long, void} but now contains uintptr_t. 79 */ 80 #define MAC_MAX_SLOTS 4 81 #define MAC_FLAG_INITIALIZED 0x0000001 /* Is initialized for use. */ 82 struct label { 83 int l_flags; 84 intptr_t l_perpolicy[MAC_MAX_SLOTS]; 85 }; 86 87 88 /* 89 * Flags for mac_labeled, a bitmask of object types need across the union of 90 * all policies currently registered with the MAC Framework, used to key 91 * whether or not labels are allocated and constructors for the type are 92 * invoked. 93 */ 94 #define MPC_OBJECT_CRED 0x0000000000000001 95 #define MPC_OBJECT_PROC 0x0000000000000002 96 #define MPC_OBJECT_VNODE 0x0000000000000004 97 #define MPC_OBJECT_INPCB 0x0000000000000008 98 #define MPC_OBJECT_SOCKET 0x0000000000000010 99 #define MPC_OBJECT_DEVFS 0x0000000000000020 100 #define MPC_OBJECT_MBUF 0x0000000000000040 101 #define MPC_OBJECT_IPQ 0x0000000000000080 102 #define MPC_OBJECT_IFNET 0x0000000000000100 103 #define MPC_OBJECT_BPFDESC 0x0000000000000200 104 #define MPC_OBJECT_PIPE 0x0000000000000400 105 #define MPC_OBJECT_MOUNT 0x0000000000000800 106 #define MPC_OBJECT_POSIXSEM 0x0000000000001000 107 #define MPC_OBJECT_POSIXSHM 0x0000000000002000 108 #define MPC_OBJECT_SYSVMSG 0x0000000000004000 109 #define MPC_OBJECT_SYSVMSQ 0x0000000000008000 110 #define MPC_OBJECT_SYSVSEM 0x0000000000010000 111 #define MPC_OBJECT_SYSVSHM 0x0000000000020000 112 #define MPC_OBJECT_SYNCACHE 0x0000000000040000 113 #define MPC_OBJECT_IP6Q 0x0000000000080000 114 115 /* 116 * MAC Framework global variables. 117 */ 118 extern struct mac_policy_list_head mac_policy_list; 119 extern struct mac_policy_list_head mac_static_policy_list; 120 extern uint64_t mac_labeled; 121 extern struct mtx mac_ifnet_mtx; 122 123 /* 124 * MAC Framework infrastructure functions. 125 */ 126 int mac_error_select(int error1, int error2); 127 128 void mac_policy_grab_exclusive(void); 129 void mac_policy_assert_exclusive(void); 130 void mac_policy_release_exclusive(void); 131 void mac_policy_list_busy(void); 132 int mac_policy_list_conditional_busy(void); 133 void mac_policy_list_unbusy(void); 134 135 struct label *mac_labelzone_alloc(int flags); 136 void mac_labelzone_free(struct label *label); 137 void mac_labelzone_init(void); 138 139 void mac_init_label(struct label *label); 140 void mac_destroy_label(struct label *label); 141 int mac_check_structmac_consistent(struct mac *mac); 142 int mac_allocate_slot(void); 143 144 #define MAC_IFNET_LOCK(ifp) mtx_lock(&mac_ifnet_mtx) 145 #define MAC_IFNET_UNLOCK(ifp) mtx_unlock(&mac_ifnet_mtx) 146 147 /* 148 * MAC Framework per-object type functions. It's not yet clear how the 149 * namespaces, etc, should work for these, so for now, sort by object type. 150 */ 151 struct label *mac_cred_label_alloc(void); 152 void mac_cred_label_free(struct label *label); 153 struct label *mac_pipe_label_alloc(void); 154 void mac_pipe_label_free(struct label *label); 155 struct label *mac_socket_label_alloc(int flag); 156 void mac_socket_label_free(struct label *label); 157 struct label *mac_vnode_label_alloc(void); 158 void mac_vnode_label_free(struct label *label); 159 160 int mac_cred_check_relabel(struct ucred *cred, struct label *newlabel); 161 int mac_cred_externalize_label(struct label *label, char *elements, 162 char *outbuf, size_t outbuflen); 163 int mac_cred_internalize_label(struct label *label, char *string); 164 void mac_cred_relabel(struct ucred *cred, struct label *newlabel); 165 166 struct label *mac_mbuf_to_label(struct mbuf *m); 167 168 void mac_pipe_copy_label(struct label *src, struct label *dest); 169 int mac_pipe_externalize_label(struct label *label, char *elements, 170 char *outbuf, size_t outbuflen); 171 int mac_pipe_internalize_label(struct label *label, char *string); 172 173 int mac_socket_label_set(struct ucred *cred, struct socket *so, 174 struct label *label); 175 void mac_socket_copy_label(struct label *src, struct label *dest); 176 int mac_socket_externalize_label(struct label *label, char *elements, 177 char *outbuf, size_t outbuflen); 178 int mac_socket_internalize_label(struct label *label, char *string); 179 180 int mac_vnode_externalize_label(struct label *label, char *elements, 181 char *outbuf, size_t outbuflen); 182 int mac_vnode_internalize_label(struct label *label, char *string); 183 void mac_vnode_check_mmap_downgrade(struct ucred *cred, struct vnode *vp, 184 int *prot); 185 int vn_setlabel(struct vnode *vp, struct label *intlabel, 186 struct ucred *cred); 187 188 /* 189 * MAC_CHECK performs the designated check by walking the policy module list 190 * and checking with each as to how it feels about the request. Note that it 191 * returns its value via 'error' in the scope of the caller. 192 */ 193 #define MAC_CHECK(check, args...) do { \ 194 struct mac_policy_conf *mpc; \ 195 int entrycount; \ 196 \ 197 error = 0; \ 198 LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) { \ 199 if (mpc->mpc_ops->mpo_ ## check != NULL) \ 200 error = mac_error_select( \ 201 mpc->mpc_ops->mpo_ ## check (args), \ 202 error); \ 203 } \ 204 if ((entrycount = mac_policy_list_conditional_busy()) != 0) { \ 205 LIST_FOREACH(mpc, &mac_policy_list, mpc_list) { \ 206 if (mpc->mpc_ops->mpo_ ## check != NULL) \ 207 error = mac_error_select( \ 208 mpc->mpc_ops->mpo_ ## check (args), \ 209 error); \ 210 } \ 211 mac_policy_list_unbusy(); \ 212 } \ 213 } while (0) 214 215 /* 216 * MAC_GRANT performs the designated check by walking the policy module list 217 * and checking with each as to how it feels about the request. Unlike 218 * MAC_CHECK, it grants if any policies return '0', and otherwise returns 219 * EPERM. Note that it returns its value via 'error' in the scope of the 220 * caller. 221 */ 222 #define MAC_GRANT(check, args...) do { \ 223 struct mac_policy_conf *mpc; \ 224 int entrycount; \ 225 \ 226 error = EPERM; \ 227 LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) { \ 228 if (mpc->mpc_ops->mpo_ ## check != NULL) { \ 229 if (mpc->mpc_ops->mpo_ ## check(args) == 0) \ 230 error = 0; \ 231 } \ 232 } \ 233 if ((entrycount = mac_policy_list_conditional_busy()) != 0) { \ 234 LIST_FOREACH(mpc, &mac_policy_list, mpc_list) { \ 235 if (mpc->mpc_ops->mpo_ ## check != NULL) { \ 236 if (mpc->mpc_ops->mpo_ ## check (args) \ 237 == 0) \ 238 error = 0; \ 239 } \ 240 } \ 241 mac_policy_list_unbusy(); \ 242 } \ 243 } while (0) 244 245 /* 246 * MAC_BOOLEAN performs the designated boolean composition by walking the 247 * module list, invoking each instance of the operation, and combining the 248 * results using the passed C operator. Note that it returns its value via 249 * 'result' in the scope of the caller, which should be initialized by the 250 * caller in a meaningful way to get a meaningful result. 251 */ 252 #define MAC_BOOLEAN(operation, composition, args...) do { \ 253 struct mac_policy_conf *mpc; \ 254 int entrycount; \ 255 \ 256 LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) { \ 257 if (mpc->mpc_ops->mpo_ ## operation != NULL) \ 258 result = result composition \ 259 mpc->mpc_ops->mpo_ ## operation (args); \ 260 } \ 261 if ((entrycount = mac_policy_list_conditional_busy()) != 0) { \ 262 LIST_FOREACH(mpc, &mac_policy_list, mpc_list) { \ 263 if (mpc->mpc_ops->mpo_ ## operation != NULL) \ 264 result = result composition \ 265 mpc->mpc_ops->mpo_ ## operation \ 266 (args); \ 267 } \ 268 mac_policy_list_unbusy(); \ 269 } \ 270 } while (0) 271 272 /* 273 * MAC_EXTERNALIZE queries each policy to see if it can generate an 274 * externalized version of a label element by name. Policies declare whether 275 * they have matched a particular element name, parsed from the string by 276 * MAC_EXTERNALIZE, and an error is returned if any element is matched by no 277 * policy. 278 */ 279 #define MAC_EXTERNALIZE(type, label, elementlist, outbuf, \ 280 outbuflen) do { \ 281 int claimed, first, ignorenotfound, savedlen; \ 282 char *element_name, *element_temp; \ 283 struct sbuf sb; \ 284 \ 285 error = 0; \ 286 first = 1; \ 287 sbuf_new(&sb, outbuf, outbuflen, SBUF_FIXEDLEN); \ 288 element_temp = elementlist; \ 289 while ((element_name = strsep(&element_temp, ",")) != NULL) { \ 290 if (element_name[0] == '?') { \ 291 element_name++; \ 292 ignorenotfound = 1; \ 293 } else \ 294 ignorenotfound = 0; \ 295 savedlen = sbuf_len(&sb); \ 296 if (first) \ 297 error = sbuf_printf(&sb, "%s/", element_name); \ 298 else \ 299 error = sbuf_printf(&sb, ",%s/", element_name); \ 300 if (error == -1) { \ 301 error = EINVAL; /* XXX: E2BIG? */ \ 302 break; \ 303 } \ 304 claimed = 0; \ 305 MAC_CHECK(type ## _externalize_label, label, \ 306 element_name, &sb, &claimed); \ 307 if (error) \ 308 break; \ 309 if (claimed == 0 && ignorenotfound) { \ 310 /* Revert last label name. */ \ 311 sbuf_setpos(&sb, savedlen); \ 312 } else if (claimed != 1) { \ 313 error = EINVAL; /* XXX: ENOLABEL? */ \ 314 break; \ 315 } else { \ 316 first = 0; \ 317 } \ 318 } \ 319 sbuf_finish(&sb); \ 320 } while (0) 321 322 /* 323 * MAC_INTERNALIZE presents parsed element names and data to each policy to 324 * see if any is willing to claim it and internalize the label data. If no 325 * policies match, an error is returned. 326 */ 327 #define MAC_INTERNALIZE(type, label, instring) do { \ 328 char *element, *element_name, *element_data; \ 329 int claimed; \ 330 \ 331 error = 0; \ 332 element = instring; \ 333 while ((element_name = strsep(&element, ",")) != NULL) { \ 334 element_data = element_name; \ 335 element_name = strsep(&element_data, "/"); \ 336 if (element_data == NULL) { \ 337 error = EINVAL; \ 338 break; \ 339 } \ 340 claimed = 0; \ 341 MAC_CHECK(type ## _internalize_label, label, \ 342 element_name, element_data, &claimed); \ 343 if (error) \ 344 break; \ 345 if (claimed != 1) { \ 346 /* XXXMAC: Another error here? */ \ 347 error = EINVAL; \ 348 break; \ 349 } \ 350 } \ 351 } while (0) 352 353 /* 354 * MAC_PERFORM performs the designated operation by walking the policy module 355 * list and invoking that operation for each policy. 356 */ 357 #define MAC_PERFORM(operation, args...) do { \ 358 struct mac_policy_conf *mpc; \ 359 int entrycount; \ 360 \ 361 LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) { \ 362 if (mpc->mpc_ops->mpo_ ## operation != NULL) \ 363 mpc->mpc_ops->mpo_ ## operation (args); \ 364 } \ 365 if ((entrycount = mac_policy_list_conditional_busy()) != 0) { \ 366 LIST_FOREACH(mpc, &mac_policy_list, mpc_list) { \ 367 if (mpc->mpc_ops->mpo_ ## operation != NULL) \ 368 mpc->mpc_ops->mpo_ ## operation (args); \ 369 } \ 370 mac_policy_list_unbusy(); \ 371 } \ 372 } while (0) 373 374 #endif /* !_SECURITY_MAC_MAC_INTERNAL_H_ */ 375