mac_framework.c revision 260817
1109313Sobrien/*-
2110252Sobrien * Copyright (c) 1999-2002, 2006, 2009 Robert N. M. Watson
3109313Sobrien * Copyright (c) 2001 Ilmar S. Habibulin
4109313Sobrien * Copyright (c) 2001-2005 Networks Associates Technology, Inc.
5109313Sobrien * Copyright (c) 2005-2006 SPARTA, Inc.
6109313Sobrien * Copyright (c) 2008-2009 Apple Inc.
7109313Sobrien * All rights reserved.
8109313Sobrien *
9109313Sobrien * This software was developed by Robert Watson and Ilmar Habibulin for the
10109313Sobrien * TrustedBSD Project.
11109313Sobrien *
12109313Sobrien * This software was developed for the FreeBSD Project in part by Network
13109313Sobrien * Associates Laboratories, the Security Research Division of Network
14109313Sobrien * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"),
15109313Sobrien * as part of the DARPA CHATS research program.
16109313Sobrien *
17109313Sobrien * This software was enhanced by SPARTA ISSO under SPAWAR contract
18109313Sobrien * N66001-04-C-6019 ("SEFOS").
19109313Sobrien *
20109313Sobrien * This software was developed at the University of Cambridge Computer
21109313Sobrien * Laboratory with support from a grant from Google, Inc.
22109313Sobrien *
23109313Sobrien * Redistribution and use in source and binary forms, with or without
24109313Sobrien * modification, are permitted provided that the following conditions
25109313Sobrien * are met:
26109313Sobrien * 1. Redistributions of source code must retain the above copyright
27109313Sobrien *    notice, this list of conditions and the following disclaimer.
28109313Sobrien * 2. Redistributions in binary form must reproduce the above copyright
29109313Sobrien *    notice, this list of conditions and the following disclaimer in the
30109313Sobrien *    documentation and/or other materials provided with the distribution.
31109313Sobrien *
32109313Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
33109313Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
34118680Smarcel * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
35109313Sobrien * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
36109313Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37109313Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
38109313Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
39110257Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
40109313Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
41109313Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
42109313Sobrien * SUCH DAMAGE.
43109313Sobrien */
44109313Sobrien
45109313Sobrien/*-
46109313Sobrien * Framework for extensible kernel access control.  This file contains core
47109313Sobrien * kernel infrastructure for the TrustedBSD MAC Framework, including policy
48109313Sobrien * registration, versioning, locking, error composition operator, and system
49109313Sobrien * calls.
50109313Sobrien *
51109313Sobrien * The MAC Framework implements three programming interfaces:
52109313Sobrien *
53109313Sobrien * - The kernel MAC interface, defined in mac_framework.h, and invoked
54109313Sobrien *   throughout the kernel to request security decisions, notify of security
55109313Sobrien *   related events, etc.
56109313Sobrien *
57109313Sobrien * - The MAC policy module interface, defined in mac_policy.h, which is
58109313Sobrien *   implemented by MAC policy modules and invoked by the MAC Framework to
59109313Sobrien *   forward kernel security requests and notifications to policy modules.
60109313Sobrien *
61109313Sobrien * - The user MAC API, defined in mac.h, which allows user programs to query
62109313Sobrien *   and set label state on objects.
63109313Sobrien *
64109313Sobrien * The majority of the MAC Framework implementation may be found in
65109313Sobrien * src/sys/security/mac.  Sample policy modules may be found in
66109313Sobrien * src/sys/security/mac_*.
67109313Sobrien */
68109313Sobrien
69109313Sobrien#include "opt_kdtrace.h"
70109313Sobrien#include "opt_mac.h"
71109313Sobrien
72109313Sobrien#include <sys/cdefs.h>
73109313Sobrien__FBSDID("$FreeBSD: stable/10/sys/security/mac/mac_framework.c 260817 2014-01-17 10:58:59Z avg $");
74109313Sobrien
75109313Sobrien#include <sys/param.h>
76109313Sobrien#include <sys/systm.h>
77109313Sobrien#include <sys/condvar.h>
78109313Sobrien#include <sys/kernel.h>
79109313Sobrien#include <sys/lock.h>
80109313Sobrien#include <sys/mac.h>
81109313Sobrien#include <sys/module.h>
82109313Sobrien#include <sys/rmlock.h>
83109313Sobrien#include <sys/sdt.h>
84109313Sobrien#include <sys/sx.h>
85109313Sobrien#include <sys/sysctl.h>
86241737Sed
87109313Sobrien#include <security/mac/mac_framework.h>
88109313Sobrien#include <security/mac/mac_internal.h>
89109313Sobrien#include <security/mac/mac_policy.h>
90109313Sobrien
91109313Sobrien/*
92109313Sobrien * DTrace SDT providers for MAC.
93109313Sobrien */
94109313SobrienSDT_PROVIDER_DEFINE(mac);
95109313SobrienSDT_PROVIDER_DEFINE(mac_framework);
96109313Sobrien
97109313SobrienSDT_PROBE_DEFINE2(mac, kernel, policy, modevent, "int",
98109313Sobrien    "struct mac_policy_conf *");
99109313SobrienSDT_PROBE_DEFINE1(mac, kernel, policy, register,
100109313Sobrien    "struct mac_policy_conf *");
101109313SobrienSDT_PROBE_DEFINE1(mac, kernel, policy, unregister,
102109313Sobrien    "struct mac_policy_conf *");
103109313Sobrien
104109313Sobrien/*
105109313Sobrien * Root sysctl node for all MAC and MAC policy controls.
106109313Sobrien */
107109313SobrienSYSCTL_NODE(_security, OID_AUTO, mac, CTLFLAG_RW, 0,
108109313Sobrien    "TrustedBSD MAC policy controls");
109109313Sobrien
110109313Sobrien/*
111109313Sobrien * Declare that the kernel provides MAC support, version 3 (FreeBSD 7.x).
112109313Sobrien * This permits modules to refuse to be loaded if the necessary support isn't
113109313Sobrien * present, even if it's pre-boot.
114109313Sobrien */
115109313SobrienMODULE_VERSION(kernel_mac_support, MAC_VERSION);
116109313Sobrien
117109313Sobrienstatic unsigned int	mac_version = MAC_VERSION;
118109313SobrienSYSCTL_UINT(_security_mac, OID_AUTO, version, CTLFLAG_RD, &mac_version, 0,
119109313Sobrien    "");
120119794Sschweikh
121109313Sobrien/*
122109313Sobrien * Labels consist of a indexed set of "slots", which are allocated policies
123109313Sobrien * as required.  The MAC Framework maintains a bitmask of slots allocated so
124109313Sobrien * far to prevent reuse.  Slots cannot be reused, as the MAC Framework
125109313Sobrien * guarantees that newly allocated slots in labels will be NULL unless
126109313Sobrien * otherwise initialized, and because we do not have a mechanism to garbage
127241737Sed * collect slots on policy unload.  As labeled policies tend to be statically
128109313Sobrien * loaded during boot, and not frequently unloaded and reloaded, this is not
129109313Sobrien * generally an issue.
130109313Sobrien */
131109313Sobrien#if MAC_MAX_SLOTS > 32
132119794Sschweikh#error "MAC_MAX_SLOTS too large"
133109313Sobrien#endif
134109313Sobrien
135109313Sobrienstatic unsigned int mac_max_slots = MAC_MAX_SLOTS;
136109313Sobrienstatic unsigned int mac_slot_offsets_free = (1 << MAC_MAX_SLOTS) - 1;
137109313SobrienSYSCTL_UINT(_security_mac, OID_AUTO, max_slots, CTLFLAG_RD, &mac_max_slots,
138109313Sobrien    0, "");
139109313Sobrien
140109313Sobrien/*
141109313Sobrien * Has the kernel started generating labeled objects yet?  All read/write
142109313Sobrien * access to this variable is serialized during the boot process.  Following
143109313Sobrien * the end of serialization, we don't update this flag; no locking.
144109313Sobrien */
145109313Sobrienstatic int	mac_late = 0;
146109313Sobrien
147109313Sobrien/*
148109313Sobrien * Each policy declares a mask of object types requiring labels to be
149109313Sobrien * allocated for them.  For convenience, we combine and cache the bitwise or
150109313Sobrien * of the per-policy object flags to track whether we will allocate a label
151109313Sobrien * for an object type at run-time.
152109313Sobrien */
153109313Sobrienuint64_t	mac_labeled;
154109313SobrienSYSCTL_UQUAD(_security_mac, OID_AUTO, labeled, CTLFLAG_RD, &mac_labeled, 0,
155109313Sobrien    "Mask of object types being labeled");
156109313Sobrien
157109313SobrienMALLOC_DEFINE(M_MACTEMP, "mactemp", "MAC temporary label storage");
158109313Sobrien
159109313Sobrien/*
160109313Sobrien * MAC policy modules are placed in one of two lists: mac_static_policy_list,
161119794Sschweikh * for policies that are loaded early and cannot be unloaded, and
162109313Sobrien * mac_policy_list, which holds policies either loaded later in the boot
163109313Sobrien * cycle or that may be unloaded.  The static policy list does not require
164109313Sobrien * locks to iterate over, but the dynamic list requires synchronization.
165109313Sobrien * Support for dynamic policy loading can be compiled out using the
166109313Sobrien * MAC_STATIC kernel option.
167109313Sobrien *
168109332Sobrien * The dynamic policy list is protected by two locks: modifying the list
169110256Sobrien * requires both locks to be held exclusively.  One of the locks,
170109332Sobrien * mac_policy_rm, is acquired over policy entry points that will never sleep;
171109332Sobrien * the other, mac_policy_sx, is acquire over policy entry points that may
172109332Sobrien * sleep.  The former category will be used when kernel locks may be held
173109332Sobrien * over calls to the MAC Framework, during network processing in ithreads,
174109332Sobrien * etc.  The latter will tend to involve potentially blocking memory
175109332Sobrien * allocations, extended attribute I/O, etc.
176109332Sobrien */
177109332Sobrien#ifndef MAC_STATIC
178109332Sobrienstatic struct rmlock mac_policy_rm;	/* Non-sleeping entry points. */
179109332Sobrienstatic struct sx mac_policy_sx;		/* Sleeping entry points. */
180109332Sobrien#endif
181109332Sobrien
182109332Sobrienstruct mac_policy_list_head mac_policy_list;
183109332Sobrienstruct mac_policy_list_head mac_static_policy_list;
184109332Sobrienu_int mac_policy_count;			/* Registered policy count. */
185109332Sobrien
186109332Sobrienstatic void	mac_policy_xlock(void);
187109332Sobrienstatic void	mac_policy_xlock_assert(void);
188109332Sobrienstatic void	mac_policy_xunlock(void);
189109332Sobrien
190109332Sobrienvoid
191109332Sobrienmac_policy_slock_nosleep(struct rm_priotracker *tracker)
192109332Sobrien{
193109332Sobrien
194109332Sobrien#ifndef MAC_STATIC
195109332Sobrien	if (!mac_late)
196109332Sobrien		return;
197109332Sobrien
198109332Sobrien	rm_rlock(&mac_policy_rm, tracker);
199109332Sobrien#endif
200109332Sobrien}
201109332Sobrien
202109332Sobrienvoid
203109332Sobrienmac_policy_slock_sleep(void)
204109332Sobrien{
205109332Sobrien
206109332Sobrien	WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL,
207109332Sobrien 	    "mac_policy_slock_sleep");
208109332Sobrien
209109332Sobrien#ifndef MAC_STATIC
210109332Sobrien	if (!mac_late)
211109332Sobrien		return;
212109332Sobrien
213109332Sobrien	sx_slock(&mac_policy_sx);
214109332Sobrien#endif
215109332Sobrien}
216109332Sobrien
217109332Sobrienvoid
218109332Sobrienmac_policy_sunlock_nosleep(struct rm_priotracker *tracker)
219109332Sobrien{
220109332Sobrien
221109332Sobrien#ifndef MAC_STATIC
222109332Sobrien	if (!mac_late)
223109332Sobrien		return;
224109332Sobrien
225109332Sobrien	rm_runlock(&mac_policy_rm, tracker);
226109332Sobrien#endif
227109332Sobrien}
228109332Sobrien
229109332Sobrienvoid
230109332Sobrienmac_policy_sunlock_sleep(void)
231109332Sobrien{
232109332Sobrien
233109332Sobrien#ifndef MAC_STATIC
234109332Sobrien	if (!mac_late)
235154958Smarcel		return;
236109332Sobrien
237109332Sobrien	sx_sunlock(&mac_policy_sx);
238109332Sobrien#endif
239109332Sobrien}
240109332Sobrien
241119794Sschweikhstatic void
242109313Sobrienmac_policy_xlock(void)
243110256Sobrien{
244109457Smarcel
245109457Smarcel	WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL,
246153500Smarcel 	    "mac_policy_xlock()");
247153500Smarcel
248109457Smarcel#ifndef MAC_STATIC
249109457Smarcel	if (!mac_late)
250109457Smarcel		return;
251109457Smarcel
252109457Smarcel	sx_xlock(&mac_policy_sx);
253109457Smarcel	rm_wlock(&mac_policy_rm);
254109457Smarcel#endif
255109457Smarcel}
256109457Smarcel
257153500Smarcelstatic void
258153500Smarcelmac_policy_xunlock(void)
259153500Smarcel{
260153500Smarcel
261109457Smarcel#ifndef MAC_STATIC
262153500Smarcel	if (!mac_late)
263109457Smarcel		return;
264153500Smarcel
265153500Smarcel	rm_wunlock(&mac_policy_rm);
266153500Smarcel	sx_xunlock(&mac_policy_sx);
267119794Sschweikh#endif
268109313Sobrien}
269241737Sed
270109313Sobrienstatic void
271109313Sobrienmac_policy_xlock_assert(void)
272109313Sobrien{
273241737Sed
274109313Sobrien#ifndef MAC_STATIC
275109313Sobrien	if (!mac_late)
276109313Sobrien		return;
277241737Sed
278109313Sobrien	/* XXXRW: rm_assert(&mac_policy_rm, RA_WLOCKED); */
279109313Sobrien	sx_assert(&mac_policy_sx, SA_XLOCKED);
280109313Sobrien#endif
281241737Sed}
282109313Sobrien
283109313Sobrien/*
284109313Sobrien * Initialize the MAC subsystem, including appropriate SMP locks.
285241737Sed */
286109313Sobrienstatic void
287226434Smarcelmac_init(void)
288226434Smarcel{
289226434Smarcel
290226434Smarcel	LIST_INIT(&mac_static_policy_list);
291109313Sobrien	LIST_INIT(&mac_policy_list);
292109313Sobrien	mac_labelzone_init();
293241737Sed
294109313Sobrien#ifndef MAC_STATIC
295126484Sjake	rm_init_flags(&mac_policy_rm, "mac_policy_rm", RM_NOWITNESS |
296109313Sobrien	    RM_RECURSE);
297109313Sobrien	sx_init_flags(&mac_policy_sx, "mac_policy_sx", SX_NOWITNESS);
298241737Sed#endif
299109313Sobrien}
300109313Sobrien
301109313Sobrien/*
302109313Sobrien * For the purposes of modules that want to know if they were loaded "early",
303109329Sobrien * set the mac_late flag once we've processed modules either linked into the
304110256Sobrien * kernel, or loaded before the kernel startup.
305109332Sobrien */
306109329Sobrienstatic void
307109329Sobrienmac_late_init(void)
308109329Sobrien{
309109329Sobrien
310109329Sobrien	mac_late = 1;
311109329Sobrien}
312109329Sobrien
313109329Sobrien/*
314109329Sobrien * Given a policy, derive from its set of non-NULL label init methods what
315109329Sobrien * object types the policy is interested in.
316109329Sobrien */
317109329Sobrienstatic uint64_t
318109329Sobrienmac_policy_getlabeled(struct mac_policy_conf *mpc)
319109329Sobrien{
320109329Sobrien	uint64_t labeled;
321109329Sobrien
322109329Sobrien#define	MPC_FLAG(method, flag)					\
323109329Sobrien	if (mpc->mpc_ops->mpo_ ## method != NULL)			\
324109332Sobrien		labeled |= (flag);					\
325109329Sobrien
326211188Srpaulo	labeled = 0;
327109329Sobrien	MPC_FLAG(cred_init_label, MPC_OBJECT_CRED);
328109329Sobrien	MPC_FLAG(proc_init_label, MPC_OBJECT_PROC);
329109329Sobrien	MPC_FLAG(vnode_init_label, MPC_OBJECT_VNODE);
330109329Sobrien	MPC_FLAG(inpcb_init_label, MPC_OBJECT_INPCB);
331109329Sobrien	MPC_FLAG(socket_init_label, MPC_OBJECT_SOCKET);
332109332Sobrien	MPC_FLAG(devfs_init_label, MPC_OBJECT_DEVFS);
333109457Smarcel	MPC_FLAG(mbuf_init_label, MPC_OBJECT_MBUF);
334109457Smarcel	MPC_FLAG(ipq_init_label, MPC_OBJECT_IPQ);
335109329Sobrien	MPC_FLAG(ifnet_init_label, MPC_OBJECT_IFNET);
336109329Sobrien	MPC_FLAG(bpfdesc_init_label, MPC_OBJECT_BPFDESC);
337109332Sobrien	MPC_FLAG(pipe_init_label, MPC_OBJECT_PIPE);
338109329Sobrien	MPC_FLAG(mount_init_label, MPC_OBJECT_MOUNT);
339109329Sobrien	MPC_FLAG(posixsem_init_label, MPC_OBJECT_POSIXSEM);
340119795Sschweikh	MPC_FLAG(posixshm_init_label, MPC_OBJECT_POSIXSHM);
341109313Sobrien	MPC_FLAG(sysvmsg_init_label, MPC_OBJECT_SYSVMSG);
342241737Sed	MPC_FLAG(sysvmsq_init_label, MPC_OBJECT_SYSVMSQ);
343109313Sobrien	MPC_FLAG(sysvsem_init_label, MPC_OBJECT_SYSVSEM);
344109313Sobrien	MPC_FLAG(sysvshm_init_label, MPC_OBJECT_SYSVSHM);
345109313Sobrien	MPC_FLAG(syncache_init_label, MPC_OBJECT_SYNCACHE);
346109313Sobrien	MPC_FLAG(ip6q_init_label, MPC_OBJECT_IP6Q);
347109313Sobrien
348241737Sed#undef MPC_FLAG
349109313Sobrien	return (labeled);
350109313Sobrien}
351109313Sobrien
352241737Sed/*
353109313Sobrien * When policies are loaded or unloaded, walk the list of registered policies
354109313Sobrien * and built mac_labeled, a bitmask representing the union of all objects
355109313Sobrien * requiring labels across all policies.
356241737Sed */
357241737Sedstatic void
358241737Sedmac_policy_update(void)
359241737Sed{
360109313Sobrien	struct mac_policy_conf *mpc;
361241737Sed
362241737Sed	mac_policy_xlock_assert();
363241737Sed
364241737Sed	mac_labeled = 0;
365241737Sed	mac_policy_count = 0;
366241737Sed	LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) {
367241737Sed		mac_labeled |= mac_policy_getlabeled(mpc);
368241737Sed		mac_policy_count++;
369109313Sobrien	}
370241737Sed	LIST_FOREACH(mpc, &mac_policy_list, mpc_list) {
371241737Sed		mac_labeled |= mac_policy_getlabeled(mpc);
372241737Sed		mac_policy_count++;
373241737Sed	}
374241737Sed}
375241737Sed
376241737Sedstatic int
377241737Sedmac_policy_register(struct mac_policy_conf *mpc)
378241737Sed{
379241737Sed	struct mac_policy_conf *tmpc;
380241737Sed	int error, slot, static_entry;
381109313Sobrien
382241737Sed	error = 0;
383109313Sobrien
384109313Sobrien	/*
385109313Sobrien	 * We don't technically need exclusive access while !mac_late, but
386109313Sobrien	 * hold it for assertion consistency.
387109313Sobrien	 */
388109313Sobrien	mac_policy_xlock();
389109313Sobrien
390109313Sobrien	/*
391109313Sobrien	 * If the module can potentially be unloaded, or we're loading late,
392109313Sobrien	 * we have to stick it in the non-static list and pay an extra
393109313Sobrien	 * performance overhead.  Otherwise, we can pay a light locking cost
394109313Sobrien	 * and stick it in the static list.
395109313Sobrien	 */
396109313Sobrien	static_entry = (!mac_late &&
397109313Sobrien	    !(mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_UNLOADOK));
398109313Sobrien
399110252Sobrien	if (static_entry) {
400109313Sobrien		LIST_FOREACH(tmpc, &mac_static_policy_list, mpc_list) {
401109313Sobrien			if (strcmp(tmpc->mpc_name, mpc->mpc_name) == 0) {
402109313Sobrien				error = EEXIST;
403109313Sobrien				goto out;
404109313Sobrien			}
405109313Sobrien		}
406109313Sobrien	} else {
407109313Sobrien		LIST_FOREACH(tmpc, &mac_policy_list, mpc_list) {
408109313Sobrien			if (strcmp(tmpc->mpc_name, mpc->mpc_name) == 0) {
409109313Sobrien				error = EEXIST;
410109313Sobrien				goto out;
411109313Sobrien			}
412109313Sobrien		}
413109313Sobrien	}
414109313Sobrien	if (mpc->mpc_field_off != NULL) {
415109313Sobrien		slot = ffs(mac_slot_offsets_free);
416109313Sobrien		if (slot == 0) {
417109313Sobrien			error = ENOMEM;
418109313Sobrien			goto out;
419109313Sobrien		}
420109313Sobrien		slot--;
421109313Sobrien		mac_slot_offsets_free &= ~(1 << slot);
422109313Sobrien		*mpc->mpc_field_off = slot;
423109313Sobrien	}
424109313Sobrien	mpc->mpc_runtime_flags |= MPC_RUNTIME_FLAG_REGISTERED;
425109313Sobrien
426109313Sobrien	/*
427109313Sobrien	 * If we're loading a MAC module after the framework has initialized,
428109313Sobrien	 * it has to go into the dynamic list.  If we're loading it before
429109313Sobrien	 * we've finished initializing, it can go into the static list with
430109313Sobrien	 * weaker locker requirements.
431109313Sobrien	 */
432109313Sobrien	if (static_entry)
433109313Sobrien		LIST_INSERT_HEAD(&mac_static_policy_list, mpc, mpc_list);
434109313Sobrien	else
435109313Sobrien		LIST_INSERT_HEAD(&mac_policy_list, mpc, mpc_list);
436109313Sobrien
437109313Sobrien	/*
438109313Sobrien	 * Per-policy initialization.  Currently, this takes place under the
439109313Sobrien	 * exclusive lock, so policies must not sleep in their init method.
440109313Sobrien	 * In the future, we may want to separate "init" from "start", with
441109313Sobrien	 * "init" occuring without the lock held.  Likewise, on tear-down,
442109313Sobrien	 * breaking out "stop" from "destroy".
443109313Sobrien	 */
444109313Sobrien	if (mpc->mpc_ops->mpo_init != NULL)
445109313Sobrien		(*(mpc->mpc_ops->mpo_init))(mpc);
446109313Sobrien	mac_policy_update();
447109313Sobrien
448109313Sobrien	SDT_PROBE(mac, kernel, policy, register, mpc, 0, 0, 0, 0);
449109313Sobrien	printf("Security policy loaded: %s (%s)\n", mpc->mpc_fullname,
450109313Sobrien	    mpc->mpc_name);
451109313Sobrien
452109313Sobrienout:
453109313Sobrien	mac_policy_xunlock();
454109313Sobrien	return (error);
455109313Sobrien}
456109313Sobrien
457109313Sobrienstatic int
458117009Srumac_policy_unregister(struct mac_policy_conf *mpc)
459109313Sobrien{
460109313Sobrien
461109313Sobrien	/*
462109313Sobrien	 * If we fail the load, we may get a request to unload.  Check to see
463109313Sobrien	 * if we did the run-time registration, and if not, silently succeed.
464109313Sobrien	 */
465109313Sobrien	mac_policy_xlock();
466109313Sobrien	if ((mpc->mpc_runtime_flags & MPC_RUNTIME_FLAG_REGISTERED) == 0) {
467109313Sobrien		mac_policy_xunlock();
468109313Sobrien		return (0);
469109313Sobrien	}
470109313Sobrien#if 0
471110256Sobrien	/*
472110256Sobrien	 * Don't allow unloading modules with private data.
473110256Sobrien	 */
474110252Sobrien	if (mpc->mpc_field_off != NULL) {
475110256Sobrien		mac_policy_xunlock();
476110256Sobrien		return (EBUSY);
477110256Sobrien	}
478109313Sobrien#endif
479110252Sobrien	/*
480109313Sobrien	 * Only allow the unload to proceed if the module is unloadable by
481110252Sobrien	 * its own definition.
482109313Sobrien	 */
483109313Sobrien	if ((mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_UNLOADOK) == 0) {
484109313Sobrien		mac_policy_xunlock();
485109313Sobrien		return (EBUSY);
486109313Sobrien	}
487109313Sobrien	if (mpc->mpc_ops->mpo_destroy != NULL)
488109313Sobrien		(*(mpc->mpc_ops->mpo_destroy))(mpc);
489110256Sobrien
490110256Sobrien	LIST_REMOVE(mpc, mpc_list);
491109313Sobrien	mpc->mpc_runtime_flags &= ~MPC_RUNTIME_FLAG_REGISTERED;
492109313Sobrien	mac_policy_update();
493109313Sobrien	mac_policy_xunlock();
494109313Sobrien
495109313Sobrien	SDT_PROBE(mac, kernel, policy, unregister, mpc, 0, 0, 0, 0);
496109313Sobrien	printf("Security policy unload: %s (%s)\n", mpc->mpc_fullname,
497109313Sobrien	    mpc->mpc_name);
498109313Sobrien
499109313Sobrien	return (0);
500109313Sobrien}
501109313Sobrien
502109313Sobrien/*
503109313Sobrien * Allow MAC policy modules to register during boot, etc.
504109313Sobrien */
505109313Sobrienint
506110256Sobrienmac_policy_modevent(module_t mod, int type, void *data)
507110256Sobrien{
508109313Sobrien	struct mac_policy_conf *mpc;
509109313Sobrien	int error;
510109313Sobrien
511109313Sobrien	error = 0;
512109313Sobrien	mpc = (struct mac_policy_conf *) data;
513109313Sobrien
514109313Sobrien#ifdef MAC_STATIC
515109313Sobrien	if (mac_late) {
516109313Sobrien		printf("mac_policy_modevent: MAC_STATIC and late\n");
517109313Sobrien		return (EBUSY);
518109313Sobrien	}
519109313Sobrien#endif
520109313Sobrien
521109313Sobrien	SDT_PROBE(mac, kernel, policy, modevent, type, mpc, 0, 0, 0);
522109313Sobrien	switch (type) {
523109313Sobrien	case MOD_LOAD:
524109313Sobrien		if (mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_NOTLATE &&
525109313Sobrien		    mac_late) {
526109313Sobrien			printf("mac_policy_modevent: can't load %s policy "
527109313Sobrien			    "after booting\n", mpc->mpc_name);
528109313Sobrien			error = EBUSY;
529109313Sobrien			break;
530109313Sobrien		}
531109313Sobrien		error = mac_policy_register(mpc);
532109313Sobrien		break;
533109313Sobrien	case MOD_UNLOAD:
534109313Sobrien		/* Don't unregister the module if it was never registered. */
535109313Sobrien		if ((mpc->mpc_runtime_flags & MPC_RUNTIME_FLAG_REGISTERED)
536109313Sobrien		    != 0)
537109313Sobrien			error = mac_policy_unregister(mpc);
538109313Sobrien		else
539109313Sobrien			error = 0;
540109313Sobrien		break;
541109313Sobrien	default:
542109313Sobrien		error = EOPNOTSUPP;
543109313Sobrien		break;
544109313Sobrien	}
545109313Sobrien
546109313Sobrien	return (error);
547109313Sobrien}
548109313Sobrien
549109313Sobrien/*
550109313Sobrien * Define an error value precedence, and given two arguments, selects the
551109313Sobrien * value with the higher precedence.
552109313Sobrien */
553109313Sobrienint
554109313Sobrienmac_error_select(int error1, int error2)
555109313Sobrien{
556109313Sobrien
557241737Sed	/* Certain decision-making errors take top priority. */
558110252Sobrien	if (error1 == EDEADLK || error2 == EDEADLK)
559109313Sobrien		return (EDEADLK);
560109313Sobrien
561109313Sobrien	/* Invalid arguments should be reported where possible. */
562109313Sobrien	if (error1 == EINVAL || error2 == EINVAL)
563109313Sobrien		return (EINVAL);
564109313Sobrien
565109313Sobrien	/* Precedence goes to "visibility", with both process and file. */
566109313Sobrien	if (error1 == ESRCH || error2 == ESRCH)
567109313Sobrien		return (ESRCH);
568109313Sobrien
569109313Sobrien	if (error1 == ENOENT || error2 == ENOENT)
570109313Sobrien		return (ENOENT);
571109313Sobrien
572109313Sobrien	/* Precedence goes to DAC/MAC protections. */
573109313Sobrien	if (error1 == EACCES || error2 == EACCES)
574109313Sobrien		return (EACCES);
575109313Sobrien
576109313Sobrien	/* Precedence goes to privilege. */
577109313Sobrien	if (error1 == EPERM || error2 == EPERM)
578109313Sobrien		return (EPERM);
579109313Sobrien
580109313Sobrien	/* Precedence goes to error over success; otherwise, arbitrary. */
581109313Sobrien	if (error1 != 0)
582109313Sobrien		return (error1);
583109313Sobrien	return (error2);
584109313Sobrien}
585109313Sobrien
586109313Sobrienint
587109313Sobrienmac_check_structmac_consistent(struct mac *mac)
588109313Sobrien{
589109313Sobrien
590109313Sobrien	if (mac->m_buflen < 0 ||
591109313Sobrien	    mac->m_buflen > MAC_MAX_LABEL_BUF_LEN)
592109313Sobrien		return (EINVAL);
593109313Sobrien
594109313Sobrien	return (0);
595109313Sobrien}
596109313Sobrien
597109313SobrienSYSINIT(mac, SI_SUB_MAC, SI_ORDER_FIRST, mac_init, NULL);
598109457SmarcelSYSINIT(mac_late, SI_SUB_MAC_LATE, SI_ORDER_FIRST, mac_late_init, NULL);
599109313Sobrien