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