mac_syscalls.c revision 165469
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_syscalls.c 165469 2006-12-22 23:34:47Z 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 <fs/devfs/devfs.h>
84100979Srwatson
85100979Srwatson#include <net/bpfdesc.h>
86100979Srwatson#include <net/if.h>
87100979Srwatson#include <net/if_var.h>
88100979Srwatson
89100979Srwatson#include <netinet/in.h>
90100979Srwatson#include <netinet/ip_var.h>
91100979Srwatson
92163606Srwatson#include <security/mac/mac_framework.h>
93121374Srwatson#include <security/mac/mac_internal.h>
94165469Srwatson#include <security/mac/mac_policy.h>
95121374Srwatson
96100979Srwatson#ifdef MAC
97100979Srwatson
98101712Srwatson/*
99101712Srwatson * Declare that the kernel provides MAC support, version 1.  This permits
100101712Srwatson * modules to refuse to be loaded if the necessary support isn't present,
101101712Srwatson * even if it's pre-boot.
102101712Srwatson */
103147983SrwatsonMODULE_VERSION(kernel_mac_support, 3);
104101712Srwatson
105100979SrwatsonSYSCTL_NODE(_security, OID_AUTO, mac, CTLFLAG_RW, 0,
106100979Srwatson    "TrustedBSD MAC policy controls");
107104517Srwatson
108165411Srwatson/*
109165411Srwatson * Labels consist of a indexed set of "slots", which are allocated policies
110165411Srwatson * as required.  The MAC Framework maintains a bitmask of slots allocated so
111165411Srwatson * far to prevent reuse.  Slots cannot be reused, as the MAC Framework
112165411Srwatson * guarantees that newly allocated slots in labels will be NULL unless
113165411Srwatson * otherwise initialized, and because we do not have a mechanism to garbage
114165411Srwatson * collect slots on policy unload.  As labeled policies tend to be statically
115165411Srwatson * loaded during boot, and not frequently unloaded and reloaded, this is not
116165411Srwatson * generally an issue.
117165411Srwatson */
118114846Srwatson#if MAC_MAX_SLOTS > 32
119114846Srwatson#error "MAC_MAX_SLOTS too large"
120100979Srwatson#endif
121105497Srwatson
122114846Srwatsonstatic unsigned int mac_max_slots = MAC_MAX_SLOTS;
123114846Srwatsonstatic unsigned int mac_slot_offsets_free = (1 << MAC_MAX_SLOTS) - 1;
124114846SrwatsonSYSCTL_UINT(_security_mac, OID_AUTO, max_slots, CTLFLAG_RD,
125114846Srwatson    &mac_max_slots, 0, "");
126100979Srwatson
127105959Srwatson/*
128105959Srwatson * Has the kernel started generating labeled objects yet?  All read/write
129105959Srwatson * access to this variable is serialized during the boot process.  Following
130105959Srwatson * the end of serialization, we don't update this flag; no locking.
131105959Srwatson */
132121372Srwatsonint	mac_late = 0;
133100979Srwatson
134105988Srwatson/*
135165411Srwatson * Flag to indicate whether or not we should allocate label storage for new
136165411Srwatson * mbufs.  Since most dynamic policies we currently work with don't rely on
137165411Srwatson * mbuf labeling, try to avoid paying the cost of mtag allocation unless
138165411Srwatson * specifically notified of interest.  One result of this is that if a
139165411Srwatson * dynamically loaded policy requests mbuf labels, it must be able to deal
140165411Srwatson * with a NULL label being returned on any mbufs that were already in flight
141165411Srwatson * when the policy was loaded.  Since the policy already has to deal with
142165411Srwatson * uninitialized labels, this probably won't be a problem.  Note: currently
143165411Srwatson * no locking.  Will this be a problem?
144165411Srwatson *
145165411Srwatson * In the future, we may want to allow objects to request labeling on a per-
146165411Srwatson * object type basis, rather than globally for all objects.
147113487Srwatson */
148118308Srwatson#ifndef MAC_ALWAYS_LABEL_MBUF
149121372Srwatsonint	mac_labelmbufs = 0;
150113487Srwatson#endif
151113487Srwatson
152100979Srwatsonstatic int	mac_policy_register(struct mac_policy_conf *mpc);
153100979Srwatsonstatic int	mac_policy_unregister(struct mac_policy_conf *mpc);
154100979Srwatson
155105694SrwatsonMALLOC_DEFINE(M_MACTEMP, "mactemp", "MAC temporary label storage");
156100979Srwatson
157100979Srwatson/*
158165411Srwatson * mac_static_policy_list holds a list of policy modules that are not loaded
159165411Srwatson * while the system is "live", and cannot be unloaded.  These policies can be
160165411Srwatson * invoked without holding the busy count.
161114806Srwatson *
162114806Srwatson * mac_policy_list stores the list of dynamic policies.  A busy count is
163165411Srwatson * maintained for the list, stored in mac_policy_busy.  The busy count is
164165411Srwatson * protected by mac_policy_mtx; the list may be modified only while the busy
165165411Srwatson * count is 0, requiring that the lock be held to prevent new references to
166165411Srwatson * the list from being acquired.  For almost all operations, incrementing the
167165411Srwatson * busy count is sufficient to guarantee consistency, as the list cannot be
168165411Srwatson * modified while the busy count is elevated.  For a few special operations
169165411Srwatson * involving a change to the list of active policies, the mtx itself must be
170165411Srwatson * held.  A condition variable, mac_policy_cv, is used to signal potential
171165411Srwatson * exclusive consumers that they should try to acquire the lock if a first
172165411Srwatson * attempt at exclusive access fails.
173165411Srwatson *
174165411Srwatson * This design intentionally avoids fairness, and may starve attempts to
175165411Srwatson * acquire an exclusive lock on a busy system.  This is required because we
176165411Srwatson * do not ever want acquiring a read reference to perform an unbounded length
177165411Srwatson * sleep.  Read references are acquired in ithreads, network isrs, etc, and
178165411Srwatson * any unbounded blocking could lead quickly to deadlock.
179165411Srwatson *
180165411Srwatson * Another reason for never blocking on read references is that the MAC
181165411Srwatson * Framework may recurse: if a policy calls a VOP, for example, this might
182165411Srwatson * lead to vnode life cycle operations (such as init/destroy).
183100979Srwatson */
184128885Srwatson#ifndef MAC_STATIC
185114806Srwatsonstatic struct mtx mac_policy_mtx;
186114806Srwatsonstatic struct cv mac_policy_cv;
187114806Srwatsonstatic int mac_policy_count;
188128885Srwatson#endif
189121372Srwatsonstruct mac_policy_list_head mac_policy_list;
190121372Srwatsonstruct mac_policy_list_head mac_static_policy_list;
191100979Srwatson
192106856Srwatson/*
193165411Srwatson * We manually invoke WITNESS_WARN() to allow Witness to generate warnings
194165411Srwatson * even if we don't end up ever triggering the wait at run-time.  The
195165411Srwatson * consumer of the exclusive interface must not hold any locks (other than
196165411Srwatson * potentially Giant) since we may sleep for long (potentially indefinite)
197165411Srwatson * periods of time waiting for the framework to become quiescent so that a
198165411Srwatson * policy list change may be made.
199106856Srwatson */
200121372Srwatsonvoid
201114806Srwatsonmac_policy_grab_exclusive(void)
202114806Srwatson{
203122454Srwatson
204128885Srwatson#ifndef MAC_STATIC
205137072Srwatson	if (!mac_late)
206137072Srwatson		return;
207137072Srwatson
208114806Srwatson	WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL,
209114806Srwatson 	    "mac_policy_grab_exclusive() at %s:%d", __FILE__, __LINE__);
210114806Srwatson	mtx_lock(&mac_policy_mtx);
211114806Srwatson	while (mac_policy_count != 0)
212114806Srwatson		cv_wait(&mac_policy_cv, &mac_policy_mtx);
213128885Srwatson#endif
214114806Srwatson}
215106856Srwatson
216121372Srwatsonvoid
217114806Srwatsonmac_policy_assert_exclusive(void)
218114806Srwatson{
219122454Srwatson
220128885Srwatson#ifndef MAC_STATIC
221137072Srwatson	if (!mac_late)
222137072Srwatson		return;
223137072Srwatson
224114806Srwatson	mtx_assert(&mac_policy_mtx, MA_OWNED);
225114806Srwatson	KASSERT(mac_policy_count == 0,
226114806Srwatson	    ("mac_policy_assert_exclusive(): not exclusive"));
227128885Srwatson#endif
228114806Srwatson}
229113487Srwatson
230121372Srwatsonvoid
231114806Srwatsonmac_policy_release_exclusive(void)
232114806Srwatson{
233100979Srwatson
234128885Srwatson#ifndef MAC_STATIC
235137072Srwatson	if (!mac_late)
236137072Srwatson		return;
237137072Srwatson
238114806Srwatson	KASSERT(mac_policy_count == 0,
239114806Srwatson	    ("mac_policy_release_exclusive(): not exclusive"));
240114806Srwatson	mtx_unlock(&mac_policy_mtx);
241114806Srwatson	cv_signal(&mac_policy_cv);
242128885Srwatson#endif
243114806Srwatson}
244100979Srwatson
245121372Srwatsonvoid
246114806Srwatsonmac_policy_list_busy(void)
247114806Srwatson{
248122454Srwatson
249128885Srwatson#ifndef MAC_STATIC
250137072Srwatson	if (!mac_late)
251137072Srwatson		return;
252137072Srwatson
253114806Srwatson	mtx_lock(&mac_policy_mtx);
254114806Srwatson	mac_policy_count++;
255114806Srwatson	mtx_unlock(&mac_policy_mtx);
256128885Srwatson#endif
257114806Srwatson}
258114806Srwatson
259121372Srwatsonint
260114806Srwatsonmac_policy_list_conditional_busy(void)
261114806Srwatson{
262128885Srwatson#ifndef MAC_STATIC
263114806Srwatson	int ret;
264114806Srwatson
265137072Srwatson	if (!mac_late)
266137072Srwatson		return (1);
267137072Srwatson
268114806Srwatson	mtx_lock(&mac_policy_mtx);
269114806Srwatson	if (!LIST_EMPTY(&mac_policy_list)) {
270114806Srwatson		mac_policy_count++;
271114806Srwatson		ret = 1;
272114806Srwatson	} else
273114806Srwatson		ret = 0;
274114806Srwatson	mtx_unlock(&mac_policy_mtx);
275114806Srwatson	return (ret);
276128885Srwatson#else
277137072Srwatson	if (!mac_late)
278137072Srwatson		return (1);
279137072Srwatson
280128885Srwatson	return (1);
281128885Srwatson#endif
282114806Srwatson}
283114806Srwatson
284121372Srwatsonvoid
285114806Srwatsonmac_policy_list_unbusy(void)
286114806Srwatson{
287122454Srwatson
288128885Srwatson#ifndef MAC_STATIC
289137072Srwatson	if (!mac_late)
290137072Srwatson		return;
291137072Srwatson
292114806Srwatson	mtx_lock(&mac_policy_mtx);
293114806Srwatson	mac_policy_count--;
294114806Srwatson	KASSERT(mac_policy_count >= 0, ("MAC_POLICY_LIST_LOCK"));
295114806Srwatson	if (mac_policy_count == 0)
296114806Srwatson		cv_signal(&mac_policy_cv);
297114806Srwatson	mtx_unlock(&mac_policy_mtx);
298128885Srwatson#endif
299114806Srwatson}
300114806Srwatson
301100979Srwatson/*
302100979Srwatson * Initialize the MAC subsystem, including appropriate SMP locks.
303100979Srwatson */
304100979Srwatsonstatic void
305100979Srwatsonmac_init(void)
306100979Srwatson{
307100979Srwatson
308114806Srwatson	LIST_INIT(&mac_static_policy_list);
309100979Srwatson	LIST_INIT(&mac_policy_list);
310122524Srwatson	mac_labelzone_init();
311114806Srwatson
312128885Srwatson#ifndef MAC_STATIC
313114806Srwatson	mtx_init(&mac_policy_mtx, "mac_policy_mtx", NULL, MTX_DEF);
314114806Srwatson	cv_init(&mac_policy_cv, "mac_policy_cv");
315128885Srwatson#endif
316100979Srwatson}
317100979Srwatson
318100979Srwatson/*
319165411Srwatson * For the purposes of modules that want to know if they were loaded "early",
320165411Srwatson * set the mac_late flag once we've processed modules either linked into the
321165411Srwatson * kernel, or loaded before the kernel startup.
322100979Srwatson */
323100979Srwatsonstatic void
324100979Srwatsonmac_late_init(void)
325100979Srwatson{
326100979Srwatson
327100979Srwatson	mac_late = 1;
328100979Srwatson}
329100979Srwatson
330100979Srwatson/*
331113487Srwatson * After the policy list has changed, walk the list to update any global
332118308Srwatson * flags.  Currently, we support only one flag, and it's conditionally
333165411Srwatson * defined; as a result, the entire function is conditional.  Eventually, the
334165411Srwatson * #else case might also iterate across the policies.
335113487Srwatson */
336113487Srwatsonstatic void
337113487Srwatsonmac_policy_updateflags(void)
338113487Srwatson{
339118308Srwatson#ifndef MAC_ALWAYS_LABEL_MBUF
340113487Srwatson	struct mac_policy_conf *tmpc;
341113487Srwatson	int labelmbufs;
342113487Srwatson
343114806Srwatson	mac_policy_assert_exclusive();
344113487Srwatson
345113487Srwatson	labelmbufs = 0;
346114806Srwatson	LIST_FOREACH(tmpc, &mac_static_policy_list, mpc_list) {
347114806Srwatson		if (tmpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_LABELMBUFS)
348114806Srwatson			labelmbufs++;
349114806Srwatson	}
350113487Srwatson	LIST_FOREACH(tmpc, &mac_policy_list, mpc_list) {
351113487Srwatson		if (tmpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_LABELMBUFS)
352113487Srwatson			labelmbufs++;
353113487Srwatson	}
354113487Srwatson	mac_labelmbufs = (labelmbufs != 0);
355113487Srwatson#endif
356113487Srwatson}
357113487Srwatson
358113487Srwatson/*
359100979Srwatson * Allow MAC policy modules to register during boot, etc.
360100979Srwatson */
361100894Srwatsonint
362100979Srwatsonmac_policy_modevent(module_t mod, int type, void *data)
363100979Srwatson{
364100979Srwatson	struct mac_policy_conf *mpc;
365100979Srwatson	int error;
366100979Srwatson
367100979Srwatson	error = 0;
368100979Srwatson	mpc = (struct mac_policy_conf *) data;
369100979Srwatson
370128885Srwatson#ifdef MAC_STATIC
371128885Srwatson	if (mac_late) {
372128885Srwatson		printf("mac_policy_modevent: MAC_STATIC and late\n");
373128885Srwatson		return (EBUSY);
374128885Srwatson	}
375128885Srwatson#endif
376128885Srwatson
377100979Srwatson	switch (type) {
378100979Srwatson	case MOD_LOAD:
379100979Srwatson		if (mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_NOTLATE &&
380100979Srwatson		    mac_late) {
381100979Srwatson			printf("mac_policy_modevent: can't load %s policy "
382100979Srwatson			    "after booting\n", mpc->mpc_name);
383100979Srwatson			error = EBUSY;
384100979Srwatson			break;
385100979Srwatson		}
386100979Srwatson		error = mac_policy_register(mpc);
387100979Srwatson		break;
388100979Srwatson	case MOD_UNLOAD:
389100979Srwatson		/* Don't unregister the module if it was never registered. */
390100979Srwatson		if ((mpc->mpc_runtime_flags & MPC_RUNTIME_FLAG_REGISTERED)
391100979Srwatson		    != 0)
392100979Srwatson			error = mac_policy_unregister(mpc);
393100979Srwatson		else
394100979Srwatson			error = 0;
395100979Srwatson		break;
396100979Srwatson	default:
397132199Sphk		error = EOPNOTSUPP;
398100979Srwatson		break;
399100979Srwatson	}
400100979Srwatson
401100979Srwatson	return (error);
402100979Srwatson}
403100979Srwatson
404100979Srwatsonstatic int
405100979Srwatsonmac_policy_register(struct mac_policy_conf *mpc)
406100979Srwatson{
407100979Srwatson	struct mac_policy_conf *tmpc;
408114806Srwatson	int error, slot, static_entry;
409100979Srwatson
410114806Srwatson	error = 0;
411114806Srwatson
412114806Srwatson	/*
413165411Srwatson	 * We don't technically need exclusive access while !mac_late, but
414165411Srwatson	 * hold it for assertion consistency.
415114806Srwatson	 */
416114806Srwatson	mac_policy_grab_exclusive();
417114806Srwatson
418114806Srwatson	/*
419165411Srwatson	 * If the module can potentially be unloaded, or we're loading late,
420165411Srwatson	 * we have to stick it in the non-static list and pay an extra
421165411Srwatson	 * performance overhead.  Otherwise, we can pay a light locking cost
422165411Srwatson	 * and stick it in the static list.
423114806Srwatson	 */
424114806Srwatson	static_entry = (!mac_late &&
425114806Srwatson	    !(mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_UNLOADOK));
426114806Srwatson
427114806Srwatson	if (static_entry) {
428114806Srwatson		LIST_FOREACH(tmpc, &mac_static_policy_list, mpc_list) {
429114806Srwatson			if (strcmp(tmpc->mpc_name, mpc->mpc_name) == 0) {
430114806Srwatson				error = EEXIST;
431114806Srwatson				goto out;
432114806Srwatson			}
433100979Srwatson		}
434114806Srwatson	} else {
435114806Srwatson		LIST_FOREACH(tmpc, &mac_policy_list, mpc_list) {
436114806Srwatson			if (strcmp(tmpc->mpc_name, mpc->mpc_name) == 0) {
437114806Srwatson				error = EEXIST;
438114806Srwatson				goto out;
439114806Srwatson			}
440114806Srwatson		}
441100979Srwatson	}
442100979Srwatson	if (mpc->mpc_field_off != NULL) {
443114846Srwatson		slot = ffs(mac_slot_offsets_free);
444100979Srwatson		if (slot == 0) {
445114806Srwatson			error = ENOMEM;
446114806Srwatson			goto out;
447100979Srwatson		}
448100979Srwatson		slot--;
449114846Srwatson		mac_slot_offsets_free &= ~(1 << slot);
450100979Srwatson		*mpc->mpc_field_off = slot;
451100979Srwatson	}
452100979Srwatson	mpc->mpc_runtime_flags |= MPC_RUNTIME_FLAG_REGISTERED;
453100979Srwatson
454114806Srwatson	/*
455165411Srwatson	 * If we're loading a MAC module after the framework has initialized,
456165411Srwatson	 * it has to go into the dynamic list.  If we're loading it before
457165411Srwatson	 * we've finished initializing, it can go into the static list with
458165411Srwatson	 * weaker locker requirements.
459114806Srwatson	 */
460114806Srwatson	if (static_entry)
461114806Srwatson		LIST_INSERT_HEAD(&mac_static_policy_list, mpc, mpc_list);
462114806Srwatson	else
463114806Srwatson		LIST_INSERT_HEAD(&mac_policy_list, mpc, mpc_list);
464114806Srwatson
465165411Srwatson	/*
466165411Srwatson	 * Per-policy initialization.  Currently, this takes place under the
467165411Srwatson	 * exclusive lock, so policies must not sleep in their init method.
468165411Srwatson	 * In the future, we may want to separate "init" from "start", with
469165411Srwatson	 * "init" occuring without the lock held.  Likewise, on tear-down,
470165411Srwatson	 * breaking out "stop" from "destroy".
471165411Srwatson	 */
472100979Srwatson	if (mpc->mpc_ops->mpo_init != NULL)
473100979Srwatson		(*(mpc->mpc_ops->mpo_init))(mpc);
474113487Srwatson	mac_policy_updateflags();
475100979Srwatson
476100979Srwatson	printf("Security policy loaded: %s (%s)\n", mpc->mpc_fullname,
477100979Srwatson	    mpc->mpc_name);
478100979Srwatson
479114806Srwatsonout:
480114806Srwatson	mac_policy_release_exclusive();
481114806Srwatson	return (error);
482100979Srwatson}
483100979Srwatson
484100979Srwatsonstatic int
485100979Srwatsonmac_policy_unregister(struct mac_policy_conf *mpc)
486100979Srwatson{
487100979Srwatson
488104520Srwatson	/*
489165411Srwatson	 * If we fail the load, we may get a request to unload.  Check to see
490165411Srwatson	 * if we did the run-time registration, and if not, silently succeed.
491104520Srwatson	 */
492114806Srwatson	mac_policy_grab_exclusive();
493104520Srwatson	if ((mpc->mpc_runtime_flags & MPC_RUNTIME_FLAG_REGISTERED) == 0) {
494114806Srwatson		mac_policy_release_exclusive();
495104520Srwatson		return (0);
496104520Srwatson	}
497100979Srwatson#if 0
498100979Srwatson	/*
499100979Srwatson	 * Don't allow unloading modules with private data.
500100979Srwatson	 */
501104520Srwatson	if (mpc->mpc_field_off != NULL) {
502104520Srwatson		MAC_POLICY_LIST_UNLOCK();
503100979Srwatson		return (EBUSY);
504104520Srwatson	}
505100979Srwatson#endif
506104520Srwatson	/*
507165411Srwatson	 * Only allow the unload to proceed if the module is unloadable by
508165411Srwatson	 * its own definition.
509104520Srwatson	 */
510104520Srwatson	if ((mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_UNLOADOK) == 0) {
511114806Srwatson		mac_policy_release_exclusive();
512100979Srwatson		return (EBUSY);
513104520Srwatson	}
514100979Srwatson	if (mpc->mpc_ops->mpo_destroy != NULL)
515100979Srwatson		(*(mpc->mpc_ops->mpo_destroy))(mpc);
516100979Srwatson
517100979Srwatson	LIST_REMOVE(mpc, mpc_list);
518106856Srwatson	mpc->mpc_runtime_flags &= ~MPC_RUNTIME_FLAG_REGISTERED;
519113487Srwatson	mac_policy_updateflags();
520100979Srwatson
521114806Srwatson	mac_policy_release_exclusive();
522114806Srwatson
523100979Srwatson	printf("Security policy unload: %s (%s)\n", mpc->mpc_fullname,
524100979Srwatson	    mpc->mpc_name);
525100979Srwatson
526100979Srwatson	return (0);
527100979Srwatson}
528100979Srwatson
529100979Srwatson/*
530100979Srwatson * Define an error value precedence, and given two arguments, selects the
531100979Srwatson * value with the higher precedence.
532100979Srwatson */
533121371Srwatsonint
534121371Srwatsonmac_error_select(int error1, int error2)
535100979Srwatson{
536100979Srwatson
537100979Srwatson	/* Certain decision-making errors take top priority. */
538100979Srwatson	if (error1 == EDEADLK || error2 == EDEADLK)
539100979Srwatson		return (EDEADLK);
540100979Srwatson
541100979Srwatson	/* Invalid arguments should be reported where possible. */
542100979Srwatson	if (error1 == EINVAL || error2 == EINVAL)
543100979Srwatson		return (EINVAL);
544100979Srwatson
545100979Srwatson	/* Precedence goes to "visibility", with both process and file. */
546100979Srwatson	if (error1 == ESRCH || error2 == ESRCH)
547100979Srwatson		return (ESRCH);
548100979Srwatson
549100979Srwatson	if (error1 == ENOENT || error2 == ENOENT)
550100979Srwatson		return (ENOENT);
551100979Srwatson
552100979Srwatson	/* Precedence goes to DAC/MAC protections. */
553100979Srwatson	if (error1 == EACCES || error2 == EACCES)
554100979Srwatson		return (EACCES);
555100979Srwatson
556100979Srwatson	/* Precedence goes to privilege. */
557100979Srwatson	if (error1 == EPERM || error2 == EPERM)
558100979Srwatson		return (EPERM);
559100979Srwatson
560100979Srwatson	/* Precedence goes to error over success; otherwise, arbitrary. */
561100979Srwatson	if (error1 != 0)
562100979Srwatson		return (error1);
563100979Srwatson	return (error2);
564100979Srwatson}
565100979Srwatson
566121374Srwatsonvoid
567104521Srwatsonmac_init_label(struct label *label)
568104521Srwatson{
569104521Srwatson
570104521Srwatson	bzero(label, sizeof(*label));
571104521Srwatson	label->l_flags = MAC_FLAG_INITIALIZED;
572104521Srwatson}
573104521Srwatson
574121374Srwatsonvoid
575104521Srwatsonmac_destroy_label(struct label *label)
576104521Srwatson{
577104521Srwatson
578104521Srwatson	KASSERT(label->l_flags & MAC_FLAG_INITIALIZED,
579104521Srwatson	    ("destroying uninitialized label"));
580104521Srwatson
581104521Srwatson	bzero(label, sizeof(*label));
582104521Srwatson	/* implicit: label->l_flags &= ~MAC_FLAG_INITIALIZED; */
583104521Srwatson}
584104521Srwatson
585112675Srwatsonint
586105694Srwatsonmac_check_structmac_consistent(struct mac *mac)
587104522Srwatson{
588105694Srwatson
589120582Srwatson	if (mac->m_buflen < 0 ||
590120582Srwatson	    mac->m_buflen > MAC_MAX_LABEL_BUF_LEN)
591105694Srwatson		return (EINVAL);
592105694Srwatson
593105694Srwatson	return (0);
594105694Srwatson}
595105694Srwatson
596122584Srwatson/*
597122584Srwatson * MPSAFE
598122584Srwatson */
599105988Srwatsonint
600105694Srwatson__mac_get_pid(struct thread *td, struct __mac_get_pid_args *uap)
601105694Srwatson{
602105694Srwatson	char *elements, *buffer;
603105694Srwatson	struct mac mac;
604105694Srwatson	struct proc *tproc;
605105694Srwatson	struct ucred *tcred;
606105694Srwatson	int error;
607105694Srwatson
608107849Salfred	error = copyin(uap->mac_p, &mac, sizeof(mac));
609105694Srwatson	if (error)
610105694Srwatson		return (error);
611105694Srwatson
612105694Srwatson	error = mac_check_structmac_consistent(&mac);
613105694Srwatson	if (error)
614105694Srwatson		return (error);
615105694Srwatson
616105694Srwatson	tproc = pfind(uap->pid);
617105694Srwatson	if (tproc == NULL)
618105694Srwatson		return (ESRCH);
619105694Srwatson
620105694Srwatson	tcred = NULL;				/* Satisfy gcc. */
621105694Srwatson	error = p_cansee(td, tproc);
622105694Srwatson	if (error == 0)
623105694Srwatson		tcred = crhold(tproc->p_ucred);
624105694Srwatson	PROC_UNLOCK(tproc);
625105694Srwatson	if (error)
626105694Srwatson		return (error);
627105694Srwatson
628111119Simp	elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
629105694Srwatson	error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
630105694Srwatson	if (error) {
631105694Srwatson		free(elements, M_MACTEMP);
632105694Srwatson		crfree(tcred);
633105694Srwatson		return (error);
634105694Srwatson	}
635105694Srwatson
636111119Simp	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
637122524Srwatson	error = mac_externalize_cred_label(tcred->cr_label, elements,
638122159Srwatson	    buffer, mac.m_buflen);
639105694Srwatson	if (error == 0)
640105694Srwatson		error = copyout(buffer, mac.m_string, strlen(buffer)+1);
641105694Srwatson
642105694Srwatson	free(buffer, M_MACTEMP);
643105694Srwatson	free(elements, M_MACTEMP);
644105694Srwatson	crfree(tcred);
645105694Srwatson	return (error);
646105694Srwatson}
647105694Srwatson
648100979Srwatson/*
649100979Srwatson * MPSAFE
650100979Srwatson */
651100979Srwatsonint
652100894Srwatson__mac_get_proc(struct thread *td, struct __mac_get_proc_args *uap)
653100894Srwatson{
654105694Srwatson	char *elements, *buffer;
655105694Srwatson	struct mac mac;
656100979Srwatson	int error;
657100894Srwatson
658105694Srwatson	error = copyin(uap->mac_p, &mac, sizeof(mac));
659105694Srwatson	if (error)
660105694Srwatson		return (error);
661105694Srwatson
662105694Srwatson	error = mac_check_structmac_consistent(&mac);
663105694Srwatson	if (error)
664105694Srwatson		return (error);
665105694Srwatson
666111119Simp	elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
667105694Srwatson	error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
668105694Srwatson	if (error) {
669105694Srwatson		free(elements, M_MACTEMP);
670105694Srwatson		return (error);
671105694Srwatson	}
672105694Srwatson
673111119Simp	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
674122524Srwatson	error = mac_externalize_cred_label(td->td_ucred->cr_label,
675122159Srwatson	    elements, buffer, mac.m_buflen);
676100979Srwatson	if (error == 0)
677105694Srwatson		error = copyout(buffer, mac.m_string, strlen(buffer)+1);
678100979Srwatson
679105694Srwatson	free(buffer, M_MACTEMP);
680105694Srwatson	free(elements, M_MACTEMP);
681100979Srwatson	return (error);
682100979Srwatson}
683100979Srwatson
684100979Srwatson/*
685100979Srwatson * MPSAFE
686100979Srwatson */
687100979Srwatsonint
688100979Srwatson__mac_set_proc(struct thread *td, struct __mac_set_proc_args *uap)
689100979Srwatson{
690100979Srwatson	struct ucred *newcred, *oldcred;
691122524Srwatson	struct label *intlabel;
692100979Srwatson	struct proc *p;
693105694Srwatson	struct mac mac;
694105694Srwatson	char *buffer;
695100979Srwatson	int error;
696100979Srwatson
697105694Srwatson	error = copyin(uap->mac_p, &mac, sizeof(mac));
698100979Srwatson	if (error)
699100979Srwatson		return (error);
700100979Srwatson
701105694Srwatson	error = mac_check_structmac_consistent(&mac);
702100979Srwatson	if (error)
703100979Srwatson		return (error);
704100979Srwatson
705111119Simp	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
706105694Srwatson	error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
707105694Srwatson	if (error) {
708105694Srwatson		free(buffer, M_MACTEMP);
709105694Srwatson		return (error);
710105694Srwatson	}
711105694Srwatson
712122524Srwatson	intlabel = mac_cred_label_alloc();
713122524Srwatson	error = mac_internalize_cred_label(intlabel, buffer);
714105694Srwatson	free(buffer, M_MACTEMP);
715122524Srwatson	if (error)
716122524Srwatson		goto out;
717105694Srwatson
718100979Srwatson	newcred = crget();
719100979Srwatson
720100979Srwatson	p = td->td_proc;
721100979Srwatson	PROC_LOCK(p);
722100979Srwatson	oldcred = p->p_ucred;
723100979Srwatson
724122524Srwatson	error = mac_check_cred_relabel(oldcred, intlabel);
725100979Srwatson	if (error) {
726100979Srwatson		PROC_UNLOCK(p);
727100979Srwatson		crfree(newcred);
728105694Srwatson		goto out;
729100979Srwatson	}
730100979Srwatson
731100979Srwatson	setsugid(p);
732100979Srwatson	crcopy(newcred, oldcred);
733122524Srwatson	mac_relabel_cred(newcred, intlabel);
734102136Srwatson	p->p_ucred = newcred;
735100979Srwatson
736102136Srwatson	/*
737165411Srwatson	 * Grab additional reference for use while revoking mmaps, prior to
738165411Srwatson	 * releasing the proc lock and sharing the cred.
739102136Srwatson	 */
740102136Srwatson	crhold(newcred);
741100979Srwatson	PROC_UNLOCK(p);
742102136Srwatson
743165433Srwatson	mac_cred_mmapped_drop_perms(td, newcred);
744102136Srwatson
745102136Srwatson	crfree(newcred);	/* Free revocation reference. */
746100979Srwatson	crfree(oldcred);
747105694Srwatson
748105694Srwatsonout:
749122524Srwatson	mac_cred_label_free(intlabel);
750105694Srwatson	return (error);
751100979Srwatson}
752100979Srwatson
753100979Srwatson/*
754100979Srwatson * MPSAFE
755100979Srwatson */
756100979Srwatsonint
757100979Srwatson__mac_get_fd(struct thread *td, struct __mac_get_fd_args *uap)
758100979Srwatson{
759105694Srwatson	char *elements, *buffer;
760122524Srwatson	struct label *intlabel;
761100979Srwatson	struct file *fp;
762105694Srwatson	struct mac mac;
763100979Srwatson	struct vnode *vp;
764100979Srwatson	struct pipe *pipe;
765122820Srwatson	struct socket *so;
766105694Srwatson	short label_type;
767150914Scsjp	int vfslocked, error;
768100979Srwatson
769105694Srwatson	error = copyin(uap->mac_p, &mac, sizeof(mac));
770105694Srwatson	if (error)
771105694Srwatson		return (error);
772100979Srwatson
773105694Srwatson	error = mac_check_structmac_consistent(&mac);
774105694Srwatson	if (error)
775105694Srwatson		return (error);
776105694Srwatson
777111119Simp	elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
778105694Srwatson	error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
779105694Srwatson	if (error) {
780105694Srwatson		free(elements, M_MACTEMP);
781105694Srwatson		return (error);
782105694Srwatson	}
783105694Srwatson
784111119Simp	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
785107849Salfred	error = fget(td, uap->fd, &fp);
786100979Srwatson	if (error)
787100979Srwatson		goto out;
788100979Srwatson
789105694Srwatson	label_type = fp->f_type;
790100979Srwatson	switch (fp->f_type) {
791100979Srwatson	case DTYPE_FIFO:
792100979Srwatson	case DTYPE_VNODE:
793116678Sphk		vp = fp->f_vnode;
794122524Srwatson		intlabel = mac_vnode_label_alloc();
795150914Scsjp		vfslocked = VFS_LOCK_GIANT(vp->v_mount);
796100979Srwatson		vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
797122524Srwatson		mac_copy_vnode_label(vp->v_label, intlabel);
798100979Srwatson		VOP_UNLOCK(vp, 0, td);
799150914Scsjp		VFS_UNLOCK_GIANT(vfslocked);
800122584Srwatson		error = mac_externalize_vnode_label(intlabel, elements,
801122584Srwatson		    buffer, mac.m_buflen);
802122584Srwatson		mac_vnode_label_free(intlabel);
803122584Srwatson		break;
804105694Srwatson
805100979Srwatson	case DTYPE_PIPE:
806109153Sdillon		pipe = fp->f_data;
807122524Srwatson		intlabel = mac_pipe_label_alloc();
808105694Srwatson		PIPE_LOCK(pipe);
809125293Srwatson		mac_copy_pipe_label(pipe->pipe_pair->pp_label, intlabel);
810105694Srwatson		PIPE_UNLOCK(pipe);
811122524Srwatson		error = mac_externalize_pipe_label(intlabel, elements,
812122159Srwatson		    buffer, mac.m_buflen);
813122524Srwatson		mac_pipe_label_free(intlabel);
814105694Srwatson		break;
815122584Srwatson
816122820Srwatson	case DTYPE_SOCKET:
817122820Srwatson		so = fp->f_data;
818122820Srwatson		intlabel = mac_socket_label_alloc(M_WAITOK);
819145160Srwatson		NET_LOCK_GIANT();
820145160Srwatson		SOCK_LOCK(so);
821122820Srwatson		mac_copy_socket_label(so->so_label, intlabel);
822145160Srwatson		SOCK_UNLOCK(so);
823145160Srwatson		NET_UNLOCK_GIANT();
824122820Srwatson		error = mac_externalize_socket_label(intlabel, elements,
825122820Srwatson		    buffer, mac.m_buflen);
826122820Srwatson		mac_socket_label_free(intlabel);
827122820Srwatson		break;
828122820Srwatson
829105694Srwatson	default:
830122584Srwatson		error = EINVAL;
831105694Srwatson	}
832122584Srwatson	fdrop(fp, td);
833100979Srwatson	if (error == 0)
834105694Srwatson		error = copyout(buffer, mac.m_string, strlen(buffer)+1);
835100979Srwatson
836105694Srwatsonout:
837105694Srwatson	free(buffer, M_MACTEMP);
838105694Srwatson	free(elements, M_MACTEMP);
839100979Srwatson	return (error);
840100979Srwatson}
841100979Srwatson
842100979Srwatson/*
843100979Srwatson * MPSAFE
844100979Srwatson */
845100979Srwatsonint
846100979Srwatson__mac_get_file(struct thread *td, struct __mac_get_file_args *uap)
847100979Srwatson{
848105694Srwatson	char *elements, *buffer;
849100979Srwatson	struct nameidata nd;
850122524Srwatson	struct label *intlabel;
851105694Srwatson	struct mac mac;
852150914Scsjp	int vfslocked, error;
853100979Srwatson
854105694Srwatson	error = copyin(uap->mac_p, &mac, sizeof(mac));
855105694Srwatson	if (error)
856105694Srwatson		return (error);
857105694Srwatson
858105694Srwatson	error = mac_check_structmac_consistent(&mac);
859105694Srwatson	if (error)
860105694Srwatson		return (error);
861105694Srwatson
862111119Simp	elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
863105694Srwatson	error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
864105694Srwatson	if (error) {
865105694Srwatson		free(elements, M_MACTEMP);
866105694Srwatson		return (error);
867105694Srwatson	}
868105694Srwatson
869111119Simp	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
870150914Scsjp	NDINIT(&nd, LOOKUP, MPSAFE | LOCKLEAF | FOLLOW, UIO_USERSPACE,
871150914Scsjp	    uap->path_p, td);
872100979Srwatson	error = namei(&nd);
873100979Srwatson	if (error)
874100979Srwatson		goto out;
875100979Srwatson
876122524Srwatson	intlabel = mac_vnode_label_alloc();
877150914Scsjp	vfslocked = NDHASGIANT(&nd);
878122524Srwatson	mac_copy_vnode_label(nd.ni_vp->v_label, intlabel);
879122524Srwatson	error = mac_externalize_vnode_label(intlabel, elements, buffer,
880122159Srwatson	    mac.m_buflen);
881105694Srwatson
882100979Srwatson	NDFREE(&nd, 0);
883150914Scsjp	VFS_UNLOCK_GIANT(vfslocked);
884122524Srwatson	mac_vnode_label_free(intlabel);
885105694Srwatson	if (error == 0)
886105694Srwatson		error = copyout(buffer, mac.m_string, strlen(buffer)+1);
887105694Srwatson
888105694Srwatsonout:
889105694Srwatson	free(buffer, M_MACTEMP);
890105694Srwatson	free(elements, M_MACTEMP);
891105694Srwatson
892105694Srwatson	return (error);
893105694Srwatson}
894105694Srwatson
895105694Srwatson/*
896105694Srwatson * MPSAFE
897105694Srwatson */
898105694Srwatsonint
899105694Srwatson__mac_get_link(struct thread *td, struct __mac_get_link_args *uap)
900105694Srwatson{
901105694Srwatson	char *elements, *buffer;
902105694Srwatson	struct nameidata nd;
903122524Srwatson	struct label *intlabel;
904105694Srwatson	struct mac mac;
905150914Scsjp	int vfslocked, error;
906105694Srwatson
907105694Srwatson	error = copyin(uap->mac_p, &mac, sizeof(mac));
908100979Srwatson	if (error)
909105694Srwatson		return (error);
910105694Srwatson
911105694Srwatson	error = mac_check_structmac_consistent(&mac);
912105694Srwatson	if (error)
913105694Srwatson		return (error);
914105694Srwatson
915111119Simp	elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
916105694Srwatson	error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
917105694Srwatson	if (error) {
918105694Srwatson		free(elements, M_MACTEMP);
919105694Srwatson		return (error);
920105694Srwatson	}
921105694Srwatson
922111119Simp	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
923150914Scsjp	NDINIT(&nd, LOOKUP, MPSAFE | LOCKLEAF | NOFOLLOW, UIO_USERSPACE,
924150914Scsjp	    uap->path_p, td);
925105694Srwatson	error = namei(&nd);
926105694Srwatson	if (error)
927100979Srwatson		goto out;
928100979Srwatson
929122524Srwatson	intlabel = mac_vnode_label_alloc();
930150914Scsjp	vfslocked = NDHASGIANT(&nd);
931122524Srwatson	mac_copy_vnode_label(nd.ni_vp->v_label, intlabel);
932122524Srwatson	error = mac_externalize_vnode_label(intlabel, elements, buffer,
933122159Srwatson	    mac.m_buflen);
934105694Srwatson	NDFREE(&nd, 0);
935150914Scsjp	VFS_UNLOCK_GIANT(vfslocked);
936122524Srwatson	mac_vnode_label_free(intlabel);
937100979Srwatson
938105694Srwatson	if (error == 0)
939105694Srwatson		error = copyout(buffer, mac.m_string, strlen(buffer)+1);
940105694Srwatson
941100979Srwatsonout:
942105694Srwatson	free(buffer, M_MACTEMP);
943105694Srwatson	free(elements, M_MACTEMP);
944105694Srwatson
945100979Srwatson	return (error);
946100979Srwatson}
947100979Srwatson
948100979Srwatson/*
949100979Srwatson * MPSAFE
950100979Srwatson */
951100979Srwatsonint
952100979Srwatson__mac_set_fd(struct thread *td, struct __mac_set_fd_args *uap)
953100979Srwatson{
954122524Srwatson	struct label *intlabel;
955105694Srwatson	struct pipe *pipe;
956122820Srwatson	struct socket *so;
957100979Srwatson	struct file *fp;
958100979Srwatson	struct mount *mp;
959100979Srwatson	struct vnode *vp;
960105694Srwatson	struct mac mac;
961105694Srwatson	char *buffer;
962150914Scsjp	int error, vfslocked;
963100979Srwatson
964105694Srwatson	error = copyin(uap->mac_p, &mac, sizeof(mac));
965100979Srwatson	if (error)
966105694Srwatson		return (error);
967100979Srwatson
968105694Srwatson	error = mac_check_structmac_consistent(&mac);
969100979Srwatson	if (error)
970105694Srwatson		return (error);
971100979Srwatson
972111119Simp	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
973105694Srwatson	error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
974105694Srwatson	if (error) {
975105694Srwatson		free(buffer, M_MACTEMP);
976105694Srwatson		return (error);
977105694Srwatson	}
978105694Srwatson
979107849Salfred	error = fget(td, uap->fd, &fp);
980100979Srwatson	if (error)
981105694Srwatson		goto out;
982100979Srwatson
983100979Srwatson	switch (fp->f_type) {
984100979Srwatson	case DTYPE_FIFO:
985100979Srwatson	case DTYPE_VNODE:
986122524Srwatson		intlabel = mac_vnode_label_alloc();
987122524Srwatson		error = mac_internalize_vnode_label(intlabel, buffer);
988105694Srwatson		if (error) {
989122524Srwatson			mac_vnode_label_free(intlabel);
990105694Srwatson			break;
991105694Srwatson		}
992116678Sphk		vp = fp->f_vnode;
993150914Scsjp		vfslocked = VFS_LOCK_GIANT(vp->v_mount);
994100979Srwatson		error = vn_start_write(vp, &mp, V_WAIT | PCATCH);
995105694Srwatson		if (error != 0) {
996150914Scsjp			VFS_UNLOCK_GIANT(vfslocked);
997122524Srwatson			mac_vnode_label_free(intlabel);
998100979Srwatson			break;
999105694Srwatson		}
1000100979Srwatson		vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
1001122524Srwatson		error = vn_setlabel(vp, intlabel, td->td_ucred);
1002100979Srwatson		VOP_UNLOCK(vp, 0, td);
1003100979Srwatson		vn_finished_write(mp);
1004150914Scsjp		VFS_UNLOCK_GIANT(vfslocked);
1005122524Srwatson		mac_vnode_label_free(intlabel);
1006100979Srwatson		break;
1007105694Srwatson
1008100979Srwatson	case DTYPE_PIPE:
1009122524Srwatson		intlabel = mac_pipe_label_alloc();
1010122524Srwatson		error = mac_internalize_pipe_label(intlabel, buffer);
1011105694Srwatson		if (error == 0) {
1012109153Sdillon			pipe = fp->f_data;
1013105694Srwatson			PIPE_LOCK(pipe);
1014125293Srwatson			error = mac_pipe_label_set(td->td_ucred,
1015125293Srwatson			    pipe->pipe_pair, intlabel);
1016105694Srwatson			PIPE_UNLOCK(pipe);
1017105694Srwatson		}
1018122524Srwatson		mac_pipe_label_free(intlabel);
1019100979Srwatson		break;
1020105694Srwatson
1021122820Srwatson	case DTYPE_SOCKET:
1022122820Srwatson		intlabel = mac_socket_label_alloc(M_WAITOK);
1023122820Srwatson		error = mac_internalize_socket_label(intlabel, buffer);
1024122820Srwatson		if (error == 0) {
1025122820Srwatson			so = fp->f_data;
1026145160Srwatson			NET_LOCK_GIANT();
1027122820Srwatson			error = mac_socket_label_set(td->td_ucred, so,
1028122820Srwatson			    intlabel);
1029145160Srwatson			NET_UNLOCK_GIANT();
1030122820Srwatson		}
1031122820Srwatson		mac_socket_label_free(intlabel);
1032122820Srwatson		break;
1033122820Srwatson
1034100979Srwatson	default:
1035100979Srwatson		error = EINVAL;
1036100979Srwatson	}
1037100979Srwatson	fdrop(fp, td);
1038105694Srwatsonout:
1039105694Srwatson	free(buffer, M_MACTEMP);
1040100979Srwatson	return (error);
1041100979Srwatson}
1042100979Srwatson
1043100979Srwatson/*
1044100979Srwatson * MPSAFE
1045100979Srwatson */
1046100979Srwatsonint
1047100979Srwatson__mac_set_file(struct thread *td, struct __mac_set_file_args *uap)
1048100979Srwatson{
1049122524Srwatson	struct label *intlabel;
1050100979Srwatson	struct nameidata nd;
1051100979Srwatson	struct mount *mp;
1052105694Srwatson	struct mac mac;
1053105694Srwatson	char *buffer;
1054150914Scsjp	int vfslocked, error;
1055100979Srwatson
1056105694Srwatson	error = copyin(uap->mac_p, &mac, sizeof(mac));
1057100979Srwatson	if (error)
1058105694Srwatson		return (error);
1059100979Srwatson
1060105694Srwatson	error = mac_check_structmac_consistent(&mac);
1061100979Srwatson	if (error)
1062105694Srwatson		return (error);
1063100979Srwatson
1064111119Simp	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
1065105694Srwatson	error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
1066105694Srwatson	if (error) {
1067105694Srwatson		free(buffer, M_MACTEMP);
1068105694Srwatson		return (error);
1069105694Srwatson	}
1070105694Srwatson
1071122524Srwatson	intlabel = mac_vnode_label_alloc();
1072122524Srwatson	error = mac_internalize_vnode_label(intlabel, buffer);
1073105694Srwatson	free(buffer, M_MACTEMP);
1074122524Srwatson	if (error)
1075122524Srwatson		goto out;
1076105694Srwatson
1077150914Scsjp	NDINIT(&nd, LOOKUP, MPSAFE | LOCKLEAF | FOLLOW, UIO_USERSPACE,
1078150914Scsjp	    uap->path_p, td);
1079100979Srwatson	error = namei(&nd);
1080150914Scsjp	vfslocked = NDHASGIANT(&nd);
1081105694Srwatson	if (error == 0) {
1082105694Srwatson		error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH);
1083156893Stegge		if (error == 0) {
1084122524Srwatson			error = vn_setlabel(nd.ni_vp, intlabel,
1085105694Srwatson			    td->td_ucred);
1086156893Stegge			vn_finished_write(mp);
1087156893Stegge		}
1088105694Srwatson	}
1089105694Srwatson
1090105694Srwatson	NDFREE(&nd, 0);
1091150914Scsjp	VFS_UNLOCK_GIANT(vfslocked);
1092122524Srwatsonout:
1093122524Srwatson	mac_vnode_label_free(intlabel);
1094105694Srwatson	return (error);
1095105694Srwatson}
1096105694Srwatson
1097105694Srwatson/*
1098105694Srwatson * MPSAFE
1099105694Srwatson */
1100105694Srwatsonint
1101105694Srwatson__mac_set_link(struct thread *td, struct __mac_set_link_args *uap)
1102105694Srwatson{
1103122524Srwatson	struct label *intlabel;
1104105694Srwatson	struct nameidata nd;
1105105694Srwatson	struct mount *mp;
1106105694Srwatson	struct mac mac;
1107105694Srwatson	char *buffer;
1108150914Scsjp	int vfslocked, error;
1109105694Srwatson
1110105694Srwatson	error = copyin(uap->mac_p, &mac, sizeof(mac));
1111100979Srwatson	if (error)
1112105694Srwatson		return (error);
1113105694Srwatson
1114105694Srwatson	error = mac_check_structmac_consistent(&mac);
1115100979Srwatson	if (error)
1116105694Srwatson		return (error);
1117100979Srwatson
1118111119Simp	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
1119105694Srwatson	error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
1120105694Srwatson	if (error) {
1121105694Srwatson		free(buffer, M_MACTEMP);
1122105694Srwatson		return (error);
1123105694Srwatson	}
1124105694Srwatson
1125122524Srwatson	intlabel = mac_vnode_label_alloc();
1126122524Srwatson	error = mac_internalize_vnode_label(intlabel, buffer);
1127105694Srwatson	free(buffer, M_MACTEMP);
1128122524Srwatson	if (error)
1129122524Srwatson		goto out;
1130105694Srwatson
1131150914Scsjp	NDINIT(&nd, LOOKUP, MPSAFE | LOCKLEAF | NOFOLLOW, UIO_USERSPACE,
1132150914Scsjp	    uap->path_p, td);
1133105694Srwatson	error = namei(&nd);
1134150914Scsjp	vfslocked = NDHASGIANT(&nd);
1135105694Srwatson	if (error == 0) {
1136105694Srwatson		error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH);
1137156893Stegge		if (error == 0) {
1138122524Srwatson			error = vn_setlabel(nd.ni_vp, intlabel,
1139105694Srwatson			    td->td_ucred);
1140156893Stegge			vn_finished_write(mp);
1141156893Stegge		}
1142105694Srwatson	}
1143105694Srwatson
1144100979Srwatson	NDFREE(&nd, 0);
1145150914Scsjp	VFS_UNLOCK_GIANT(vfslocked);
1146122524Srwatsonout:
1147122524Srwatson	mac_vnode_label_free(intlabel);
1148100979Srwatson	return (error);
1149100979Srwatson}
1150100979Srwatson
1151105694Srwatson/*
1152105694Srwatson * MPSAFE
1153105694Srwatson */
1154102123Srwatsonint
1155102123Srwatsonmac_syscall(struct thread *td, struct mac_syscall_args *uap)
1156102123Srwatson{
1157102123Srwatson	struct mac_policy_conf *mpc;
1158102123Srwatson	char target[MAC_MAX_POLICY_NAME];
1159114806Srwatson	int entrycount, error;
1160102123Srwatson
1161107849Salfred	error = copyinstr(uap->policy, target, sizeof(target), NULL);
1162102123Srwatson	if (error)
1163102123Srwatson		return (error);
1164102123Srwatson
1165102123Srwatson	error = ENOSYS;
1166119494Srwatson	LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) {
1167102123Srwatson		if (strcmp(mpc->mpc_name, target) == 0 &&
1168102123Srwatson		    mpc->mpc_ops->mpo_syscall != NULL) {
1169102123Srwatson			error = mpc->mpc_ops->mpo_syscall(td,
1170107849Salfred			    uap->call, uap->arg);
1171102123Srwatson			goto out;
1172102123Srwatson		}
1173102123Srwatson	}
1174102123Srwatson
1175114806Srwatson	if ((entrycount = mac_policy_list_conditional_busy()) != 0) {
1176114806Srwatson		LIST_FOREACH(mpc, &mac_policy_list, mpc_list) {
1177114806Srwatson			if (strcmp(mpc->mpc_name, target) == 0 &&
1178114806Srwatson			    mpc->mpc_ops->mpo_syscall != NULL) {
1179114806Srwatson				error = mpc->mpc_ops->mpo_syscall(td,
1180114806Srwatson				    uap->call, uap->arg);
1181114806Srwatson				break;
1182114806Srwatson			}
1183114806Srwatson		}
1184114806Srwatson		mac_policy_list_unbusy();
1185114806Srwatson	}
1186102123Srwatsonout:
1187102123Srwatson	return (error);
1188102123Srwatson}
1189102123Srwatson
1190100979SrwatsonSYSINIT(mac, SI_SUB_MAC, SI_ORDER_FIRST, mac_init, NULL);
1191100979SrwatsonSYSINIT(mac_late, SI_SUB_MAC_LATE, SI_ORDER_FIRST, mac_late_init, NULL);
1192100979Srwatson
1193100979Srwatson#else /* !MAC */
1194100979Srwatson
1195100979Srwatsonint
1196105694Srwatson__mac_get_pid(struct thread *td, struct __mac_get_pid_args *uap)
1197105694Srwatson{
1198105694Srwatson
1199105694Srwatson	return (ENOSYS);
1200105694Srwatson}
1201105694Srwatson
1202105694Srwatsonint
1203100979Srwatson__mac_get_proc(struct thread *td, struct __mac_get_proc_args *uap)
1204100979Srwatson{
1205100979Srwatson
1206100894Srwatson	return (ENOSYS);
1207100894Srwatson}
1208100894Srwatson
1209100894Srwatsonint
1210100894Srwatson__mac_set_proc(struct thread *td, struct __mac_set_proc_args *uap)
1211100894Srwatson{
1212100894Srwatson
1213100894Srwatson	return (ENOSYS);
1214100894Srwatson}
1215100894Srwatson
1216100894Srwatsonint
1217100894Srwatson__mac_get_fd(struct thread *td, struct __mac_get_fd_args *uap)
1218100894Srwatson{
1219100894Srwatson
1220100894Srwatson	return (ENOSYS);
1221100894Srwatson}
1222100894Srwatson
1223100894Srwatsonint
1224100894Srwatson__mac_get_file(struct thread *td, struct __mac_get_file_args *uap)
1225100894Srwatson{
1226100894Srwatson
1227100894Srwatson	return (ENOSYS);
1228100894Srwatson}
1229100894Srwatson
1230100894Srwatsonint
1231105694Srwatson__mac_get_link(struct thread *td, struct __mac_get_link_args *uap)
1232105694Srwatson{
1233105694Srwatson
1234105694Srwatson	return (ENOSYS);
1235105694Srwatson}
1236105694Srwatson
1237105694Srwatsonint
1238100894Srwatson__mac_set_fd(struct thread *td, struct __mac_set_fd_args *uap)
1239100894Srwatson{
1240100894Srwatson
1241100894Srwatson	return (ENOSYS);
1242100894Srwatson}
1243100894Srwatson
1244100894Srwatsonint
1245100894Srwatson__mac_set_file(struct thread *td, struct __mac_set_file_args *uap)
1246100894Srwatson{
1247100894Srwatson
1248100894Srwatson	return (ENOSYS);
1249100894Srwatson}
1250100979Srwatson
1251102123Srwatsonint
1252105694Srwatson__mac_set_link(struct thread *td, struct __mac_set_link_args *uap)
1253105694Srwatson{
1254105694Srwatson
1255105694Srwatson	return (ENOSYS);
1256105694Srwatson}
1257105694Srwatson
1258105694Srwatsonint
1259102123Srwatsonmac_syscall(struct thread *td, struct mac_syscall_args *uap)
1260102123Srwatson{
1261102123Srwatson
1262102123Srwatson	return (ENOSYS);
1263102123Srwatson}
1264102123Srwatson
1265128901Srwatson#endif /* !MAC */
1266