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