mac_syscalls.c revision 165433
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 165433 2006-12-21 09:51:34Z 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
744165433Srwatson	mac_cred_mmapped_drop_perms(td, newcred);
745102136Srwatson
746102136Srwatson	crfree(newcred);	/* Free revocation reference. */
747100979Srwatson	crfree(oldcred);
748105694Srwatson
749105694Srwatsonout:
750122524Srwatson	mac_cred_label_free(intlabel);
751105694Srwatson	return (error);
752100979Srwatson}
753100979Srwatson
754100979Srwatson/*
755100979Srwatson * MPSAFE
756100979Srwatson */
757100979Srwatsonint
758100979Srwatson__mac_get_fd(struct thread *td, struct __mac_get_fd_args *uap)
759100979Srwatson{
760105694Srwatson	char *elements, *buffer;
761122524Srwatson	struct label *intlabel;
762100979Srwatson	struct file *fp;
763105694Srwatson	struct mac mac;
764100979Srwatson	struct vnode *vp;
765100979Srwatson	struct pipe *pipe;
766122820Srwatson	struct socket *so;
767105694Srwatson	short label_type;
768150914Scsjp	int vfslocked, error;
769100979Srwatson
770105694Srwatson	error = copyin(uap->mac_p, &mac, sizeof(mac));
771105694Srwatson	if (error)
772105694Srwatson		return (error);
773100979Srwatson
774105694Srwatson	error = mac_check_structmac_consistent(&mac);
775105694Srwatson	if (error)
776105694Srwatson		return (error);
777105694Srwatson
778111119Simp	elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
779105694Srwatson	error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
780105694Srwatson	if (error) {
781105694Srwatson		free(elements, M_MACTEMP);
782105694Srwatson		return (error);
783105694Srwatson	}
784105694Srwatson
785111119Simp	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
786107849Salfred	error = fget(td, uap->fd, &fp);
787100979Srwatson	if (error)
788100979Srwatson		goto out;
789100979Srwatson
790105694Srwatson	label_type = fp->f_type;
791100979Srwatson	switch (fp->f_type) {
792100979Srwatson	case DTYPE_FIFO:
793100979Srwatson	case DTYPE_VNODE:
794116678Sphk		vp = fp->f_vnode;
795122524Srwatson		intlabel = mac_vnode_label_alloc();
796150914Scsjp		vfslocked = VFS_LOCK_GIANT(vp->v_mount);
797100979Srwatson		vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
798122524Srwatson		mac_copy_vnode_label(vp->v_label, intlabel);
799100979Srwatson		VOP_UNLOCK(vp, 0, td);
800150914Scsjp		VFS_UNLOCK_GIANT(vfslocked);
801122584Srwatson		error = mac_externalize_vnode_label(intlabel, elements,
802122584Srwatson		    buffer, mac.m_buflen);
803122584Srwatson		mac_vnode_label_free(intlabel);
804122584Srwatson		break;
805105694Srwatson
806100979Srwatson	case DTYPE_PIPE:
807109153Sdillon		pipe = fp->f_data;
808122524Srwatson		intlabel = mac_pipe_label_alloc();
809105694Srwatson		PIPE_LOCK(pipe);
810125293Srwatson		mac_copy_pipe_label(pipe->pipe_pair->pp_label, intlabel);
811105694Srwatson		PIPE_UNLOCK(pipe);
812122524Srwatson		error = mac_externalize_pipe_label(intlabel, elements,
813122159Srwatson		    buffer, mac.m_buflen);
814122524Srwatson		mac_pipe_label_free(intlabel);
815105694Srwatson		break;
816122584Srwatson
817122820Srwatson	case DTYPE_SOCKET:
818122820Srwatson		so = fp->f_data;
819122820Srwatson		intlabel = mac_socket_label_alloc(M_WAITOK);
820145160Srwatson		NET_LOCK_GIANT();
821145160Srwatson		SOCK_LOCK(so);
822122820Srwatson		mac_copy_socket_label(so->so_label, intlabel);
823145160Srwatson		SOCK_UNLOCK(so);
824145160Srwatson		NET_UNLOCK_GIANT();
825122820Srwatson		error = mac_externalize_socket_label(intlabel, elements,
826122820Srwatson		    buffer, mac.m_buflen);
827122820Srwatson		mac_socket_label_free(intlabel);
828122820Srwatson		break;
829122820Srwatson
830105694Srwatson	default:
831122584Srwatson		error = EINVAL;
832105694Srwatson	}
833122584Srwatson	fdrop(fp, td);
834100979Srwatson	if (error == 0)
835105694Srwatson		error = copyout(buffer, mac.m_string, strlen(buffer)+1);
836100979Srwatson
837105694Srwatsonout:
838105694Srwatson	free(buffer, M_MACTEMP);
839105694Srwatson	free(elements, M_MACTEMP);
840100979Srwatson	return (error);
841100979Srwatson}
842100979Srwatson
843100979Srwatson/*
844100979Srwatson * MPSAFE
845100979Srwatson */
846100979Srwatsonint
847100979Srwatson__mac_get_file(struct thread *td, struct __mac_get_file_args *uap)
848100979Srwatson{
849105694Srwatson	char *elements, *buffer;
850100979Srwatson	struct nameidata nd;
851122524Srwatson	struct label *intlabel;
852105694Srwatson	struct mac mac;
853150914Scsjp	int vfslocked, error;
854100979Srwatson
855105694Srwatson	error = copyin(uap->mac_p, &mac, sizeof(mac));
856105694Srwatson	if (error)
857105694Srwatson		return (error);
858105694Srwatson
859105694Srwatson	error = mac_check_structmac_consistent(&mac);
860105694Srwatson	if (error)
861105694Srwatson		return (error);
862105694Srwatson
863111119Simp	elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
864105694Srwatson	error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
865105694Srwatson	if (error) {
866105694Srwatson		free(elements, M_MACTEMP);
867105694Srwatson		return (error);
868105694Srwatson	}
869105694Srwatson
870111119Simp	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
871150914Scsjp	NDINIT(&nd, LOOKUP, MPSAFE | LOCKLEAF | FOLLOW, UIO_USERSPACE,
872150914Scsjp	    uap->path_p, td);
873100979Srwatson	error = namei(&nd);
874100979Srwatson	if (error)
875100979Srwatson		goto out;
876100979Srwatson
877122524Srwatson	intlabel = mac_vnode_label_alloc();
878150914Scsjp	vfslocked = NDHASGIANT(&nd);
879122524Srwatson	mac_copy_vnode_label(nd.ni_vp->v_label, intlabel);
880122524Srwatson	error = mac_externalize_vnode_label(intlabel, elements, buffer,
881122159Srwatson	    mac.m_buflen);
882105694Srwatson
883100979Srwatson	NDFREE(&nd, 0);
884150914Scsjp	VFS_UNLOCK_GIANT(vfslocked);
885122524Srwatson	mac_vnode_label_free(intlabel);
886105694Srwatson	if (error == 0)
887105694Srwatson		error = copyout(buffer, mac.m_string, strlen(buffer)+1);
888105694Srwatson
889105694Srwatsonout:
890105694Srwatson	free(buffer, M_MACTEMP);
891105694Srwatson	free(elements, M_MACTEMP);
892105694Srwatson
893105694Srwatson	return (error);
894105694Srwatson}
895105694Srwatson
896105694Srwatson/*
897105694Srwatson * MPSAFE
898105694Srwatson */
899105694Srwatsonint
900105694Srwatson__mac_get_link(struct thread *td, struct __mac_get_link_args *uap)
901105694Srwatson{
902105694Srwatson	char *elements, *buffer;
903105694Srwatson	struct nameidata nd;
904122524Srwatson	struct label *intlabel;
905105694Srwatson	struct mac mac;
906150914Scsjp	int vfslocked, error;
907105694Srwatson
908105694Srwatson	error = copyin(uap->mac_p, &mac, sizeof(mac));
909100979Srwatson	if (error)
910105694Srwatson		return (error);
911105694Srwatson
912105694Srwatson	error = mac_check_structmac_consistent(&mac);
913105694Srwatson	if (error)
914105694Srwatson		return (error);
915105694Srwatson
916111119Simp	elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
917105694Srwatson	error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
918105694Srwatson	if (error) {
919105694Srwatson		free(elements, M_MACTEMP);
920105694Srwatson		return (error);
921105694Srwatson	}
922105694Srwatson
923111119Simp	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
924150914Scsjp	NDINIT(&nd, LOOKUP, MPSAFE | LOCKLEAF | NOFOLLOW, UIO_USERSPACE,
925150914Scsjp	    uap->path_p, td);
926105694Srwatson	error = namei(&nd);
927105694Srwatson	if (error)
928100979Srwatson		goto out;
929100979Srwatson
930122524Srwatson	intlabel = mac_vnode_label_alloc();
931150914Scsjp	vfslocked = NDHASGIANT(&nd);
932122524Srwatson	mac_copy_vnode_label(nd.ni_vp->v_label, intlabel);
933122524Srwatson	error = mac_externalize_vnode_label(intlabel, elements, buffer,
934122159Srwatson	    mac.m_buflen);
935105694Srwatson	NDFREE(&nd, 0);
936150914Scsjp	VFS_UNLOCK_GIANT(vfslocked);
937122524Srwatson	mac_vnode_label_free(intlabel);
938100979Srwatson
939105694Srwatson	if (error == 0)
940105694Srwatson		error = copyout(buffer, mac.m_string, strlen(buffer)+1);
941105694Srwatson
942100979Srwatsonout:
943105694Srwatson	free(buffer, M_MACTEMP);
944105694Srwatson	free(elements, M_MACTEMP);
945105694Srwatson
946100979Srwatson	return (error);
947100979Srwatson}
948100979Srwatson
949100979Srwatson/*
950100979Srwatson * MPSAFE
951100979Srwatson */
952100979Srwatsonint
953100979Srwatson__mac_set_fd(struct thread *td, struct __mac_set_fd_args *uap)
954100979Srwatson{
955122524Srwatson	struct label *intlabel;
956105694Srwatson	struct pipe *pipe;
957122820Srwatson	struct socket *so;
958100979Srwatson	struct file *fp;
959100979Srwatson	struct mount *mp;
960100979Srwatson	struct vnode *vp;
961105694Srwatson	struct mac mac;
962105694Srwatson	char *buffer;
963150914Scsjp	int error, vfslocked;
964100979Srwatson
965105694Srwatson	error = copyin(uap->mac_p, &mac, sizeof(mac));
966100979Srwatson	if (error)
967105694Srwatson		return (error);
968100979Srwatson
969105694Srwatson	error = mac_check_structmac_consistent(&mac);
970100979Srwatson	if (error)
971105694Srwatson		return (error);
972100979Srwatson
973111119Simp	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
974105694Srwatson	error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
975105694Srwatson	if (error) {
976105694Srwatson		free(buffer, M_MACTEMP);
977105694Srwatson		return (error);
978105694Srwatson	}
979105694Srwatson
980107849Salfred	error = fget(td, uap->fd, &fp);
981100979Srwatson	if (error)
982105694Srwatson		goto out;
983100979Srwatson
984100979Srwatson	switch (fp->f_type) {
985100979Srwatson	case DTYPE_FIFO:
986100979Srwatson	case DTYPE_VNODE:
987122524Srwatson		intlabel = mac_vnode_label_alloc();
988122524Srwatson		error = mac_internalize_vnode_label(intlabel, buffer);
989105694Srwatson		if (error) {
990122524Srwatson			mac_vnode_label_free(intlabel);
991105694Srwatson			break;
992105694Srwatson		}
993116678Sphk		vp = fp->f_vnode;
994150914Scsjp		vfslocked = VFS_LOCK_GIANT(vp->v_mount);
995100979Srwatson		error = vn_start_write(vp, &mp, V_WAIT | PCATCH);
996105694Srwatson		if (error != 0) {
997150914Scsjp			VFS_UNLOCK_GIANT(vfslocked);
998122524Srwatson			mac_vnode_label_free(intlabel);
999100979Srwatson			break;
1000105694Srwatson		}
1001100979Srwatson		vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
1002122524Srwatson		error = vn_setlabel(vp, intlabel, td->td_ucred);
1003100979Srwatson		VOP_UNLOCK(vp, 0, td);
1004100979Srwatson		vn_finished_write(mp);
1005150914Scsjp		VFS_UNLOCK_GIANT(vfslocked);
1006122524Srwatson		mac_vnode_label_free(intlabel);
1007100979Srwatson		break;
1008105694Srwatson
1009100979Srwatson	case DTYPE_PIPE:
1010122524Srwatson		intlabel = mac_pipe_label_alloc();
1011122524Srwatson		error = mac_internalize_pipe_label(intlabel, buffer);
1012105694Srwatson		if (error == 0) {
1013109153Sdillon			pipe = fp->f_data;
1014105694Srwatson			PIPE_LOCK(pipe);
1015125293Srwatson			error = mac_pipe_label_set(td->td_ucred,
1016125293Srwatson			    pipe->pipe_pair, intlabel);
1017105694Srwatson			PIPE_UNLOCK(pipe);
1018105694Srwatson		}
1019122524Srwatson		mac_pipe_label_free(intlabel);
1020100979Srwatson		break;
1021105694Srwatson
1022122820Srwatson	case DTYPE_SOCKET:
1023122820Srwatson		intlabel = mac_socket_label_alloc(M_WAITOK);
1024122820Srwatson		error = mac_internalize_socket_label(intlabel, buffer);
1025122820Srwatson		if (error == 0) {
1026122820Srwatson			so = fp->f_data;
1027145160Srwatson			NET_LOCK_GIANT();
1028122820Srwatson			error = mac_socket_label_set(td->td_ucred, so,
1029122820Srwatson			    intlabel);
1030145160Srwatson			NET_UNLOCK_GIANT();
1031122820Srwatson		}
1032122820Srwatson		mac_socket_label_free(intlabel);
1033122820Srwatson		break;
1034122820Srwatson
1035100979Srwatson	default:
1036100979Srwatson		error = EINVAL;
1037100979Srwatson	}
1038100979Srwatson	fdrop(fp, td);
1039105694Srwatsonout:
1040105694Srwatson	free(buffer, M_MACTEMP);
1041100979Srwatson	return (error);
1042100979Srwatson}
1043100979Srwatson
1044100979Srwatson/*
1045100979Srwatson * MPSAFE
1046100979Srwatson */
1047100979Srwatsonint
1048100979Srwatson__mac_set_file(struct thread *td, struct __mac_set_file_args *uap)
1049100979Srwatson{
1050122524Srwatson	struct label *intlabel;
1051100979Srwatson	struct nameidata nd;
1052100979Srwatson	struct mount *mp;
1053105694Srwatson	struct mac mac;
1054105694Srwatson	char *buffer;
1055150914Scsjp	int vfslocked, error;
1056100979Srwatson
1057105694Srwatson	error = copyin(uap->mac_p, &mac, sizeof(mac));
1058100979Srwatson	if (error)
1059105694Srwatson		return (error);
1060100979Srwatson
1061105694Srwatson	error = mac_check_structmac_consistent(&mac);
1062100979Srwatson	if (error)
1063105694Srwatson		return (error);
1064100979Srwatson
1065111119Simp	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
1066105694Srwatson	error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
1067105694Srwatson	if (error) {
1068105694Srwatson		free(buffer, M_MACTEMP);
1069105694Srwatson		return (error);
1070105694Srwatson	}
1071105694Srwatson
1072122524Srwatson	intlabel = mac_vnode_label_alloc();
1073122524Srwatson	error = mac_internalize_vnode_label(intlabel, buffer);
1074105694Srwatson	free(buffer, M_MACTEMP);
1075122524Srwatson	if (error)
1076122524Srwatson		goto out;
1077105694Srwatson
1078150914Scsjp	NDINIT(&nd, LOOKUP, MPSAFE | LOCKLEAF | FOLLOW, UIO_USERSPACE,
1079150914Scsjp	    uap->path_p, td);
1080100979Srwatson	error = namei(&nd);
1081150914Scsjp	vfslocked = NDHASGIANT(&nd);
1082105694Srwatson	if (error == 0) {
1083105694Srwatson		error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH);
1084156893Stegge		if (error == 0) {
1085122524Srwatson			error = vn_setlabel(nd.ni_vp, intlabel,
1086105694Srwatson			    td->td_ucred);
1087156893Stegge			vn_finished_write(mp);
1088156893Stegge		}
1089105694Srwatson	}
1090105694Srwatson
1091105694Srwatson	NDFREE(&nd, 0);
1092150914Scsjp	VFS_UNLOCK_GIANT(vfslocked);
1093122524Srwatsonout:
1094122524Srwatson	mac_vnode_label_free(intlabel);
1095105694Srwatson	return (error);
1096105694Srwatson}
1097105694Srwatson
1098105694Srwatson/*
1099105694Srwatson * MPSAFE
1100105694Srwatson */
1101105694Srwatsonint
1102105694Srwatson__mac_set_link(struct thread *td, struct __mac_set_link_args *uap)
1103105694Srwatson{
1104122524Srwatson	struct label *intlabel;
1105105694Srwatson	struct nameidata nd;
1106105694Srwatson	struct mount *mp;
1107105694Srwatson	struct mac mac;
1108105694Srwatson	char *buffer;
1109150914Scsjp	int vfslocked, error;
1110105694Srwatson
1111105694Srwatson	error = copyin(uap->mac_p, &mac, sizeof(mac));
1112100979Srwatson	if (error)
1113105694Srwatson		return (error);
1114105694Srwatson
1115105694Srwatson	error = mac_check_structmac_consistent(&mac);
1116100979Srwatson	if (error)
1117105694Srwatson		return (error);
1118100979Srwatson
1119111119Simp	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
1120105694Srwatson	error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
1121105694Srwatson	if (error) {
1122105694Srwatson		free(buffer, M_MACTEMP);
1123105694Srwatson		return (error);
1124105694Srwatson	}
1125105694Srwatson
1126122524Srwatson	intlabel = mac_vnode_label_alloc();
1127122524Srwatson	error = mac_internalize_vnode_label(intlabel, buffer);
1128105694Srwatson	free(buffer, M_MACTEMP);
1129122524Srwatson	if (error)
1130122524Srwatson		goto out;
1131105694Srwatson
1132150914Scsjp	NDINIT(&nd, LOOKUP, MPSAFE | LOCKLEAF | NOFOLLOW, UIO_USERSPACE,
1133150914Scsjp	    uap->path_p, td);
1134105694Srwatson	error = namei(&nd);
1135150914Scsjp	vfslocked = NDHASGIANT(&nd);
1136105694Srwatson	if (error == 0) {
1137105694Srwatson		error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH);
1138156893Stegge		if (error == 0) {
1139122524Srwatson			error = vn_setlabel(nd.ni_vp, intlabel,
1140105694Srwatson			    td->td_ucred);
1141156893Stegge			vn_finished_write(mp);
1142156893Stegge		}
1143105694Srwatson	}
1144105694Srwatson
1145100979Srwatson	NDFREE(&nd, 0);
1146150914Scsjp	VFS_UNLOCK_GIANT(vfslocked);
1147122524Srwatsonout:
1148122524Srwatson	mac_vnode_label_free(intlabel);
1149100979Srwatson	return (error);
1150100979Srwatson}
1151100979Srwatson
1152105694Srwatson/*
1153105694Srwatson * MPSAFE
1154105694Srwatson */
1155102123Srwatsonint
1156102123Srwatsonmac_syscall(struct thread *td, struct mac_syscall_args *uap)
1157102123Srwatson{
1158102123Srwatson	struct mac_policy_conf *mpc;
1159102123Srwatson	char target[MAC_MAX_POLICY_NAME];
1160114806Srwatson	int entrycount, error;
1161102123Srwatson
1162107849Salfred	error = copyinstr(uap->policy, target, sizeof(target), NULL);
1163102123Srwatson	if (error)
1164102123Srwatson		return (error);
1165102123Srwatson
1166102123Srwatson	error = ENOSYS;
1167119494Srwatson	LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) {
1168102123Srwatson		if (strcmp(mpc->mpc_name, target) == 0 &&
1169102123Srwatson		    mpc->mpc_ops->mpo_syscall != NULL) {
1170102123Srwatson			error = mpc->mpc_ops->mpo_syscall(td,
1171107849Salfred			    uap->call, uap->arg);
1172102123Srwatson			goto out;
1173102123Srwatson		}
1174102123Srwatson	}
1175102123Srwatson
1176114806Srwatson	if ((entrycount = mac_policy_list_conditional_busy()) != 0) {
1177114806Srwatson		LIST_FOREACH(mpc, &mac_policy_list, mpc_list) {
1178114806Srwatson			if (strcmp(mpc->mpc_name, target) == 0 &&
1179114806Srwatson			    mpc->mpc_ops->mpo_syscall != NULL) {
1180114806Srwatson				error = mpc->mpc_ops->mpo_syscall(td,
1181114806Srwatson				    uap->call, uap->arg);
1182114806Srwatson				break;
1183114806Srwatson			}
1184114806Srwatson		}
1185114806Srwatson		mac_policy_list_unbusy();
1186114806Srwatson	}
1187102123Srwatsonout:
1188102123Srwatson	return (error);
1189102123Srwatson}
1190102123Srwatson
1191100979SrwatsonSYSINIT(mac, SI_SUB_MAC, SI_ORDER_FIRST, mac_init, NULL);
1192100979SrwatsonSYSINIT(mac_late, SI_SUB_MAC_LATE, SI_ORDER_FIRST, mac_late_init, NULL);
1193100979Srwatson
1194100979Srwatson#else /* !MAC */
1195100979Srwatson
1196100979Srwatsonint
1197105694Srwatson__mac_get_pid(struct thread *td, struct __mac_get_pid_args *uap)
1198105694Srwatson{
1199105694Srwatson
1200105694Srwatson	return (ENOSYS);
1201105694Srwatson}
1202105694Srwatson
1203105694Srwatsonint
1204100979Srwatson__mac_get_proc(struct thread *td, struct __mac_get_proc_args *uap)
1205100979Srwatson{
1206100979Srwatson
1207100894Srwatson	return (ENOSYS);
1208100894Srwatson}
1209100894Srwatson
1210100894Srwatsonint
1211100894Srwatson__mac_set_proc(struct thread *td, struct __mac_set_proc_args *uap)
1212100894Srwatson{
1213100894Srwatson
1214100894Srwatson	return (ENOSYS);
1215100894Srwatson}
1216100894Srwatson
1217100894Srwatsonint
1218100894Srwatson__mac_get_fd(struct thread *td, struct __mac_get_fd_args *uap)
1219100894Srwatson{
1220100894Srwatson
1221100894Srwatson	return (ENOSYS);
1222100894Srwatson}
1223100894Srwatson
1224100894Srwatsonint
1225100894Srwatson__mac_get_file(struct thread *td, struct __mac_get_file_args *uap)
1226100894Srwatson{
1227100894Srwatson
1228100894Srwatson	return (ENOSYS);
1229100894Srwatson}
1230100894Srwatson
1231100894Srwatsonint
1232105694Srwatson__mac_get_link(struct thread *td, struct __mac_get_link_args *uap)
1233105694Srwatson{
1234105694Srwatson
1235105694Srwatson	return (ENOSYS);
1236105694Srwatson}
1237105694Srwatson
1238105694Srwatsonint
1239100894Srwatson__mac_set_fd(struct thread *td, struct __mac_set_fd_args *uap)
1240100894Srwatson{
1241100894Srwatson
1242100894Srwatson	return (ENOSYS);
1243100894Srwatson}
1244100894Srwatson
1245100894Srwatsonint
1246100894Srwatson__mac_set_file(struct thread *td, struct __mac_set_file_args *uap)
1247100894Srwatson{
1248100894Srwatson
1249100894Srwatson	return (ENOSYS);
1250100894Srwatson}
1251100979Srwatson
1252102123Srwatsonint
1253105694Srwatson__mac_set_link(struct thread *td, struct __mac_set_link_args *uap)
1254105694Srwatson{
1255105694Srwatson
1256105694Srwatson	return (ENOSYS);
1257105694Srwatson}
1258105694Srwatson
1259105694Srwatsonint
1260102123Srwatsonmac_syscall(struct thread *td, struct mac_syscall_args *uap)
1261102123Srwatson{
1262102123Srwatson
1263102123Srwatson	return (ENOSYS);
1264102123Srwatson}
1265102123Srwatson
1266128901Srwatson#endif /* !MAC */
1267