mac_framework.c revision 165411
1100894Srwatson/*-
2126097Srwatson * Copyright (c) 1999-2002 Robert N. M. Watson
3100894Srwatson * Copyright (c) 2001 Ilmar S. Habibulin
4145160Srwatson * Copyright (c) 2001-2005 Networks Associates Technology, Inc.
5163606Srwatson * Copyright (c) 2005-2006 SPARTA, Inc.
6100894Srwatson * All rights reserved.
7100894Srwatson *
8100894Srwatson * This software was developed by Robert Watson and Ilmar Habibulin for the
9100894Srwatson * TrustedBSD Project.
10100894Srwatson *
11106392Srwatson * This software was developed for the FreeBSD Project in part by Network
12106392Srwatson * Associates Laboratories, the Security Research Division of Network
13106392Srwatson * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"),
14106392Srwatson * as part of the DARPA CHATS research program.
15100894Srwatson *
16147983Srwatson * This software was enhanced by SPARTA ISSO under SPAWAR contract
17147983Srwatson * N66001-04-C-6019 ("SEFOS").
18147983Srwatson *
19100894Srwatson * Redistribution and use in source and binary forms, with or without
20100894Srwatson * modification, are permitted provided that the following conditions
21100894Srwatson * are met:
22100894Srwatson * 1. Redistributions of source code must retain the above copyright
23100894Srwatson *    notice, this list of conditions and the following disclaimer.
24100894Srwatson * 2. Redistributions in binary form must reproduce the above copyright
25100894Srwatson *    notice, this list of conditions and the following disclaimer in the
26100894Srwatson *    documentation and/or other materials provided with the distribution.
27100894Srwatson *
28100894Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
29100894Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30100894Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31100894Srwatson * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
32100894Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33100894Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34100894Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35100894Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36100894Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37100894Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38100894Srwatson * SUCH DAMAGE.
39100894Srwatson */
40116182Sobrien
41122454Srwatson/*-
42122454Srwatson * Framework for extensible kernel access control.  This file contains
43122454Srwatson * Kernel and userland interface to the framework, policy registration
44122454Srwatson * and composition.  Per-object interfaces, controls, and labeling may be
45145414Strhodes * found in src/sys/security/mac/.  Sample policies may be found in
46145414Strhodes * src/sys/security/mac_*.
47100894Srwatson */
48100894Srwatson
49116182Sobrien#include <sys/cdefs.h>
50116182Sobrien__FBSDID("$FreeBSD: head/sys/security/mac/mac_framework.c 165411 2006-12-20 20:38:44Z rwatson $");
51116182Sobrien
52100894Srwatson#include "opt_mac.h"
53101173Srwatson
54100894Srwatson#include <sys/param.h>
55106856Srwatson#include <sys/condvar.h>
56100979Srwatson#include <sys/extattr.h>
57106468Srwatson#include <sys/imgact.h>
58100979Srwatson#include <sys/kernel.h>
59100979Srwatson#include <sys/lock.h>
60102949Sbde#include <sys/malloc.h>
61100979Srwatson#include <sys/mutex.h>
62100979Srwatson#include <sys/mac.h>
63101712Srwatson#include <sys/module.h>
64100979Srwatson#include <sys/proc.h>
65116701Srwatson#include <sys/sbuf.h>
66100979Srwatson#include <sys/systm.h>
67100894Srwatson#include <sys/sysproto.h>
68100894Srwatson#include <sys/sysent.h>
69100979Srwatson#include <sys/vnode.h>
70100979Srwatson#include <sys/mount.h>
71100979Srwatson#include <sys/file.h>
72100979Srwatson#include <sys/namei.h>
73100979Srwatson#include <sys/socket.h>
74100979Srwatson#include <sys/pipe.h>
75100979Srwatson#include <sys/socketvar.h>
76100979Srwatson#include <sys/sysctl.h>
77100894Srwatson
78100979Srwatson#include <vm/vm.h>
79100979Srwatson#include <vm/pmap.h>
80100979Srwatson#include <vm/vm_map.h>
81100979Srwatson#include <vm/vm_object.h>
82100979Srwatson
83100979Srwatson#include <sys/mac_policy.h>
84100979Srwatson
85100979Srwatson#include <fs/devfs/devfs.h>
86100979Srwatson
87100979Srwatson#include <net/bpfdesc.h>
88100979Srwatson#include <net/if.h>
89100979Srwatson#include <net/if_var.h>
90100979Srwatson
91100979Srwatson#include <netinet/in.h>
92100979Srwatson#include <netinet/ip_var.h>
93100979Srwatson
94163606Srwatson#include <security/mac/mac_framework.h>
95121374Srwatson#include <security/mac/mac_internal.h>
96121374Srwatson
97100979Srwatson#ifdef MAC
98100979Srwatson
99101712Srwatson/*
100101712Srwatson * Declare that the kernel provides MAC support, version 1.  This permits
101101712Srwatson * modules to refuse to be loaded if the necessary support isn't present,
102101712Srwatson * even if it's pre-boot.
103101712Srwatson */
104147983SrwatsonMODULE_VERSION(kernel_mac_support, 3);
105101712Srwatson
106100979SrwatsonSYSCTL_NODE(_security, OID_AUTO, mac, CTLFLAG_RW, 0,
107100979Srwatson    "TrustedBSD MAC policy controls");
108104517Srwatson
109165411Srwatson/*
110165411Srwatson * Labels consist of a indexed set of "slots", which are allocated policies
111165411Srwatson * as required.  The MAC Framework maintains a bitmask of slots allocated so
112165411Srwatson * far to prevent reuse.  Slots cannot be reused, as the MAC Framework
113165411Srwatson * guarantees that newly allocated slots in labels will be NULL unless
114165411Srwatson * otherwise initialized, and because we do not have a mechanism to garbage
115165411Srwatson * collect slots on policy unload.  As labeled policies tend to be statically
116165411Srwatson * loaded during boot, and not frequently unloaded and reloaded, this is not
117165411Srwatson * generally an issue.
118165411Srwatson */
119114846Srwatson#if MAC_MAX_SLOTS > 32
120114846Srwatson#error "MAC_MAX_SLOTS too large"
121100979Srwatson#endif
122105497Srwatson
123114846Srwatsonstatic unsigned int mac_max_slots = MAC_MAX_SLOTS;
124114846Srwatsonstatic unsigned int mac_slot_offsets_free = (1 << MAC_MAX_SLOTS) - 1;
125114846SrwatsonSYSCTL_UINT(_security_mac, OID_AUTO, max_slots, CTLFLAG_RD,
126114846Srwatson    &mac_max_slots, 0, "");
127100979Srwatson
128105959Srwatson/*
129105959Srwatson * Has the kernel started generating labeled objects yet?  All read/write
130105959Srwatson * access to this variable is serialized during the boot process.  Following
131105959Srwatson * the end of serialization, we don't update this flag; no locking.
132105959Srwatson */
133121372Srwatsonint	mac_late = 0;
134100979Srwatson
135105988Srwatson/*
136165411Srwatson * Flag to indicate whether or not we should allocate label storage for new
137165411Srwatson * mbufs.  Since most dynamic policies we currently work with don't rely on
138165411Srwatson * mbuf labeling, try to avoid paying the cost of mtag allocation unless
139165411Srwatson * specifically notified of interest.  One result of this is that if a
140165411Srwatson * dynamically loaded policy requests mbuf labels, it must be able to deal
141165411Srwatson * with a NULL label being returned on any mbufs that were already in flight
142165411Srwatson * when the policy was loaded.  Since the policy already has to deal with
143165411Srwatson * uninitialized labels, this probably won't be a problem.  Note: currently
144165411Srwatson * no locking.  Will this be a problem?
145165411Srwatson *
146165411Srwatson * In the future, we may want to allow objects to request labeling on a per-
147165411Srwatson * object type basis, rather than globally for all objects.
148113487Srwatson */
149118308Srwatson#ifndef MAC_ALWAYS_LABEL_MBUF
150121372Srwatsonint	mac_labelmbufs = 0;
151113487Srwatson#endif
152113487Srwatson
153100979Srwatsonstatic int	mac_policy_register(struct mac_policy_conf *mpc);
154100979Srwatsonstatic int	mac_policy_unregister(struct mac_policy_conf *mpc);
155100979Srwatson
156105694SrwatsonMALLOC_DEFINE(M_MACTEMP, "mactemp", "MAC temporary label storage");
157100979Srwatson
158100979Srwatson/*
159165411Srwatson * mac_static_policy_list holds a list of policy modules that are not loaded
160165411Srwatson * while the system is "live", and cannot be unloaded.  These policies can be
161165411Srwatson * invoked without holding the busy count.
162114806Srwatson *
163114806Srwatson * mac_policy_list stores the list of dynamic policies.  A busy count is
164165411Srwatson * maintained for the list, stored in mac_policy_busy.  The busy count is
165165411Srwatson * protected by mac_policy_mtx; the list may be modified only while the busy
166165411Srwatson * count is 0, requiring that the lock be held to prevent new references to
167165411Srwatson * the list from being acquired.  For almost all operations, incrementing the
168165411Srwatson * busy count is sufficient to guarantee consistency, as the list cannot be
169165411Srwatson * modified while the busy count is elevated.  For a few special operations
170165411Srwatson * involving a change to the list of active policies, the mtx itself must be
171165411Srwatson * held.  A condition variable, mac_policy_cv, is used to signal potential
172165411Srwatson * exclusive consumers that they should try to acquire the lock if a first
173165411Srwatson * attempt at exclusive access fails.
174165411Srwatson *
175165411Srwatson * This design intentionally avoids fairness, and may starve attempts to
176165411Srwatson * acquire an exclusive lock on a busy system.  This is required because we
177165411Srwatson * do not ever want acquiring a read reference to perform an unbounded length
178165411Srwatson * sleep.  Read references are acquired in ithreads, network isrs, etc, and
179165411Srwatson * any unbounded blocking could lead quickly to deadlock.
180165411Srwatson *
181165411Srwatson * Another reason for never blocking on read references is that the MAC
182165411Srwatson * Framework may recurse: if a policy calls a VOP, for example, this might
183165411Srwatson * lead to vnode life cycle operations (such as init/destroy).
184100979Srwatson */
185128885Srwatson#ifndef MAC_STATIC
186114806Srwatsonstatic struct mtx mac_policy_mtx;
187114806Srwatsonstatic struct cv mac_policy_cv;
188114806Srwatsonstatic int mac_policy_count;
189128885Srwatson#endif
190121372Srwatsonstruct mac_policy_list_head mac_policy_list;
191121372Srwatsonstruct mac_policy_list_head mac_static_policy_list;
192100979Srwatson
193106856Srwatson/*
194165411Srwatson * We manually invoke WITNESS_WARN() to allow Witness to generate warnings
195165411Srwatson * even if we don't end up ever triggering the wait at run-time.  The
196165411Srwatson * consumer of the exclusive interface must not hold any locks (other than
197165411Srwatson * potentially Giant) since we may sleep for long (potentially indefinite)
198165411Srwatson * periods of time waiting for the framework to become quiescent so that a
199165411Srwatson * policy list change may be made.
200106856Srwatson */
201121372Srwatsonvoid
202114806Srwatsonmac_policy_grab_exclusive(void)
203114806Srwatson{
204122454Srwatson
205128885Srwatson#ifndef MAC_STATIC
206137072Srwatson	if (!mac_late)
207137072Srwatson		return;
208137072Srwatson
209114806Srwatson	WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL,
210114806Srwatson 	    "mac_policy_grab_exclusive() at %s:%d", __FILE__, __LINE__);
211114806Srwatson	mtx_lock(&mac_policy_mtx);
212114806Srwatson	while (mac_policy_count != 0)
213114806Srwatson		cv_wait(&mac_policy_cv, &mac_policy_mtx);
214128885Srwatson#endif
215114806Srwatson}
216106856Srwatson
217121372Srwatsonvoid
218114806Srwatsonmac_policy_assert_exclusive(void)
219114806Srwatson{
220122454Srwatson
221128885Srwatson#ifndef MAC_STATIC
222137072Srwatson	if (!mac_late)
223137072Srwatson		return;
224137072Srwatson
225114806Srwatson	mtx_assert(&mac_policy_mtx, MA_OWNED);
226114806Srwatson	KASSERT(mac_policy_count == 0,
227114806Srwatson	    ("mac_policy_assert_exclusive(): not exclusive"));
228128885Srwatson#endif
229114806Srwatson}
230113487Srwatson
231121372Srwatsonvoid
232114806Srwatsonmac_policy_release_exclusive(void)
233114806Srwatson{
234100979Srwatson
235128885Srwatson#ifndef MAC_STATIC
236137072Srwatson	if (!mac_late)
237137072Srwatson		return;
238137072Srwatson
239114806Srwatson	KASSERT(mac_policy_count == 0,
240114806Srwatson	    ("mac_policy_release_exclusive(): not exclusive"));
241114806Srwatson	mtx_unlock(&mac_policy_mtx);
242114806Srwatson	cv_signal(&mac_policy_cv);
243128885Srwatson#endif
244114806Srwatson}
245100979Srwatson
246121372Srwatsonvoid
247114806Srwatsonmac_policy_list_busy(void)
248114806Srwatson{
249122454Srwatson
250128885Srwatson#ifndef MAC_STATIC
251137072Srwatson	if (!mac_late)
252137072Srwatson		return;
253137072Srwatson
254114806Srwatson	mtx_lock(&mac_policy_mtx);
255114806Srwatson	mac_policy_count++;
256114806Srwatson	mtx_unlock(&mac_policy_mtx);
257128885Srwatson#endif
258114806Srwatson}
259114806Srwatson
260121372Srwatsonint
261114806Srwatsonmac_policy_list_conditional_busy(void)
262114806Srwatson{
263128885Srwatson#ifndef MAC_STATIC
264114806Srwatson	int ret;
265114806Srwatson
266137072Srwatson	if (!mac_late)
267137072Srwatson		return (1);
268137072Srwatson
269114806Srwatson	mtx_lock(&mac_policy_mtx);
270114806Srwatson	if (!LIST_EMPTY(&mac_policy_list)) {
271114806Srwatson		mac_policy_count++;
272114806Srwatson		ret = 1;
273114806Srwatson	} else
274114806Srwatson		ret = 0;
275114806Srwatson	mtx_unlock(&mac_policy_mtx);
276114806Srwatson	return (ret);
277128885Srwatson#else
278137072Srwatson	if (!mac_late)
279137072Srwatson		return (1);
280137072Srwatson
281128885Srwatson	return (1);
282128885Srwatson#endif
283114806Srwatson}
284114806Srwatson
285121372Srwatsonvoid
286114806Srwatsonmac_policy_list_unbusy(void)
287114806Srwatson{
288122454Srwatson
289128885Srwatson#ifndef MAC_STATIC
290137072Srwatson	if (!mac_late)
291137072Srwatson		return;
292137072Srwatson
293114806Srwatson	mtx_lock(&mac_policy_mtx);
294114806Srwatson	mac_policy_count--;
295114806Srwatson	KASSERT(mac_policy_count >= 0, ("MAC_POLICY_LIST_LOCK"));
296114806Srwatson	if (mac_policy_count == 0)
297114806Srwatson		cv_signal(&mac_policy_cv);
298114806Srwatson	mtx_unlock(&mac_policy_mtx);
299128885Srwatson#endif
300114806Srwatson}
301114806Srwatson
302100979Srwatson/*
303100979Srwatson * Initialize the MAC subsystem, including appropriate SMP locks.
304100979Srwatson */
305100979Srwatsonstatic void
306100979Srwatsonmac_init(void)
307100979Srwatson{
308100979Srwatson
309114806Srwatson	LIST_INIT(&mac_static_policy_list);
310100979Srwatson	LIST_INIT(&mac_policy_list);
311122524Srwatson	mac_labelzone_init();
312114806Srwatson
313128885Srwatson#ifndef MAC_STATIC
314114806Srwatson	mtx_init(&mac_policy_mtx, "mac_policy_mtx", NULL, MTX_DEF);
315114806Srwatson	cv_init(&mac_policy_cv, "mac_policy_cv");
316128885Srwatson#endif
317100979Srwatson}
318100979Srwatson
319100979Srwatson/*
320165411Srwatson * For the purposes of modules that want to know if they were loaded "early",
321165411Srwatson * set the mac_late flag once we've processed modules either linked into the
322165411Srwatson * kernel, or loaded before the kernel startup.
323100979Srwatson */
324100979Srwatsonstatic void
325100979Srwatsonmac_late_init(void)
326100979Srwatson{
327100979Srwatson
328100979Srwatson	mac_late = 1;
329100979Srwatson}
330100979Srwatson
331100979Srwatson/*
332113487Srwatson * After the policy list has changed, walk the list to update any global
333118308Srwatson * flags.  Currently, we support only one flag, and it's conditionally
334165411Srwatson * defined; as a result, the entire function is conditional.  Eventually, the
335165411Srwatson * #else case might also iterate across the policies.
336113487Srwatson */
337113487Srwatsonstatic void
338113487Srwatsonmac_policy_updateflags(void)
339113487Srwatson{
340118308Srwatson#ifndef MAC_ALWAYS_LABEL_MBUF
341113487Srwatson	struct mac_policy_conf *tmpc;
342113487Srwatson	int labelmbufs;
343113487Srwatson
344114806Srwatson	mac_policy_assert_exclusive();
345113487Srwatson
346113487Srwatson	labelmbufs = 0;
347114806Srwatson	LIST_FOREACH(tmpc, &mac_static_policy_list, mpc_list) {
348114806Srwatson		if (tmpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_LABELMBUFS)
349114806Srwatson			labelmbufs++;
350114806Srwatson	}
351113487Srwatson	LIST_FOREACH(tmpc, &mac_policy_list, mpc_list) {
352113487Srwatson		if (tmpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_LABELMBUFS)
353113487Srwatson			labelmbufs++;
354113487Srwatson	}
355113487Srwatson	mac_labelmbufs = (labelmbufs != 0);
356113487Srwatson#endif
357113487Srwatson}
358113487Srwatson
359113487Srwatson/*
360100979Srwatson * Allow MAC policy modules to register during boot, etc.
361100979Srwatson */
362100894Srwatsonint
363100979Srwatsonmac_policy_modevent(module_t mod, int type, void *data)
364100979Srwatson{
365100979Srwatson	struct mac_policy_conf *mpc;
366100979Srwatson	int error;
367100979Srwatson
368100979Srwatson	error = 0;
369100979Srwatson	mpc = (struct mac_policy_conf *) data;
370100979Srwatson
371128885Srwatson#ifdef MAC_STATIC
372128885Srwatson	if (mac_late) {
373128885Srwatson		printf("mac_policy_modevent: MAC_STATIC and late\n");
374128885Srwatson		return (EBUSY);
375128885Srwatson	}
376128885Srwatson#endif
377128885Srwatson
378100979Srwatson	switch (type) {
379100979Srwatson	case MOD_LOAD:
380100979Srwatson		if (mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_NOTLATE &&
381100979Srwatson		    mac_late) {
382100979Srwatson			printf("mac_policy_modevent: can't load %s policy "
383100979Srwatson			    "after booting\n", mpc->mpc_name);
384100979Srwatson			error = EBUSY;
385100979Srwatson			break;
386100979Srwatson		}
387100979Srwatson		error = mac_policy_register(mpc);
388100979Srwatson		break;
389100979Srwatson	case MOD_UNLOAD:
390100979Srwatson		/* Don't unregister the module if it was never registered. */
391100979Srwatson		if ((mpc->mpc_runtime_flags & MPC_RUNTIME_FLAG_REGISTERED)
392100979Srwatson		    != 0)
393100979Srwatson			error = mac_policy_unregister(mpc);
394100979Srwatson		else
395100979Srwatson			error = 0;
396100979Srwatson		break;
397100979Srwatson	default:
398132199Sphk		error = EOPNOTSUPP;
399100979Srwatson		break;
400100979Srwatson	}
401100979Srwatson
402100979Srwatson	return (error);
403100979Srwatson}
404100979Srwatson
405100979Srwatsonstatic int
406100979Srwatsonmac_policy_register(struct mac_policy_conf *mpc)
407100979Srwatson{
408100979Srwatson	struct mac_policy_conf *tmpc;
409114806Srwatson	int error, slot, static_entry;
410100979Srwatson
411114806Srwatson	error = 0;
412114806Srwatson
413114806Srwatson	/*
414165411Srwatson	 * We don't technically need exclusive access while !mac_late, but
415165411Srwatson	 * hold it for assertion consistency.
416114806Srwatson	 */
417114806Srwatson	mac_policy_grab_exclusive();
418114806Srwatson
419114806Srwatson	/*
420165411Srwatson	 * If the module can potentially be unloaded, or we're loading late,
421165411Srwatson	 * we have to stick it in the non-static list and pay an extra
422165411Srwatson	 * performance overhead.  Otherwise, we can pay a light locking cost
423165411Srwatson	 * and stick it in the static list.
424114806Srwatson	 */
425114806Srwatson	static_entry = (!mac_late &&
426114806Srwatson	    !(mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_UNLOADOK));
427114806Srwatson
428114806Srwatson	if (static_entry) {
429114806Srwatson		LIST_FOREACH(tmpc, &mac_static_policy_list, mpc_list) {
430114806Srwatson			if (strcmp(tmpc->mpc_name, mpc->mpc_name) == 0) {
431114806Srwatson				error = EEXIST;
432114806Srwatson				goto out;
433114806Srwatson			}
434100979Srwatson		}
435114806Srwatson	} else {
436114806Srwatson		LIST_FOREACH(tmpc, &mac_policy_list, mpc_list) {
437114806Srwatson			if (strcmp(tmpc->mpc_name, mpc->mpc_name) == 0) {
438114806Srwatson				error = EEXIST;
439114806Srwatson				goto out;
440114806Srwatson			}
441114806Srwatson		}
442100979Srwatson	}
443100979Srwatson	if (mpc->mpc_field_off != NULL) {
444114846Srwatson		slot = ffs(mac_slot_offsets_free);
445100979Srwatson		if (slot == 0) {
446114806Srwatson			error = ENOMEM;
447114806Srwatson			goto out;
448100979Srwatson		}
449100979Srwatson		slot--;
450114846Srwatson		mac_slot_offsets_free &= ~(1 << slot);
451100979Srwatson		*mpc->mpc_field_off = slot;
452100979Srwatson	}
453100979Srwatson	mpc->mpc_runtime_flags |= MPC_RUNTIME_FLAG_REGISTERED;
454100979Srwatson
455114806Srwatson	/*
456165411Srwatson	 * If we're loading a MAC module after the framework has initialized,
457165411Srwatson	 * it has to go into the dynamic list.  If we're loading it before
458165411Srwatson	 * we've finished initializing, it can go into the static list with
459165411Srwatson	 * weaker locker requirements.
460114806Srwatson	 */
461114806Srwatson	if (static_entry)
462114806Srwatson		LIST_INSERT_HEAD(&mac_static_policy_list, mpc, mpc_list);
463114806Srwatson	else
464114806Srwatson		LIST_INSERT_HEAD(&mac_policy_list, mpc, mpc_list);
465114806Srwatson
466165411Srwatson	/*
467165411Srwatson	 * Per-policy initialization.  Currently, this takes place under the
468165411Srwatson	 * exclusive lock, so policies must not sleep in their init method.
469165411Srwatson	 * In the future, we may want to separate "init" from "start", with
470165411Srwatson	 * "init" occuring without the lock held.  Likewise, on tear-down,
471165411Srwatson	 * breaking out "stop" from "destroy".
472165411Srwatson	 */
473100979Srwatson	if (mpc->mpc_ops->mpo_init != NULL)
474100979Srwatson		(*(mpc->mpc_ops->mpo_init))(mpc);
475113487Srwatson	mac_policy_updateflags();
476100979Srwatson
477100979Srwatson	printf("Security policy loaded: %s (%s)\n", mpc->mpc_fullname,
478100979Srwatson	    mpc->mpc_name);
479100979Srwatson
480114806Srwatsonout:
481114806Srwatson	mac_policy_release_exclusive();
482114806Srwatson	return (error);
483100979Srwatson}
484100979Srwatson
485100979Srwatsonstatic int
486100979Srwatsonmac_policy_unregister(struct mac_policy_conf *mpc)
487100979Srwatson{
488100979Srwatson
489104520Srwatson	/*
490165411Srwatson	 * If we fail the load, we may get a request to unload.  Check to see
491165411Srwatson	 * if we did the run-time registration, and if not, silently succeed.
492104520Srwatson	 */
493114806Srwatson	mac_policy_grab_exclusive();
494104520Srwatson	if ((mpc->mpc_runtime_flags & MPC_RUNTIME_FLAG_REGISTERED) == 0) {
495114806Srwatson		mac_policy_release_exclusive();
496104520Srwatson		return (0);
497104520Srwatson	}
498100979Srwatson#if 0
499100979Srwatson	/*
500100979Srwatson	 * Don't allow unloading modules with private data.
501100979Srwatson	 */
502104520Srwatson	if (mpc->mpc_field_off != NULL) {
503104520Srwatson		MAC_POLICY_LIST_UNLOCK();
504100979Srwatson		return (EBUSY);
505104520Srwatson	}
506100979Srwatson#endif
507104520Srwatson	/*
508165411Srwatson	 * Only allow the unload to proceed if the module is unloadable by
509165411Srwatson	 * its own definition.
510104520Srwatson	 */
511104520Srwatson	if ((mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_UNLOADOK) == 0) {
512114806Srwatson		mac_policy_release_exclusive();
513100979Srwatson		return (EBUSY);
514104520Srwatson	}
515100979Srwatson	if (mpc->mpc_ops->mpo_destroy != NULL)
516100979Srwatson		(*(mpc->mpc_ops->mpo_destroy))(mpc);
517100979Srwatson
518100979Srwatson	LIST_REMOVE(mpc, mpc_list);
519106856Srwatson	mpc->mpc_runtime_flags &= ~MPC_RUNTIME_FLAG_REGISTERED;
520113487Srwatson	mac_policy_updateflags();
521100979Srwatson
522114806Srwatson	mac_policy_release_exclusive();
523114806Srwatson
524100979Srwatson	printf("Security policy unload: %s (%s)\n", mpc->mpc_fullname,
525100979Srwatson	    mpc->mpc_name);
526100979Srwatson
527100979Srwatson	return (0);
528100979Srwatson}
529100979Srwatson
530100979Srwatson/*
531100979Srwatson * Define an error value precedence, and given two arguments, selects the
532100979Srwatson * value with the higher precedence.
533100979Srwatson */
534121371Srwatsonint
535121371Srwatsonmac_error_select(int error1, int error2)
536100979Srwatson{
537100979Srwatson
538100979Srwatson	/* Certain decision-making errors take top priority. */
539100979Srwatson	if (error1 == EDEADLK || error2 == EDEADLK)
540100979Srwatson		return (EDEADLK);
541100979Srwatson
542100979Srwatson	/* Invalid arguments should be reported where possible. */
543100979Srwatson	if (error1 == EINVAL || error2 == EINVAL)
544100979Srwatson		return (EINVAL);
545100979Srwatson
546100979Srwatson	/* Precedence goes to "visibility", with both process and file. */
547100979Srwatson	if (error1 == ESRCH || error2 == ESRCH)
548100979Srwatson		return (ESRCH);
549100979Srwatson
550100979Srwatson	if (error1 == ENOENT || error2 == ENOENT)
551100979Srwatson		return (ENOENT);
552100979Srwatson
553100979Srwatson	/* Precedence goes to DAC/MAC protections. */
554100979Srwatson	if (error1 == EACCES || error2 == EACCES)
555100979Srwatson		return (EACCES);
556100979Srwatson
557100979Srwatson	/* Precedence goes to privilege. */
558100979Srwatson	if (error1 == EPERM || error2 == EPERM)
559100979Srwatson		return (EPERM);
560100979Srwatson
561100979Srwatson	/* Precedence goes to error over success; otherwise, arbitrary. */
562100979Srwatson	if (error1 != 0)
563100979Srwatson		return (error1);
564100979Srwatson	return (error2);
565100979Srwatson}
566100979Srwatson
567121374Srwatsonvoid
568104521Srwatsonmac_init_label(struct label *label)
569104521Srwatson{
570104521Srwatson
571104521Srwatson	bzero(label, sizeof(*label));
572104521Srwatson	label->l_flags = MAC_FLAG_INITIALIZED;
573104521Srwatson}
574104521Srwatson
575121374Srwatsonvoid
576104521Srwatsonmac_destroy_label(struct label *label)
577104521Srwatson{
578104521Srwatson
579104521Srwatson	KASSERT(label->l_flags & MAC_FLAG_INITIALIZED,
580104521Srwatson	    ("destroying uninitialized label"));
581104521Srwatson
582104521Srwatson	bzero(label, sizeof(*label));
583104521Srwatson	/* implicit: label->l_flags &= ~MAC_FLAG_INITIALIZED; */
584104521Srwatson}
585104521Srwatson
586112675Srwatsonint
587105694Srwatsonmac_check_structmac_consistent(struct mac *mac)
588104522Srwatson{
589105694Srwatson
590120582Srwatson	if (mac->m_buflen < 0 ||
591120582Srwatson	    mac->m_buflen > MAC_MAX_LABEL_BUF_LEN)
592105694Srwatson		return (EINVAL);
593105694Srwatson
594105694Srwatson	return (0);
595105694Srwatson}
596105694Srwatson
597122584Srwatson/*
598122584Srwatson * MPSAFE
599122584Srwatson */
600105988Srwatsonint
601105694Srwatson__mac_get_pid(struct thread *td, struct __mac_get_pid_args *uap)
602105694Srwatson{
603105694Srwatson	char *elements, *buffer;
604105694Srwatson	struct mac mac;
605105694Srwatson	struct proc *tproc;
606105694Srwatson	struct ucred *tcred;
607105694Srwatson	int error;
608105694Srwatson
609107849Salfred	error = copyin(uap->mac_p, &mac, sizeof(mac));
610105694Srwatson	if (error)
611105694Srwatson		return (error);
612105694Srwatson
613105694Srwatson	error = mac_check_structmac_consistent(&mac);
614105694Srwatson	if (error)
615105694Srwatson		return (error);
616105694Srwatson
617105694Srwatson	tproc = pfind(uap->pid);
618105694Srwatson	if (tproc == NULL)
619105694Srwatson		return (ESRCH);
620105694Srwatson
621105694Srwatson	tcred = NULL;				/* Satisfy gcc. */
622105694Srwatson	error = p_cansee(td, tproc);
623105694Srwatson	if (error == 0)
624105694Srwatson		tcred = crhold(tproc->p_ucred);
625105694Srwatson	PROC_UNLOCK(tproc);
626105694Srwatson	if (error)
627105694Srwatson		return (error);
628105694Srwatson
629111119Simp	elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
630105694Srwatson	error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
631105694Srwatson	if (error) {
632105694Srwatson		free(elements, M_MACTEMP);
633105694Srwatson		crfree(tcred);
634105694Srwatson		return (error);
635105694Srwatson	}
636105694Srwatson
637111119Simp	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
638122524Srwatson	error = mac_externalize_cred_label(tcred->cr_label, elements,
639122159Srwatson	    buffer, mac.m_buflen);
640105694Srwatson	if (error == 0)
641105694Srwatson		error = copyout(buffer, mac.m_string, strlen(buffer)+1);
642105694Srwatson
643105694Srwatson	free(buffer, M_MACTEMP);
644105694Srwatson	free(elements, M_MACTEMP);
645105694Srwatson	crfree(tcred);
646105694Srwatson	return (error);
647105694Srwatson}
648105694Srwatson
649100979Srwatson/*
650100979Srwatson * MPSAFE
651100979Srwatson */
652100979Srwatsonint
653100894Srwatson__mac_get_proc(struct thread *td, struct __mac_get_proc_args *uap)
654100894Srwatson{
655105694Srwatson	char *elements, *buffer;
656105694Srwatson	struct mac mac;
657100979Srwatson	int error;
658100894Srwatson
659105694Srwatson	error = copyin(uap->mac_p, &mac, sizeof(mac));
660105694Srwatson	if (error)
661105694Srwatson		return (error);
662105694Srwatson
663105694Srwatson	error = mac_check_structmac_consistent(&mac);
664105694Srwatson	if (error)
665105694Srwatson		return (error);
666105694Srwatson
667111119Simp	elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
668105694Srwatson	error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
669105694Srwatson	if (error) {
670105694Srwatson		free(elements, M_MACTEMP);
671105694Srwatson		return (error);
672105694Srwatson	}
673105694Srwatson
674111119Simp	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
675122524Srwatson	error = mac_externalize_cred_label(td->td_ucred->cr_label,
676122159Srwatson	    elements, buffer, mac.m_buflen);
677100979Srwatson	if (error == 0)
678105694Srwatson		error = copyout(buffer, mac.m_string, strlen(buffer)+1);
679100979Srwatson
680105694Srwatson	free(buffer, M_MACTEMP);
681105694Srwatson	free(elements, M_MACTEMP);
682100979Srwatson	return (error);
683100979Srwatson}
684100979Srwatson
685100979Srwatson/*
686100979Srwatson * MPSAFE
687100979Srwatson */
688100979Srwatsonint
689100979Srwatson__mac_set_proc(struct thread *td, struct __mac_set_proc_args *uap)
690100979Srwatson{
691100979Srwatson	struct ucred *newcred, *oldcred;
692122524Srwatson	struct label *intlabel;
693100979Srwatson	struct proc *p;
694105694Srwatson	struct mac mac;
695105694Srwatson	char *buffer;
696100979Srwatson	int error;
697100979Srwatson
698105694Srwatson	error = copyin(uap->mac_p, &mac, sizeof(mac));
699100979Srwatson	if (error)
700100979Srwatson		return (error);
701100979Srwatson
702105694Srwatson	error = mac_check_structmac_consistent(&mac);
703100979Srwatson	if (error)
704100979Srwatson		return (error);
705100979Srwatson
706111119Simp	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
707105694Srwatson	error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
708105694Srwatson	if (error) {
709105694Srwatson		free(buffer, M_MACTEMP);
710105694Srwatson		return (error);
711105694Srwatson	}
712105694Srwatson
713122524Srwatson	intlabel = mac_cred_label_alloc();
714122524Srwatson	error = mac_internalize_cred_label(intlabel, buffer);
715105694Srwatson	free(buffer, M_MACTEMP);
716122524Srwatson	if (error)
717122524Srwatson		goto out;
718105694Srwatson
719100979Srwatson	newcred = crget();
720100979Srwatson
721100979Srwatson	p = td->td_proc;
722100979Srwatson	PROC_LOCK(p);
723100979Srwatson	oldcred = p->p_ucred;
724100979Srwatson
725122524Srwatson	error = mac_check_cred_relabel(oldcred, intlabel);
726100979Srwatson	if (error) {
727100979Srwatson		PROC_UNLOCK(p);
728100979Srwatson		crfree(newcred);
729105694Srwatson		goto out;
730100979Srwatson	}
731100979Srwatson
732100979Srwatson	setsugid(p);
733100979Srwatson	crcopy(newcred, oldcred);
734122524Srwatson	mac_relabel_cred(newcred, intlabel);
735102136Srwatson	p->p_ucred = newcred;
736100979Srwatson
737102136Srwatson	/*
738165411Srwatson	 * Grab additional reference for use while revoking mmaps, prior to
739165411Srwatson	 * releasing the proc lock and sharing the cred.
740102136Srwatson	 */
741102136Srwatson	crhold(newcred);
742100979Srwatson	PROC_UNLOCK(p);
743102136Srwatson
744105694Srwatson	if (mac_enforce_vm) {
745105694Srwatson		mac_cred_mmapped_drop_perms(td, newcred);
746105694Srwatson	}
747102136Srwatson
748102136Srwatson	crfree(newcred);	/* Free revocation reference. */
749100979Srwatson	crfree(oldcred);
750105694Srwatson
751105694Srwatsonout:
752122524Srwatson	mac_cred_label_free(intlabel);
753105694Srwatson	return (error);
754100979Srwatson}
755100979Srwatson
756100979Srwatson/*
757100979Srwatson * MPSAFE
758100979Srwatson */
759100979Srwatsonint
760100979Srwatson__mac_get_fd(struct thread *td, struct __mac_get_fd_args *uap)
761100979Srwatson{
762105694Srwatson	char *elements, *buffer;
763122524Srwatson	struct label *intlabel;
764100979Srwatson	struct file *fp;
765105694Srwatson	struct mac mac;
766100979Srwatson	struct vnode *vp;
767100979Srwatson	struct pipe *pipe;
768122820Srwatson	struct socket *so;
769105694Srwatson	short label_type;
770150914Scsjp	int vfslocked, error;
771100979Srwatson
772105694Srwatson	error = copyin(uap->mac_p, &mac, sizeof(mac));
773105694Srwatson	if (error)
774105694Srwatson		return (error);
775100979Srwatson
776105694Srwatson	error = mac_check_structmac_consistent(&mac);
777105694Srwatson	if (error)
778105694Srwatson		return (error);
779105694Srwatson
780111119Simp	elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
781105694Srwatson	error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
782105694Srwatson	if (error) {
783105694Srwatson		free(elements, M_MACTEMP);
784105694Srwatson		return (error);
785105694Srwatson	}
786105694Srwatson
787111119Simp	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
788107849Salfred	error = fget(td, uap->fd, &fp);
789100979Srwatson	if (error)
790100979Srwatson		goto out;
791100979Srwatson
792105694Srwatson	label_type = fp->f_type;
793100979Srwatson	switch (fp->f_type) {
794100979Srwatson	case DTYPE_FIFO:
795100979Srwatson	case DTYPE_VNODE:
796116678Sphk		vp = fp->f_vnode;
797122524Srwatson		intlabel = mac_vnode_label_alloc();
798150914Scsjp		vfslocked = VFS_LOCK_GIANT(vp->v_mount);
799100979Srwatson		vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
800122524Srwatson		mac_copy_vnode_label(vp->v_label, intlabel);
801100979Srwatson		VOP_UNLOCK(vp, 0, td);
802150914Scsjp		VFS_UNLOCK_GIANT(vfslocked);
803122584Srwatson		error = mac_externalize_vnode_label(intlabel, elements,
804122584Srwatson		    buffer, mac.m_buflen);
805122584Srwatson		mac_vnode_label_free(intlabel);
806122584Srwatson		break;
807105694Srwatson
808100979Srwatson	case DTYPE_PIPE:
809109153Sdillon		pipe = fp->f_data;
810122524Srwatson		intlabel = mac_pipe_label_alloc();
811105694Srwatson		PIPE_LOCK(pipe);
812125293Srwatson		mac_copy_pipe_label(pipe->pipe_pair->pp_label, intlabel);
813105694Srwatson		PIPE_UNLOCK(pipe);
814122524Srwatson		error = mac_externalize_pipe_label(intlabel, elements,
815122159Srwatson		    buffer, mac.m_buflen);
816122524Srwatson		mac_pipe_label_free(intlabel);
817105694Srwatson		break;
818122584Srwatson
819122820Srwatson	case DTYPE_SOCKET:
820122820Srwatson		so = fp->f_data;
821122820Srwatson		intlabel = mac_socket_label_alloc(M_WAITOK);
822145160Srwatson		NET_LOCK_GIANT();
823145160Srwatson		SOCK_LOCK(so);
824122820Srwatson		mac_copy_socket_label(so->so_label, intlabel);
825145160Srwatson		SOCK_UNLOCK(so);
826145160Srwatson		NET_UNLOCK_GIANT();
827122820Srwatson		error = mac_externalize_socket_label(intlabel, elements,
828122820Srwatson		    buffer, mac.m_buflen);
829122820Srwatson		mac_socket_label_free(intlabel);
830122820Srwatson		break;
831122820Srwatson
832105694Srwatson	default:
833122584Srwatson		error = EINVAL;
834105694Srwatson	}
835122584Srwatson	fdrop(fp, td);
836100979Srwatson	if (error == 0)
837105694Srwatson		error = copyout(buffer, mac.m_string, strlen(buffer)+1);
838100979Srwatson
839105694Srwatsonout:
840105694Srwatson	free(buffer, M_MACTEMP);
841105694Srwatson	free(elements, M_MACTEMP);
842100979Srwatson	return (error);
843100979Srwatson}
844100979Srwatson
845100979Srwatson/*
846100979Srwatson * MPSAFE
847100979Srwatson */
848100979Srwatsonint
849100979Srwatson__mac_get_file(struct thread *td, struct __mac_get_file_args *uap)
850100979Srwatson{
851105694Srwatson	char *elements, *buffer;
852100979Srwatson	struct nameidata nd;
853122524Srwatson	struct label *intlabel;
854105694Srwatson	struct mac mac;
855150914Scsjp	int vfslocked, error;
856100979Srwatson
857105694Srwatson	error = copyin(uap->mac_p, &mac, sizeof(mac));
858105694Srwatson	if (error)
859105694Srwatson		return (error);
860105694Srwatson
861105694Srwatson	error = mac_check_structmac_consistent(&mac);
862105694Srwatson	if (error)
863105694Srwatson		return (error);
864105694Srwatson
865111119Simp	elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
866105694Srwatson	error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
867105694Srwatson	if (error) {
868105694Srwatson		free(elements, M_MACTEMP);
869105694Srwatson		return (error);
870105694Srwatson	}
871105694Srwatson
872111119Simp	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
873150914Scsjp	NDINIT(&nd, LOOKUP, MPSAFE | LOCKLEAF | FOLLOW, UIO_USERSPACE,
874150914Scsjp	    uap->path_p, td);
875100979Srwatson	error = namei(&nd);
876100979Srwatson	if (error)
877100979Srwatson		goto out;
878100979Srwatson
879122524Srwatson	intlabel = mac_vnode_label_alloc();
880150914Scsjp	vfslocked = NDHASGIANT(&nd);
881122524Srwatson	mac_copy_vnode_label(nd.ni_vp->v_label, intlabel);
882122524Srwatson	error = mac_externalize_vnode_label(intlabel, elements, buffer,
883122159Srwatson	    mac.m_buflen);
884105694Srwatson
885100979Srwatson	NDFREE(&nd, 0);
886150914Scsjp	VFS_UNLOCK_GIANT(vfslocked);
887122524Srwatson	mac_vnode_label_free(intlabel);
888105694Srwatson	if (error == 0)
889105694Srwatson		error = copyout(buffer, mac.m_string, strlen(buffer)+1);
890105694Srwatson
891105694Srwatsonout:
892105694Srwatson	free(buffer, M_MACTEMP);
893105694Srwatson	free(elements, M_MACTEMP);
894105694Srwatson
895105694Srwatson	return (error);
896105694Srwatson}
897105694Srwatson
898105694Srwatson/*
899105694Srwatson * MPSAFE
900105694Srwatson */
901105694Srwatsonint
902105694Srwatson__mac_get_link(struct thread *td, struct __mac_get_link_args *uap)
903105694Srwatson{
904105694Srwatson	char *elements, *buffer;
905105694Srwatson	struct nameidata nd;
906122524Srwatson	struct label *intlabel;
907105694Srwatson	struct mac mac;
908150914Scsjp	int vfslocked, error;
909105694Srwatson
910105694Srwatson	error = copyin(uap->mac_p, &mac, sizeof(mac));
911100979Srwatson	if (error)
912105694Srwatson		return (error);
913105694Srwatson
914105694Srwatson	error = mac_check_structmac_consistent(&mac);
915105694Srwatson	if (error)
916105694Srwatson		return (error);
917105694Srwatson
918111119Simp	elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
919105694Srwatson	error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
920105694Srwatson	if (error) {
921105694Srwatson		free(elements, M_MACTEMP);
922105694Srwatson		return (error);
923105694Srwatson	}
924105694Srwatson
925111119Simp	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
926150914Scsjp	NDINIT(&nd, LOOKUP, MPSAFE | LOCKLEAF | NOFOLLOW, UIO_USERSPACE,
927150914Scsjp	    uap->path_p, td);
928105694Srwatson	error = namei(&nd);
929105694Srwatson	if (error)
930100979Srwatson		goto out;
931100979Srwatson
932122524Srwatson	intlabel = mac_vnode_label_alloc();
933150914Scsjp	vfslocked = NDHASGIANT(&nd);
934122524Srwatson	mac_copy_vnode_label(nd.ni_vp->v_label, intlabel);
935122524Srwatson	error = mac_externalize_vnode_label(intlabel, elements, buffer,
936122159Srwatson	    mac.m_buflen);
937105694Srwatson	NDFREE(&nd, 0);
938150914Scsjp	VFS_UNLOCK_GIANT(vfslocked);
939122524Srwatson	mac_vnode_label_free(intlabel);
940100979Srwatson
941105694Srwatson	if (error == 0)
942105694Srwatson		error = copyout(buffer, mac.m_string, strlen(buffer)+1);
943105694Srwatson
944100979Srwatsonout:
945105694Srwatson	free(buffer, M_MACTEMP);
946105694Srwatson	free(elements, M_MACTEMP);
947105694Srwatson
948100979Srwatson	return (error);
949100979Srwatson}
950100979Srwatson
951100979Srwatson/*
952100979Srwatson * MPSAFE
953100979Srwatson */
954100979Srwatsonint
955100979Srwatson__mac_set_fd(struct thread *td, struct __mac_set_fd_args *uap)
956100979Srwatson{
957122524Srwatson	struct label *intlabel;
958105694Srwatson	struct pipe *pipe;
959122820Srwatson	struct socket *so;
960100979Srwatson	struct file *fp;
961100979Srwatson	struct mount *mp;
962100979Srwatson	struct vnode *vp;
963105694Srwatson	struct mac mac;
964105694Srwatson	char *buffer;
965150914Scsjp	int error, vfslocked;
966100979Srwatson
967105694Srwatson	error = copyin(uap->mac_p, &mac, sizeof(mac));
968100979Srwatson	if (error)
969105694Srwatson		return (error);
970100979Srwatson
971105694Srwatson	error = mac_check_structmac_consistent(&mac);
972100979Srwatson	if (error)
973105694Srwatson		return (error);
974100979Srwatson
975111119Simp	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
976105694Srwatson	error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
977105694Srwatson	if (error) {
978105694Srwatson		free(buffer, M_MACTEMP);
979105694Srwatson		return (error);
980105694Srwatson	}
981105694Srwatson
982107849Salfred	error = fget(td, uap->fd, &fp);
983100979Srwatson	if (error)
984105694Srwatson		goto out;
985100979Srwatson
986100979Srwatson	switch (fp->f_type) {
987100979Srwatson	case DTYPE_FIFO:
988100979Srwatson	case DTYPE_VNODE:
989122524Srwatson		intlabel = mac_vnode_label_alloc();
990122524Srwatson		error = mac_internalize_vnode_label(intlabel, buffer);
991105694Srwatson		if (error) {
992122524Srwatson			mac_vnode_label_free(intlabel);
993105694Srwatson			break;
994105694Srwatson		}
995116678Sphk		vp = fp->f_vnode;
996150914Scsjp		vfslocked = VFS_LOCK_GIANT(vp->v_mount);
997100979Srwatson		error = vn_start_write(vp, &mp, V_WAIT | PCATCH);
998105694Srwatson		if (error != 0) {
999150914Scsjp			VFS_UNLOCK_GIANT(vfslocked);
1000122524Srwatson			mac_vnode_label_free(intlabel);
1001100979Srwatson			break;
1002105694Srwatson		}
1003100979Srwatson		vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
1004122524Srwatson		error = vn_setlabel(vp, intlabel, td->td_ucred);
1005100979Srwatson		VOP_UNLOCK(vp, 0, td);
1006100979Srwatson		vn_finished_write(mp);
1007150914Scsjp		VFS_UNLOCK_GIANT(vfslocked);
1008122524Srwatson		mac_vnode_label_free(intlabel);
1009100979Srwatson		break;
1010105694Srwatson
1011100979Srwatson	case DTYPE_PIPE:
1012122524Srwatson		intlabel = mac_pipe_label_alloc();
1013122524Srwatson		error = mac_internalize_pipe_label(intlabel, buffer);
1014105694Srwatson		if (error == 0) {
1015109153Sdillon			pipe = fp->f_data;
1016105694Srwatson			PIPE_LOCK(pipe);
1017125293Srwatson			error = mac_pipe_label_set(td->td_ucred,
1018125293Srwatson			    pipe->pipe_pair, intlabel);
1019105694Srwatson			PIPE_UNLOCK(pipe);
1020105694Srwatson		}
1021122524Srwatson		mac_pipe_label_free(intlabel);
1022100979Srwatson		break;
1023105694Srwatson
1024122820Srwatson	case DTYPE_SOCKET:
1025122820Srwatson		intlabel = mac_socket_label_alloc(M_WAITOK);
1026122820Srwatson		error = mac_internalize_socket_label(intlabel, buffer);
1027122820Srwatson		if (error == 0) {
1028122820Srwatson			so = fp->f_data;
1029145160Srwatson			NET_LOCK_GIANT();
1030122820Srwatson			error = mac_socket_label_set(td->td_ucred, so,
1031122820Srwatson			    intlabel);
1032145160Srwatson			NET_UNLOCK_GIANT();
1033122820Srwatson		}
1034122820Srwatson		mac_socket_label_free(intlabel);
1035122820Srwatson		break;
1036122820Srwatson
1037100979Srwatson	default:
1038100979Srwatson		error = EINVAL;
1039100979Srwatson	}
1040100979Srwatson	fdrop(fp, td);
1041105694Srwatsonout:
1042105694Srwatson	free(buffer, M_MACTEMP);
1043100979Srwatson	return (error);
1044100979Srwatson}
1045100979Srwatson
1046100979Srwatson/*
1047100979Srwatson * MPSAFE
1048100979Srwatson */
1049100979Srwatsonint
1050100979Srwatson__mac_set_file(struct thread *td, struct __mac_set_file_args *uap)
1051100979Srwatson{
1052122524Srwatson	struct label *intlabel;
1053100979Srwatson	struct nameidata nd;
1054100979Srwatson	struct mount *mp;
1055105694Srwatson	struct mac mac;
1056105694Srwatson	char *buffer;
1057150914Scsjp	int vfslocked, error;
1058100979Srwatson
1059105694Srwatson	error = copyin(uap->mac_p, &mac, sizeof(mac));
1060100979Srwatson	if (error)
1061105694Srwatson		return (error);
1062100979Srwatson
1063105694Srwatson	error = mac_check_structmac_consistent(&mac);
1064100979Srwatson	if (error)
1065105694Srwatson		return (error);
1066100979Srwatson
1067111119Simp	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
1068105694Srwatson	error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
1069105694Srwatson	if (error) {
1070105694Srwatson		free(buffer, M_MACTEMP);
1071105694Srwatson		return (error);
1072105694Srwatson	}
1073105694Srwatson
1074122524Srwatson	intlabel = mac_vnode_label_alloc();
1075122524Srwatson	error = mac_internalize_vnode_label(intlabel, buffer);
1076105694Srwatson	free(buffer, M_MACTEMP);
1077122524Srwatson	if (error)
1078122524Srwatson		goto out;
1079105694Srwatson
1080150914Scsjp	NDINIT(&nd, LOOKUP, MPSAFE | LOCKLEAF | FOLLOW, UIO_USERSPACE,
1081150914Scsjp	    uap->path_p, td);
1082100979Srwatson	error = namei(&nd);
1083150914Scsjp	vfslocked = NDHASGIANT(&nd);
1084105694Srwatson	if (error == 0) {
1085105694Srwatson		error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH);
1086156893Stegge		if (error == 0) {
1087122524Srwatson			error = vn_setlabel(nd.ni_vp, intlabel,
1088105694Srwatson			    td->td_ucred);
1089156893Stegge			vn_finished_write(mp);
1090156893Stegge		}
1091105694Srwatson	}
1092105694Srwatson
1093105694Srwatson	NDFREE(&nd, 0);
1094150914Scsjp	VFS_UNLOCK_GIANT(vfslocked);
1095122524Srwatsonout:
1096122524Srwatson	mac_vnode_label_free(intlabel);
1097105694Srwatson	return (error);
1098105694Srwatson}
1099105694Srwatson
1100105694Srwatson/*
1101105694Srwatson * MPSAFE
1102105694Srwatson */
1103105694Srwatsonint
1104105694Srwatson__mac_set_link(struct thread *td, struct __mac_set_link_args *uap)
1105105694Srwatson{
1106122524Srwatson	struct label *intlabel;
1107105694Srwatson	struct nameidata nd;
1108105694Srwatson	struct mount *mp;
1109105694Srwatson	struct mac mac;
1110105694Srwatson	char *buffer;
1111150914Scsjp	int vfslocked, error;
1112105694Srwatson
1113105694Srwatson	error = copyin(uap->mac_p, &mac, sizeof(mac));
1114100979Srwatson	if (error)
1115105694Srwatson		return (error);
1116105694Srwatson
1117105694Srwatson	error = mac_check_structmac_consistent(&mac);
1118100979Srwatson	if (error)
1119105694Srwatson		return (error);
1120100979Srwatson
1121111119Simp	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
1122105694Srwatson	error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
1123105694Srwatson	if (error) {
1124105694Srwatson		free(buffer, M_MACTEMP);
1125105694Srwatson		return (error);
1126105694Srwatson	}
1127105694Srwatson
1128122524Srwatson	intlabel = mac_vnode_label_alloc();
1129122524Srwatson	error = mac_internalize_vnode_label(intlabel, buffer);
1130105694Srwatson	free(buffer, M_MACTEMP);
1131122524Srwatson	if (error)
1132122524Srwatson		goto out;
1133105694Srwatson
1134150914Scsjp	NDINIT(&nd, LOOKUP, MPSAFE | LOCKLEAF | NOFOLLOW, UIO_USERSPACE,
1135150914Scsjp	    uap->path_p, td);
1136105694Srwatson	error = namei(&nd);
1137150914Scsjp	vfslocked = NDHASGIANT(&nd);
1138105694Srwatson	if (error == 0) {
1139105694Srwatson		error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH);
1140156893Stegge		if (error == 0) {
1141122524Srwatson			error = vn_setlabel(nd.ni_vp, intlabel,
1142105694Srwatson			    td->td_ucred);
1143156893Stegge			vn_finished_write(mp);
1144156893Stegge		}
1145105694Srwatson	}
1146105694Srwatson
1147100979Srwatson	NDFREE(&nd, 0);
1148150914Scsjp	VFS_UNLOCK_GIANT(vfslocked);
1149122524Srwatsonout:
1150122524Srwatson	mac_vnode_label_free(intlabel);
1151100979Srwatson	return (error);
1152100979Srwatson}
1153100979Srwatson
1154105694Srwatson/*
1155105694Srwatson * MPSAFE
1156105694Srwatson */
1157102123Srwatsonint
1158102123Srwatsonmac_syscall(struct thread *td, struct mac_syscall_args *uap)
1159102123Srwatson{
1160102123Srwatson	struct mac_policy_conf *mpc;
1161102123Srwatson	char target[MAC_MAX_POLICY_NAME];
1162114806Srwatson	int entrycount, error;
1163102123Srwatson
1164107849Salfred	error = copyinstr(uap->policy, target, sizeof(target), NULL);
1165102123Srwatson	if (error)
1166102123Srwatson		return (error);
1167102123Srwatson
1168102123Srwatson	error = ENOSYS;
1169119494Srwatson	LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) {
1170102123Srwatson		if (strcmp(mpc->mpc_name, target) == 0 &&
1171102123Srwatson		    mpc->mpc_ops->mpo_syscall != NULL) {
1172102123Srwatson			error = mpc->mpc_ops->mpo_syscall(td,
1173107849Salfred			    uap->call, uap->arg);
1174102123Srwatson			goto out;
1175102123Srwatson		}
1176102123Srwatson	}
1177102123Srwatson
1178114806Srwatson	if ((entrycount = mac_policy_list_conditional_busy()) != 0) {
1179114806Srwatson		LIST_FOREACH(mpc, &mac_policy_list, mpc_list) {
1180114806Srwatson			if (strcmp(mpc->mpc_name, target) == 0 &&
1181114806Srwatson			    mpc->mpc_ops->mpo_syscall != NULL) {
1182114806Srwatson				error = mpc->mpc_ops->mpo_syscall(td,
1183114806Srwatson				    uap->call, uap->arg);
1184114806Srwatson				break;
1185114806Srwatson			}
1186114806Srwatson		}
1187114806Srwatson		mac_policy_list_unbusy();
1188114806Srwatson	}
1189102123Srwatsonout:
1190102123Srwatson	return (error);
1191102123Srwatson}
1192102123Srwatson
1193100979SrwatsonSYSINIT(mac, SI_SUB_MAC, SI_ORDER_FIRST, mac_init, NULL);
1194100979SrwatsonSYSINIT(mac_late, SI_SUB_MAC_LATE, SI_ORDER_FIRST, mac_late_init, NULL);
1195100979Srwatson
1196100979Srwatson#else /* !MAC */
1197100979Srwatson
1198100979Srwatsonint
1199105694Srwatson__mac_get_pid(struct thread *td, struct __mac_get_pid_args *uap)
1200105694Srwatson{
1201105694Srwatson
1202105694Srwatson	return (ENOSYS);
1203105694Srwatson}
1204105694Srwatson
1205105694Srwatsonint
1206100979Srwatson__mac_get_proc(struct thread *td, struct __mac_get_proc_args *uap)
1207100979Srwatson{
1208100979Srwatson
1209100894Srwatson	return (ENOSYS);
1210100894Srwatson}
1211100894Srwatson
1212100894Srwatsonint
1213100894Srwatson__mac_set_proc(struct thread *td, struct __mac_set_proc_args *uap)
1214100894Srwatson{
1215100894Srwatson
1216100894Srwatson	return (ENOSYS);
1217100894Srwatson}
1218100894Srwatson
1219100894Srwatsonint
1220100894Srwatson__mac_get_fd(struct thread *td, struct __mac_get_fd_args *uap)
1221100894Srwatson{
1222100894Srwatson
1223100894Srwatson	return (ENOSYS);
1224100894Srwatson}
1225100894Srwatson
1226100894Srwatsonint
1227100894Srwatson__mac_get_file(struct thread *td, struct __mac_get_file_args *uap)
1228100894Srwatson{
1229100894Srwatson
1230100894Srwatson	return (ENOSYS);
1231100894Srwatson}
1232100894Srwatson
1233100894Srwatsonint
1234105694Srwatson__mac_get_link(struct thread *td, struct __mac_get_link_args *uap)
1235105694Srwatson{
1236105694Srwatson
1237105694Srwatson	return (ENOSYS);
1238105694Srwatson}
1239105694Srwatson
1240105694Srwatsonint
1241100894Srwatson__mac_set_fd(struct thread *td, struct __mac_set_fd_args *uap)
1242100894Srwatson{
1243100894Srwatson
1244100894Srwatson	return (ENOSYS);
1245100894Srwatson}
1246100894Srwatson
1247100894Srwatsonint
1248100894Srwatson__mac_set_file(struct thread *td, struct __mac_set_file_args *uap)
1249100894Srwatson{
1250100894Srwatson
1251100894Srwatson	return (ENOSYS);
1252100894Srwatson}
1253100979Srwatson
1254102123Srwatsonint
1255105694Srwatson__mac_set_link(struct thread *td, struct __mac_set_link_args *uap)
1256105694Srwatson{
1257105694Srwatson
1258105694Srwatson	return (ENOSYS);
1259105694Srwatson}
1260105694Srwatson
1261105694Srwatsonint
1262102123Srwatsonmac_syscall(struct thread *td, struct mac_syscall_args *uap)
1263102123Srwatson{
1264102123Srwatson
1265102123Srwatson	return (ENOSYS);
1266102123Srwatson}
1267102123Srwatson
1268128901Srwatson#endif /* !MAC */
1269