xref: /freebsd/sys/security/mac/mac_internal.h (revision 39beb93c3f8bdbf72a61fda42300b5ebed7390c8)
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