mac_syscalls.c revision 150914
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.
5147983Srwatson * Copyright (c) 2005 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 150914 2005-10-04 14:32:58Z csjp $");
51116182Sobrien
52100894Srwatson#include "opt_mac.h"
53104300Sphk#include "opt_devfs.h"
54101173Srwatson
55100894Srwatson#include <sys/param.h>
56106856Srwatson#include <sys/condvar.h>
57100979Srwatson#include <sys/extattr.h>
58106468Srwatson#include <sys/imgact.h>
59100979Srwatson#include <sys/kernel.h>
60100979Srwatson#include <sys/lock.h>
61102949Sbde#include <sys/malloc.h>
62100979Srwatson#include <sys/mutex.h>
63100979Srwatson#include <sys/mac.h>
64101712Srwatson#include <sys/module.h>
65100979Srwatson#include <sys/proc.h>
66116701Srwatson#include <sys/sbuf.h>
67100979Srwatson#include <sys/systm.h>
68100894Srwatson#include <sys/sysproto.h>
69100894Srwatson#include <sys/sysent.h>
70100979Srwatson#include <sys/vnode.h>
71100979Srwatson#include <sys/mount.h>
72100979Srwatson#include <sys/file.h>
73100979Srwatson#include <sys/namei.h>
74100979Srwatson#include <sys/socket.h>
75100979Srwatson#include <sys/pipe.h>
76100979Srwatson#include <sys/socketvar.h>
77100979Srwatson#include <sys/sysctl.h>
78100894Srwatson
79100979Srwatson#include <vm/vm.h>
80100979Srwatson#include <vm/pmap.h>
81100979Srwatson#include <vm/vm_map.h>
82100979Srwatson#include <vm/vm_object.h>
83100979Srwatson
84100979Srwatson#include <sys/mac_policy.h>
85100979Srwatson
86100979Srwatson#include <fs/devfs/devfs.h>
87100979Srwatson
88100979Srwatson#include <net/bpfdesc.h>
89100979Srwatson#include <net/if.h>
90100979Srwatson#include <net/if_var.h>
91100979Srwatson
92100979Srwatson#include <netinet/in.h>
93100979Srwatson#include <netinet/ip_var.h>
94100979Srwatson
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
109114846Srwatson#if MAC_MAX_SLOTS > 32
110114846Srwatson#error "MAC_MAX_SLOTS too large"
111100979Srwatson#endif
112105497Srwatson
113114846Srwatsonstatic unsigned int mac_max_slots = MAC_MAX_SLOTS;
114114846Srwatsonstatic unsigned int mac_slot_offsets_free = (1 << MAC_MAX_SLOTS) - 1;
115114846SrwatsonSYSCTL_UINT(_security_mac, OID_AUTO, max_slots, CTLFLAG_RD,
116114846Srwatson    &mac_max_slots, 0, "");
117100979Srwatson
118105959Srwatson/*
119105959Srwatson * Has the kernel started generating labeled objects yet?  All read/write
120105959Srwatson * access to this variable is serialized during the boot process.  Following
121105959Srwatson * the end of serialization, we don't update this flag; no locking.
122105959Srwatson */
123121372Srwatsonint	mac_late = 0;
124100979Srwatson
125105988Srwatson/*
126113487Srwatson * Flag to indicate whether or not we should allocate label storage for
127113487Srwatson * new mbufs.  Since most dynamic policies we currently work with don't
128113487Srwatson * rely on mbuf labeling, try to avoid paying the cost of mtag allocation
129113487Srwatson * unless specifically notified of interest.  One result of this is
130113487Srwatson * that if a dynamically loaded policy requests mbuf labels, it must
131113487Srwatson * be able to deal with a NULL label being returned on any mbufs that
132113487Srwatson * were already in flight when the policy was loaded.  Since the policy
133113487Srwatson * already has to deal with uninitialized labels, this probably won't
134113487Srwatson * be a problem.  Note: currently no locking.  Will this be a problem?
135113487Srwatson */
136118308Srwatson#ifndef MAC_ALWAYS_LABEL_MBUF
137121372Srwatsonint	mac_labelmbufs = 0;
138113487Srwatson#endif
139113487Srwatson
140101988Srwatson#ifdef MAC_DEBUG
141104268SrwatsonSYSCTL_NODE(_security_mac, OID_AUTO, debug, CTLFLAG_RW, 0,
142104268Srwatson    "TrustedBSD MAC debug info");
143104517SrwatsonSYSCTL_NODE(_security_mac_debug, OID_AUTO, counters, CTLFLAG_RW, 0,
144104517Srwatson    "TrustedBSD MAC object counters");
145104517Srwatson
146121374Srwatsonstatic unsigned int nmactemp;
147104517SrwatsonSYSCTL_UINT(_security_mac_debug_counters, OID_AUTO, temp, CTLFLAG_RD,
148100979Srwatson    &nmactemp, 0, "number of temporary labels in use");
149101988Srwatson#endif
150100979Srwatson
151100979Srwatsonstatic int	mac_policy_register(struct mac_policy_conf *mpc);
152100979Srwatsonstatic int	mac_policy_unregister(struct mac_policy_conf *mpc);
153100979Srwatson
154105694SrwatsonMALLOC_DEFINE(M_MACTEMP, "mactemp", "MAC temporary label storage");
155100979Srwatson
156100979Srwatson/*
157114806Srwatson * mac_static_policy_list holds a list of policy modules that are not
158114806Srwatson * loaded while the system is "live", and cannot be unloaded.  These
159114806Srwatson * policies can be invoked without holding the busy count.
160114806Srwatson *
161114806Srwatson * mac_policy_list stores the list of dynamic policies.  A busy count is
162106856Srwatson * maintained for the list, stored in mac_policy_busy.  The busy count
163114806Srwatson * is protected by mac_policy_mtx; the list may be modified only
164106856Srwatson * while the busy count is 0, requiring that the lock be held to
165106856Srwatson * prevent new references to the list from being acquired.  For almost
166106856Srwatson * all operations, incrementing the busy count is sufficient to
167106856Srwatson * guarantee consistency, as the list cannot be modified while the
168106856Srwatson * busy count is elevated.  For a few special operations involving a
169114806Srwatson * change to the list of active policies, the mtx itself must be held.
170114806Srwatson * A condition variable, mac_policy_cv, is used to signal potential
171114806Srwatson * exclusive consumers that they should try to acquire the lock if a
172114806Srwatson * first attempt at exclusive access fails.
173100979Srwatson */
174128885Srwatson#ifndef MAC_STATIC
175114806Srwatsonstatic struct mtx mac_policy_mtx;
176114806Srwatsonstatic struct cv mac_policy_cv;
177114806Srwatsonstatic int mac_policy_count;
178128885Srwatson#endif
179121372Srwatsonstruct mac_policy_list_head mac_policy_list;
180121372Srwatsonstruct mac_policy_list_head mac_static_policy_list;
181100979Srwatson
182106856Srwatson/*
183111883Sjhb * We manually invoke WITNESS_WARN() to allow Witness to generate
184106856Srwatson * warnings even if we don't end up ever triggering the wait at
185106856Srwatson * run-time.  The consumer of the exclusive interface must not hold
186106856Srwatson * any locks (other than potentially Giant) since we may sleep for
187106856Srwatson * long (potentially indefinite) periods of time waiting for the
188106856Srwatson * framework to become quiescent so that a policy list change may
189106856Srwatson * be made.
190106856Srwatson */
191121372Srwatsonvoid
192114806Srwatsonmac_policy_grab_exclusive(void)
193114806Srwatson{
194122454Srwatson
195128885Srwatson#ifndef MAC_STATIC
196137072Srwatson	if (!mac_late)
197137072Srwatson		return;
198137072Srwatson
199114806Srwatson	WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL,
200114806Srwatson 	    "mac_policy_grab_exclusive() at %s:%d", __FILE__, __LINE__);
201114806Srwatson	mtx_lock(&mac_policy_mtx);
202114806Srwatson	while (mac_policy_count != 0)
203114806Srwatson		cv_wait(&mac_policy_cv, &mac_policy_mtx);
204128885Srwatson#endif
205114806Srwatson}
206106856Srwatson
207121372Srwatsonvoid
208114806Srwatsonmac_policy_assert_exclusive(void)
209114806Srwatson{
210122454Srwatson
211128885Srwatson#ifndef MAC_STATIC
212137072Srwatson	if (!mac_late)
213137072Srwatson		return;
214137072Srwatson
215114806Srwatson	mtx_assert(&mac_policy_mtx, MA_OWNED);
216114806Srwatson	KASSERT(mac_policy_count == 0,
217114806Srwatson	    ("mac_policy_assert_exclusive(): not exclusive"));
218128885Srwatson#endif
219114806Srwatson}
220113487Srwatson
221121372Srwatsonvoid
222114806Srwatsonmac_policy_release_exclusive(void)
223114806Srwatson{
224100979Srwatson
225128885Srwatson#ifndef MAC_STATIC
226137072Srwatson	if (!mac_late)
227137072Srwatson		return;
228137072Srwatson
229114806Srwatson	KASSERT(mac_policy_count == 0,
230114806Srwatson	    ("mac_policy_release_exclusive(): not exclusive"));
231114806Srwatson	mtx_unlock(&mac_policy_mtx);
232114806Srwatson	cv_signal(&mac_policy_cv);
233128885Srwatson#endif
234114806Srwatson}
235100979Srwatson
236121372Srwatsonvoid
237114806Srwatsonmac_policy_list_busy(void)
238114806Srwatson{
239122454Srwatson
240128885Srwatson#ifndef MAC_STATIC
241137072Srwatson	if (!mac_late)
242137072Srwatson		return;
243137072Srwatson
244114806Srwatson	mtx_lock(&mac_policy_mtx);
245114806Srwatson	mac_policy_count++;
246114806Srwatson	mtx_unlock(&mac_policy_mtx);
247128885Srwatson#endif
248114806Srwatson}
249114806Srwatson
250121372Srwatsonint
251114806Srwatsonmac_policy_list_conditional_busy(void)
252114806Srwatson{
253128885Srwatson#ifndef MAC_STATIC
254114806Srwatson	int ret;
255114806Srwatson
256137072Srwatson	if (!mac_late)
257137072Srwatson		return (1);
258137072Srwatson
259114806Srwatson	mtx_lock(&mac_policy_mtx);
260114806Srwatson	if (!LIST_EMPTY(&mac_policy_list)) {
261114806Srwatson		mac_policy_count++;
262114806Srwatson		ret = 1;
263114806Srwatson	} else
264114806Srwatson		ret = 0;
265114806Srwatson	mtx_unlock(&mac_policy_mtx);
266114806Srwatson	return (ret);
267128885Srwatson#else
268137072Srwatson	if (!mac_late)
269137072Srwatson		return (1);
270137072Srwatson
271128885Srwatson	return (1);
272128885Srwatson#endif
273114806Srwatson}
274114806Srwatson
275121372Srwatsonvoid
276114806Srwatsonmac_policy_list_unbusy(void)
277114806Srwatson{
278122454Srwatson
279128885Srwatson#ifndef MAC_STATIC
280137072Srwatson	if (!mac_late)
281137072Srwatson		return;
282137072Srwatson
283114806Srwatson	mtx_lock(&mac_policy_mtx);
284114806Srwatson	mac_policy_count--;
285114806Srwatson	KASSERT(mac_policy_count >= 0, ("MAC_POLICY_LIST_LOCK"));
286114806Srwatson	if (mac_policy_count == 0)
287114806Srwatson		cv_signal(&mac_policy_cv);
288114806Srwatson	mtx_unlock(&mac_policy_mtx);
289128885Srwatson#endif
290114806Srwatson}
291114806Srwatson
292100979Srwatson/*
293100979Srwatson * Initialize the MAC subsystem, including appropriate SMP locks.
294100979Srwatson */
295100979Srwatsonstatic void
296100979Srwatsonmac_init(void)
297100979Srwatson{
298100979Srwatson
299114806Srwatson	LIST_INIT(&mac_static_policy_list);
300100979Srwatson	LIST_INIT(&mac_policy_list);
301122524Srwatson	mac_labelzone_init();
302114806Srwatson
303128885Srwatson#ifndef MAC_STATIC
304114806Srwatson	mtx_init(&mac_policy_mtx, "mac_policy_mtx", NULL, MTX_DEF);
305114806Srwatson	cv_init(&mac_policy_cv, "mac_policy_cv");
306128885Srwatson#endif
307100979Srwatson}
308100979Srwatson
309100979Srwatson/*
310100979Srwatson * For the purposes of modules that want to know if they were loaded
311100979Srwatson * "early", set the mac_late flag once we've processed modules either
312100979Srwatson * linked into the kernel, or loaded before the kernel startup.
313100979Srwatson */
314100979Srwatsonstatic void
315100979Srwatsonmac_late_init(void)
316100979Srwatson{
317100979Srwatson
318100979Srwatson	mac_late = 1;
319100979Srwatson}
320100979Srwatson
321100979Srwatson/*
322113487Srwatson * After the policy list has changed, walk the list to update any global
323118308Srwatson * flags.  Currently, we support only one flag, and it's conditionally
324118308Srwatson * defined; as a result, the entire function is conditional.  Eventually,
325118308Srwatson * the #else case might also iterate across the policies.
326113487Srwatson */
327113487Srwatsonstatic void
328113487Srwatsonmac_policy_updateflags(void)
329113487Srwatson{
330118308Srwatson#ifndef MAC_ALWAYS_LABEL_MBUF
331113487Srwatson	struct mac_policy_conf *tmpc;
332113487Srwatson	int labelmbufs;
333113487Srwatson
334114806Srwatson	mac_policy_assert_exclusive();
335113487Srwatson
336113487Srwatson	labelmbufs = 0;
337114806Srwatson	LIST_FOREACH(tmpc, &mac_static_policy_list, mpc_list) {
338114806Srwatson		if (tmpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_LABELMBUFS)
339114806Srwatson			labelmbufs++;
340114806Srwatson	}
341113487Srwatson	LIST_FOREACH(tmpc, &mac_policy_list, mpc_list) {
342113487Srwatson		if (tmpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_LABELMBUFS)
343113487Srwatson			labelmbufs++;
344113487Srwatson	}
345113487Srwatson	mac_labelmbufs = (labelmbufs != 0);
346113487Srwatson#endif
347113487Srwatson}
348113487Srwatson
349113487Srwatson/*
350100979Srwatson * Allow MAC policy modules to register during boot, etc.
351100979Srwatson */
352100894Srwatsonint
353100979Srwatsonmac_policy_modevent(module_t mod, int type, void *data)
354100979Srwatson{
355100979Srwatson	struct mac_policy_conf *mpc;
356100979Srwatson	int error;
357100979Srwatson
358100979Srwatson	error = 0;
359100979Srwatson	mpc = (struct mac_policy_conf *) data;
360100979Srwatson
361128885Srwatson#ifdef MAC_STATIC
362128885Srwatson	if (mac_late) {
363128885Srwatson		printf("mac_policy_modevent: MAC_STATIC and late\n");
364128885Srwatson		return (EBUSY);
365128885Srwatson	}
366128885Srwatson#endif
367128885Srwatson
368100979Srwatson	switch (type) {
369100979Srwatson	case MOD_LOAD:
370100979Srwatson		if (mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_NOTLATE &&
371100979Srwatson		    mac_late) {
372100979Srwatson			printf("mac_policy_modevent: can't load %s policy "
373100979Srwatson			    "after booting\n", mpc->mpc_name);
374100979Srwatson			error = EBUSY;
375100979Srwatson			break;
376100979Srwatson		}
377100979Srwatson		error = mac_policy_register(mpc);
378100979Srwatson		break;
379100979Srwatson	case MOD_UNLOAD:
380100979Srwatson		/* Don't unregister the module if it was never registered. */
381100979Srwatson		if ((mpc->mpc_runtime_flags & MPC_RUNTIME_FLAG_REGISTERED)
382100979Srwatson		    != 0)
383100979Srwatson			error = mac_policy_unregister(mpc);
384100979Srwatson		else
385100979Srwatson			error = 0;
386100979Srwatson		break;
387100979Srwatson	default:
388132199Sphk		error = EOPNOTSUPP;
389100979Srwatson		break;
390100979Srwatson	}
391100979Srwatson
392100979Srwatson	return (error);
393100979Srwatson}
394100979Srwatson
395100979Srwatsonstatic int
396100979Srwatsonmac_policy_register(struct mac_policy_conf *mpc)
397100979Srwatson{
398100979Srwatson	struct mac_policy_conf *tmpc;
399114806Srwatson	int error, slot, static_entry;
400100979Srwatson
401114806Srwatson	error = 0;
402114806Srwatson
403114806Srwatson	/*
404114806Srwatson	 * We don't technically need exclusive access while !mac_late,
405114806Srwatson	 * but hold it for assertion consistency.
406114806Srwatson	 */
407114806Srwatson	mac_policy_grab_exclusive();
408114806Srwatson
409114806Srwatson	/*
410114806Srwatson	 * If the module can potentially be unloaded, or we're loading
411114806Srwatson	 * late, we have to stick it in the non-static list and pay
412114806Srwatson	 * an extra performance overhead.  Otherwise, we can pay a
413114806Srwatson	 * light locking cost and stick it in the static list.
414114806Srwatson	 */
415114806Srwatson	static_entry = (!mac_late &&
416114806Srwatson	    !(mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_UNLOADOK));
417114806Srwatson
418114806Srwatson	if (static_entry) {
419114806Srwatson		LIST_FOREACH(tmpc, &mac_static_policy_list, mpc_list) {
420114806Srwatson			if (strcmp(tmpc->mpc_name, mpc->mpc_name) == 0) {
421114806Srwatson				error = EEXIST;
422114806Srwatson				goto out;
423114806Srwatson			}
424100979Srwatson		}
425114806Srwatson	} else {
426114806Srwatson		LIST_FOREACH(tmpc, &mac_policy_list, mpc_list) {
427114806Srwatson			if (strcmp(tmpc->mpc_name, mpc->mpc_name) == 0) {
428114806Srwatson				error = EEXIST;
429114806Srwatson				goto out;
430114806Srwatson			}
431114806Srwatson		}
432100979Srwatson	}
433100979Srwatson	if (mpc->mpc_field_off != NULL) {
434114846Srwatson		slot = ffs(mac_slot_offsets_free);
435100979Srwatson		if (slot == 0) {
436114806Srwatson			error = ENOMEM;
437114806Srwatson			goto out;
438100979Srwatson		}
439100979Srwatson		slot--;
440114846Srwatson		mac_slot_offsets_free &= ~(1 << slot);
441100979Srwatson		*mpc->mpc_field_off = slot;
442100979Srwatson	}
443100979Srwatson	mpc->mpc_runtime_flags |= MPC_RUNTIME_FLAG_REGISTERED;
444100979Srwatson
445114806Srwatson	/*
446114806Srwatson	 * If we're loading a MAC module after the framework has
447114806Srwatson	 * initialized, it has to go into the dynamic list.  If
448114806Srwatson	 * we're loading it before we've finished initializing,
449114806Srwatson	 * it can go into the static list with weaker locker
450114806Srwatson	 * requirements.
451114806Srwatson	 */
452114806Srwatson	if (static_entry)
453114806Srwatson		LIST_INSERT_HEAD(&mac_static_policy_list, mpc, mpc_list);
454114806Srwatson	else
455114806Srwatson		LIST_INSERT_HEAD(&mac_policy_list, mpc, mpc_list);
456114806Srwatson
457100979Srwatson	/* Per-policy initialization. */
458100979Srwatson	if (mpc->mpc_ops->mpo_init != NULL)
459100979Srwatson		(*(mpc->mpc_ops->mpo_init))(mpc);
460113487Srwatson	mac_policy_updateflags();
461100979Srwatson
462100979Srwatson	printf("Security policy loaded: %s (%s)\n", mpc->mpc_fullname,
463100979Srwatson	    mpc->mpc_name);
464100979Srwatson
465114806Srwatsonout:
466114806Srwatson	mac_policy_release_exclusive();
467114806Srwatson	return (error);
468100979Srwatson}
469100979Srwatson
470100979Srwatsonstatic int
471100979Srwatsonmac_policy_unregister(struct mac_policy_conf *mpc)
472100979Srwatson{
473100979Srwatson
474104520Srwatson	/*
475104520Srwatson	 * If we fail the load, we may get a request to unload.  Check
476104520Srwatson	 * to see if we did the run-time registration, and if not,
477104520Srwatson	 * silently succeed.
478104520Srwatson	 */
479114806Srwatson	mac_policy_grab_exclusive();
480104520Srwatson	if ((mpc->mpc_runtime_flags & MPC_RUNTIME_FLAG_REGISTERED) == 0) {
481114806Srwatson		mac_policy_release_exclusive();
482104520Srwatson		return (0);
483104520Srwatson	}
484100979Srwatson#if 0
485100979Srwatson	/*
486100979Srwatson	 * Don't allow unloading modules with private data.
487100979Srwatson	 */
488104520Srwatson	if (mpc->mpc_field_off != NULL) {
489104520Srwatson		MAC_POLICY_LIST_UNLOCK();
490100979Srwatson		return (EBUSY);
491104520Srwatson	}
492100979Srwatson#endif
493104520Srwatson	/*
494104520Srwatson	 * Only allow the unload to proceed if the module is unloadable
495104520Srwatson	 * by its own definition.
496104520Srwatson	 */
497104520Srwatson	if ((mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_UNLOADOK) == 0) {
498114806Srwatson		mac_policy_release_exclusive();
499100979Srwatson		return (EBUSY);
500104520Srwatson	}
501100979Srwatson	if (mpc->mpc_ops->mpo_destroy != NULL)
502100979Srwatson		(*(mpc->mpc_ops->mpo_destroy))(mpc);
503100979Srwatson
504100979Srwatson	LIST_REMOVE(mpc, mpc_list);
505106856Srwatson	mpc->mpc_runtime_flags &= ~MPC_RUNTIME_FLAG_REGISTERED;
506113487Srwatson	mac_policy_updateflags();
507100979Srwatson
508114806Srwatson	mac_policy_release_exclusive();
509114806Srwatson
510100979Srwatson	printf("Security policy unload: %s (%s)\n", mpc->mpc_fullname,
511100979Srwatson	    mpc->mpc_name);
512100979Srwatson
513100979Srwatson	return (0);
514100979Srwatson}
515100979Srwatson
516100979Srwatson/*
517100979Srwatson * Define an error value precedence, and given two arguments, selects the
518100979Srwatson * value with the higher precedence.
519100979Srwatson */
520121371Srwatsonint
521121371Srwatsonmac_error_select(int error1, int error2)
522100979Srwatson{
523100979Srwatson
524100979Srwatson	/* Certain decision-making errors take top priority. */
525100979Srwatson	if (error1 == EDEADLK || error2 == EDEADLK)
526100979Srwatson		return (EDEADLK);
527100979Srwatson
528100979Srwatson	/* Invalid arguments should be reported where possible. */
529100979Srwatson	if (error1 == EINVAL || error2 == EINVAL)
530100979Srwatson		return (EINVAL);
531100979Srwatson
532100979Srwatson	/* Precedence goes to "visibility", with both process and file. */
533100979Srwatson	if (error1 == ESRCH || error2 == ESRCH)
534100979Srwatson		return (ESRCH);
535100979Srwatson
536100979Srwatson	if (error1 == ENOENT || error2 == ENOENT)
537100979Srwatson		return (ENOENT);
538100979Srwatson
539100979Srwatson	/* Precedence goes to DAC/MAC protections. */
540100979Srwatson	if (error1 == EACCES || error2 == EACCES)
541100979Srwatson		return (EACCES);
542100979Srwatson
543100979Srwatson	/* Precedence goes to privilege. */
544100979Srwatson	if (error1 == EPERM || error2 == EPERM)
545100979Srwatson		return (EPERM);
546100979Srwatson
547100979Srwatson	/* Precedence goes to error over success; otherwise, arbitrary. */
548100979Srwatson	if (error1 != 0)
549100979Srwatson		return (error1);
550100979Srwatson	return (error2);
551100979Srwatson}
552100979Srwatson
553121374Srwatsonvoid
554104521Srwatsonmac_init_label(struct label *label)
555104521Srwatson{
556104521Srwatson
557104521Srwatson	bzero(label, sizeof(*label));
558104521Srwatson	label->l_flags = MAC_FLAG_INITIALIZED;
559104521Srwatson}
560104521Srwatson
561121374Srwatsonvoid
562104521Srwatsonmac_destroy_label(struct label *label)
563104521Srwatson{
564104521Srwatson
565104521Srwatson	KASSERT(label->l_flags & MAC_FLAG_INITIALIZED,
566104521Srwatson	    ("destroying uninitialized label"));
567104521Srwatson
568104521Srwatson	bzero(label, sizeof(*label));
569104521Srwatson	/* implicit: label->l_flags &= ~MAC_FLAG_INITIALIZED; */
570104521Srwatson}
571104521Srwatson
572112675Srwatsonint
573105694Srwatsonmac_check_structmac_consistent(struct mac *mac)
574104522Srwatson{
575105694Srwatson
576120582Srwatson	if (mac->m_buflen < 0 ||
577120582Srwatson	    mac->m_buflen > MAC_MAX_LABEL_BUF_LEN)
578105694Srwatson		return (EINVAL);
579105694Srwatson
580105694Srwatson	return (0);
581105694Srwatson}
582105694Srwatson
583122584Srwatson/*
584122584Srwatson * MPSAFE
585122584Srwatson */
586105988Srwatsonint
587105694Srwatson__mac_get_pid(struct thread *td, struct __mac_get_pid_args *uap)
588105694Srwatson{
589105694Srwatson	char *elements, *buffer;
590105694Srwatson	struct mac mac;
591105694Srwatson	struct proc *tproc;
592105694Srwatson	struct ucred *tcred;
593105694Srwatson	int error;
594105694Srwatson
595107849Salfred	error = copyin(uap->mac_p, &mac, sizeof(mac));
596105694Srwatson	if (error)
597105694Srwatson		return (error);
598105694Srwatson
599105694Srwatson	error = mac_check_structmac_consistent(&mac);
600105694Srwatson	if (error)
601105694Srwatson		return (error);
602105694Srwatson
603105694Srwatson	tproc = pfind(uap->pid);
604105694Srwatson	if (tproc == NULL)
605105694Srwatson		return (ESRCH);
606105694Srwatson
607105694Srwatson	tcred = NULL;				/* Satisfy gcc. */
608105694Srwatson	error = p_cansee(td, tproc);
609105694Srwatson	if (error == 0)
610105694Srwatson		tcred = crhold(tproc->p_ucred);
611105694Srwatson	PROC_UNLOCK(tproc);
612105694Srwatson	if (error)
613105694Srwatson		return (error);
614105694Srwatson
615111119Simp	elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
616105694Srwatson	error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
617105694Srwatson	if (error) {
618105694Srwatson		free(elements, M_MACTEMP);
619105694Srwatson		crfree(tcred);
620105694Srwatson		return (error);
621105694Srwatson	}
622105694Srwatson
623111119Simp	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
624122524Srwatson	error = mac_externalize_cred_label(tcred->cr_label, elements,
625122159Srwatson	    buffer, mac.m_buflen);
626105694Srwatson	if (error == 0)
627105694Srwatson		error = copyout(buffer, mac.m_string, strlen(buffer)+1);
628105694Srwatson
629105694Srwatson	free(buffer, M_MACTEMP);
630105694Srwatson	free(elements, M_MACTEMP);
631105694Srwatson	crfree(tcred);
632105694Srwatson	return (error);
633105694Srwatson}
634105694Srwatson
635100979Srwatson/*
636100979Srwatson * MPSAFE
637100979Srwatson */
638100979Srwatsonint
639100894Srwatson__mac_get_proc(struct thread *td, struct __mac_get_proc_args *uap)
640100894Srwatson{
641105694Srwatson	char *elements, *buffer;
642105694Srwatson	struct mac mac;
643100979Srwatson	int error;
644100894Srwatson
645105694Srwatson	error = copyin(uap->mac_p, &mac, sizeof(mac));
646105694Srwatson	if (error)
647105694Srwatson		return (error);
648105694Srwatson
649105694Srwatson	error = mac_check_structmac_consistent(&mac);
650105694Srwatson	if (error)
651105694Srwatson		return (error);
652105694Srwatson
653111119Simp	elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
654105694Srwatson	error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
655105694Srwatson	if (error) {
656105694Srwatson		free(elements, M_MACTEMP);
657105694Srwatson		return (error);
658105694Srwatson	}
659105694Srwatson
660111119Simp	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
661122524Srwatson	error = mac_externalize_cred_label(td->td_ucred->cr_label,
662122159Srwatson	    elements, buffer, mac.m_buflen);
663100979Srwatson	if (error == 0)
664105694Srwatson		error = copyout(buffer, mac.m_string, strlen(buffer)+1);
665100979Srwatson
666105694Srwatson	free(buffer, M_MACTEMP);
667105694Srwatson	free(elements, M_MACTEMP);
668100979Srwatson	return (error);
669100979Srwatson}
670100979Srwatson
671100979Srwatson/*
672100979Srwatson * MPSAFE
673100979Srwatson */
674100979Srwatsonint
675100979Srwatson__mac_set_proc(struct thread *td, struct __mac_set_proc_args *uap)
676100979Srwatson{
677100979Srwatson	struct ucred *newcred, *oldcred;
678122524Srwatson	struct label *intlabel;
679100979Srwatson	struct proc *p;
680105694Srwatson	struct mac mac;
681105694Srwatson	char *buffer;
682100979Srwatson	int error;
683100979Srwatson
684105694Srwatson	error = copyin(uap->mac_p, &mac, sizeof(mac));
685100979Srwatson	if (error)
686100979Srwatson		return (error);
687100979Srwatson
688105694Srwatson	error = mac_check_structmac_consistent(&mac);
689100979Srwatson	if (error)
690100979Srwatson		return (error);
691100979Srwatson
692111119Simp	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
693105694Srwatson	error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
694105694Srwatson	if (error) {
695105694Srwatson		free(buffer, M_MACTEMP);
696105694Srwatson		return (error);
697105694Srwatson	}
698105694Srwatson
699122524Srwatson	intlabel = mac_cred_label_alloc();
700122524Srwatson	error = mac_internalize_cred_label(intlabel, buffer);
701105694Srwatson	free(buffer, M_MACTEMP);
702122524Srwatson	if (error)
703122524Srwatson		goto out;
704105694Srwatson
705100979Srwatson	newcred = crget();
706100979Srwatson
707100979Srwatson	p = td->td_proc;
708100979Srwatson	PROC_LOCK(p);
709100979Srwatson	oldcred = p->p_ucred;
710100979Srwatson
711122524Srwatson	error = mac_check_cred_relabel(oldcred, intlabel);
712100979Srwatson	if (error) {
713100979Srwatson		PROC_UNLOCK(p);
714100979Srwatson		crfree(newcred);
715105694Srwatson		goto out;
716100979Srwatson	}
717100979Srwatson
718100979Srwatson	setsugid(p);
719100979Srwatson	crcopy(newcred, oldcred);
720122524Srwatson	mac_relabel_cred(newcred, intlabel);
721102136Srwatson	p->p_ucred = newcred;
722100979Srwatson
723102136Srwatson	/*
724102136Srwatson	 * Grab additional reference for use while revoking mmaps, prior
725102136Srwatson	 * to releasing the proc lock and sharing the cred.
726102136Srwatson	 */
727102136Srwatson	crhold(newcred);
728100979Srwatson	PROC_UNLOCK(p);
729102136Srwatson
730105694Srwatson	if (mac_enforce_vm) {
731105694Srwatson		mac_cred_mmapped_drop_perms(td, newcred);
732105694Srwatson	}
733102136Srwatson
734102136Srwatson	crfree(newcred);	/* Free revocation reference. */
735100979Srwatson	crfree(oldcred);
736105694Srwatson
737105694Srwatsonout:
738122524Srwatson	mac_cred_label_free(intlabel);
739105694Srwatson	return (error);
740100979Srwatson}
741100979Srwatson
742100979Srwatson/*
743100979Srwatson * MPSAFE
744100979Srwatson */
745100979Srwatsonint
746100979Srwatson__mac_get_fd(struct thread *td, struct __mac_get_fd_args *uap)
747100979Srwatson{
748105694Srwatson	char *elements, *buffer;
749122524Srwatson	struct label *intlabel;
750100979Srwatson	struct file *fp;
751105694Srwatson	struct mac mac;
752100979Srwatson	struct vnode *vp;
753100979Srwatson	struct pipe *pipe;
754122820Srwatson	struct socket *so;
755105694Srwatson	short label_type;
756150914Scsjp	int vfslocked, error;
757100979Srwatson
758105694Srwatson	error = copyin(uap->mac_p, &mac, sizeof(mac));
759105694Srwatson	if (error)
760105694Srwatson		return (error);
761100979Srwatson
762105694Srwatson	error = mac_check_structmac_consistent(&mac);
763105694Srwatson	if (error)
764105694Srwatson		return (error);
765105694Srwatson
766111119Simp	elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
767105694Srwatson	error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
768105694Srwatson	if (error) {
769105694Srwatson		free(elements, M_MACTEMP);
770105694Srwatson		return (error);
771105694Srwatson	}
772105694Srwatson
773111119Simp	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
774107849Salfred	error = fget(td, uap->fd, &fp);
775100979Srwatson	if (error)
776100979Srwatson		goto out;
777100979Srwatson
778105694Srwatson	label_type = fp->f_type;
779100979Srwatson	switch (fp->f_type) {
780100979Srwatson	case DTYPE_FIFO:
781100979Srwatson	case DTYPE_VNODE:
782116678Sphk		vp = fp->f_vnode;
783122524Srwatson		intlabel = mac_vnode_label_alloc();
784150914Scsjp		vfslocked = VFS_LOCK_GIANT(vp->v_mount);
785100979Srwatson		vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
786122524Srwatson		mac_copy_vnode_label(vp->v_label, intlabel);
787100979Srwatson		VOP_UNLOCK(vp, 0, td);
788150914Scsjp		VFS_UNLOCK_GIANT(vfslocked);
789122584Srwatson		error = mac_externalize_vnode_label(intlabel, elements,
790122584Srwatson		    buffer, mac.m_buflen);
791122584Srwatson		mac_vnode_label_free(intlabel);
792122584Srwatson		break;
793105694Srwatson
794100979Srwatson	case DTYPE_PIPE:
795109153Sdillon		pipe = fp->f_data;
796122524Srwatson		intlabel = mac_pipe_label_alloc();
797105694Srwatson		PIPE_LOCK(pipe);
798125293Srwatson		mac_copy_pipe_label(pipe->pipe_pair->pp_label, intlabel);
799105694Srwatson		PIPE_UNLOCK(pipe);
800122524Srwatson		error = mac_externalize_pipe_label(intlabel, elements,
801122159Srwatson		    buffer, mac.m_buflen);
802122524Srwatson		mac_pipe_label_free(intlabel);
803105694Srwatson		break;
804122584Srwatson
805122820Srwatson	case DTYPE_SOCKET:
806122820Srwatson		so = fp->f_data;
807122820Srwatson		intlabel = mac_socket_label_alloc(M_WAITOK);
808145160Srwatson		NET_LOCK_GIANT();
809145160Srwatson		SOCK_LOCK(so);
810122820Srwatson		mac_copy_socket_label(so->so_label, intlabel);
811145160Srwatson		SOCK_UNLOCK(so);
812145160Srwatson		NET_UNLOCK_GIANT();
813122820Srwatson		error = mac_externalize_socket_label(intlabel, elements,
814122820Srwatson		    buffer, mac.m_buflen);
815122820Srwatson		mac_socket_label_free(intlabel);
816122820Srwatson		break;
817122820Srwatson
818105694Srwatson	default:
819122584Srwatson		error = EINVAL;
820105694Srwatson	}
821122584Srwatson	fdrop(fp, td);
822100979Srwatson	if (error == 0)
823105694Srwatson		error = copyout(buffer, mac.m_string, strlen(buffer)+1);
824100979Srwatson
825105694Srwatsonout:
826105694Srwatson	free(buffer, M_MACTEMP);
827105694Srwatson	free(elements, M_MACTEMP);
828100979Srwatson	return (error);
829100979Srwatson}
830100979Srwatson
831100979Srwatson/*
832100979Srwatson * MPSAFE
833100979Srwatson */
834100979Srwatsonint
835100979Srwatson__mac_get_file(struct thread *td, struct __mac_get_file_args *uap)
836100979Srwatson{
837105694Srwatson	char *elements, *buffer;
838100979Srwatson	struct nameidata nd;
839122524Srwatson	struct label *intlabel;
840105694Srwatson	struct mac mac;
841150914Scsjp	int vfslocked, error;
842100979Srwatson
843105694Srwatson	error = copyin(uap->mac_p, &mac, sizeof(mac));
844105694Srwatson	if (error)
845105694Srwatson		return (error);
846105694Srwatson
847105694Srwatson	error = mac_check_structmac_consistent(&mac);
848105694Srwatson	if (error)
849105694Srwatson		return (error);
850105694Srwatson
851111119Simp	elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
852105694Srwatson	error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
853105694Srwatson	if (error) {
854105694Srwatson		free(elements, M_MACTEMP);
855105694Srwatson		return (error);
856105694Srwatson	}
857105694Srwatson
858111119Simp	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
859150914Scsjp	NDINIT(&nd, LOOKUP, MPSAFE | LOCKLEAF | FOLLOW, UIO_USERSPACE,
860150914Scsjp	    uap->path_p, td);
861100979Srwatson	error = namei(&nd);
862100979Srwatson	if (error)
863100979Srwatson		goto out;
864100979Srwatson
865122524Srwatson	intlabel = mac_vnode_label_alloc();
866150914Scsjp	vfslocked = NDHASGIANT(&nd);
867122524Srwatson	mac_copy_vnode_label(nd.ni_vp->v_label, intlabel);
868122524Srwatson	error = mac_externalize_vnode_label(intlabel, elements, buffer,
869122159Srwatson	    mac.m_buflen);
870105694Srwatson
871100979Srwatson	NDFREE(&nd, 0);
872150914Scsjp	VFS_UNLOCK_GIANT(vfslocked);
873122524Srwatson	mac_vnode_label_free(intlabel);
874105694Srwatson	if (error == 0)
875105694Srwatson		error = copyout(buffer, mac.m_string, strlen(buffer)+1);
876105694Srwatson
877105694Srwatsonout:
878105694Srwatson	free(buffer, M_MACTEMP);
879105694Srwatson	free(elements, M_MACTEMP);
880105694Srwatson
881105694Srwatson	return (error);
882105694Srwatson}
883105694Srwatson
884105694Srwatson/*
885105694Srwatson * MPSAFE
886105694Srwatson */
887105694Srwatsonint
888105694Srwatson__mac_get_link(struct thread *td, struct __mac_get_link_args *uap)
889105694Srwatson{
890105694Srwatson	char *elements, *buffer;
891105694Srwatson	struct nameidata nd;
892122524Srwatson	struct label *intlabel;
893105694Srwatson	struct mac mac;
894150914Scsjp	int vfslocked, error;
895105694Srwatson
896105694Srwatson	error = copyin(uap->mac_p, &mac, sizeof(mac));
897100979Srwatson	if (error)
898105694Srwatson		return (error);
899105694Srwatson
900105694Srwatson	error = mac_check_structmac_consistent(&mac);
901105694Srwatson	if (error)
902105694Srwatson		return (error);
903105694Srwatson
904111119Simp	elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
905105694Srwatson	error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
906105694Srwatson	if (error) {
907105694Srwatson		free(elements, M_MACTEMP);
908105694Srwatson		return (error);
909105694Srwatson	}
910105694Srwatson
911111119Simp	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
912150914Scsjp	NDINIT(&nd, LOOKUP, MPSAFE | LOCKLEAF | NOFOLLOW, UIO_USERSPACE,
913150914Scsjp	    uap->path_p, td);
914105694Srwatson	error = namei(&nd);
915105694Srwatson	if (error)
916100979Srwatson		goto out;
917100979Srwatson
918122524Srwatson	intlabel = mac_vnode_label_alloc();
919150914Scsjp	vfslocked = NDHASGIANT(&nd);
920122524Srwatson	mac_copy_vnode_label(nd.ni_vp->v_label, intlabel);
921122524Srwatson	error = mac_externalize_vnode_label(intlabel, elements, buffer,
922122159Srwatson	    mac.m_buflen);
923105694Srwatson	NDFREE(&nd, 0);
924150914Scsjp	VFS_UNLOCK_GIANT(vfslocked);
925122524Srwatson	mac_vnode_label_free(intlabel);
926100979Srwatson
927105694Srwatson	if (error == 0)
928105694Srwatson		error = copyout(buffer, mac.m_string, strlen(buffer)+1);
929105694Srwatson
930100979Srwatsonout:
931105694Srwatson	free(buffer, M_MACTEMP);
932105694Srwatson	free(elements, M_MACTEMP);
933105694Srwatson
934100979Srwatson	return (error);
935100979Srwatson}
936100979Srwatson
937100979Srwatson/*
938100979Srwatson * MPSAFE
939100979Srwatson */
940100979Srwatsonint
941100979Srwatson__mac_set_fd(struct thread *td, struct __mac_set_fd_args *uap)
942100979Srwatson{
943122524Srwatson	struct label *intlabel;
944105694Srwatson	struct pipe *pipe;
945122820Srwatson	struct socket *so;
946100979Srwatson	struct file *fp;
947100979Srwatson	struct mount *mp;
948100979Srwatson	struct vnode *vp;
949105694Srwatson	struct mac mac;
950105694Srwatson	char *buffer;
951150914Scsjp	int error, vfslocked;
952100979Srwatson
953105694Srwatson	error = copyin(uap->mac_p, &mac, sizeof(mac));
954100979Srwatson	if (error)
955105694Srwatson		return (error);
956100979Srwatson
957105694Srwatson	error = mac_check_structmac_consistent(&mac);
958100979Srwatson	if (error)
959105694Srwatson		return (error);
960100979Srwatson
961111119Simp	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
962105694Srwatson	error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
963105694Srwatson	if (error) {
964105694Srwatson		free(buffer, M_MACTEMP);
965105694Srwatson		return (error);
966105694Srwatson	}
967105694Srwatson
968107849Salfred	error = fget(td, uap->fd, &fp);
969100979Srwatson	if (error)
970105694Srwatson		goto out;
971100979Srwatson
972100979Srwatson	switch (fp->f_type) {
973100979Srwatson	case DTYPE_FIFO:
974100979Srwatson	case DTYPE_VNODE:
975122524Srwatson		intlabel = mac_vnode_label_alloc();
976122524Srwatson		error = mac_internalize_vnode_label(intlabel, buffer);
977105694Srwatson		if (error) {
978122524Srwatson			mac_vnode_label_free(intlabel);
979105694Srwatson			break;
980105694Srwatson		}
981116678Sphk		vp = fp->f_vnode;
982150914Scsjp		vfslocked = VFS_LOCK_GIANT(vp->v_mount);
983100979Srwatson		error = vn_start_write(vp, &mp, V_WAIT | PCATCH);
984105694Srwatson		if (error != 0) {
985150914Scsjp			VFS_UNLOCK_GIANT(vfslocked);
986122524Srwatson			mac_vnode_label_free(intlabel);
987100979Srwatson			break;
988105694Srwatson		}
989100979Srwatson		vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
990122524Srwatson		error = vn_setlabel(vp, intlabel, td->td_ucred);
991100979Srwatson		VOP_UNLOCK(vp, 0, td);
992100979Srwatson		vn_finished_write(mp);
993150914Scsjp		VFS_UNLOCK_GIANT(vfslocked);
994122524Srwatson		mac_vnode_label_free(intlabel);
995100979Srwatson		break;
996105694Srwatson
997100979Srwatson	case DTYPE_PIPE:
998122524Srwatson		intlabel = mac_pipe_label_alloc();
999122524Srwatson		error = mac_internalize_pipe_label(intlabel, buffer);
1000105694Srwatson		if (error == 0) {
1001109153Sdillon			pipe = fp->f_data;
1002105694Srwatson			PIPE_LOCK(pipe);
1003125293Srwatson			error = mac_pipe_label_set(td->td_ucred,
1004125293Srwatson			    pipe->pipe_pair, intlabel);
1005105694Srwatson			PIPE_UNLOCK(pipe);
1006105694Srwatson		}
1007122524Srwatson		mac_pipe_label_free(intlabel);
1008100979Srwatson		break;
1009105694Srwatson
1010122820Srwatson	case DTYPE_SOCKET:
1011122820Srwatson		intlabel = mac_socket_label_alloc(M_WAITOK);
1012122820Srwatson		error = mac_internalize_socket_label(intlabel, buffer);
1013122820Srwatson		if (error == 0) {
1014122820Srwatson			so = fp->f_data;
1015145160Srwatson			NET_LOCK_GIANT();
1016122820Srwatson			error = mac_socket_label_set(td->td_ucred, so,
1017122820Srwatson			    intlabel);
1018145160Srwatson			NET_UNLOCK_GIANT();
1019122820Srwatson		}
1020122820Srwatson		mac_socket_label_free(intlabel);
1021122820Srwatson		break;
1022122820Srwatson
1023100979Srwatson	default:
1024100979Srwatson		error = EINVAL;
1025100979Srwatson	}
1026100979Srwatson	fdrop(fp, td);
1027105694Srwatsonout:
1028105694Srwatson	free(buffer, M_MACTEMP);
1029100979Srwatson	return (error);
1030100979Srwatson}
1031100979Srwatson
1032100979Srwatson/*
1033100979Srwatson * MPSAFE
1034100979Srwatson */
1035100979Srwatsonint
1036100979Srwatson__mac_set_file(struct thread *td, struct __mac_set_file_args *uap)
1037100979Srwatson{
1038122524Srwatson	struct label *intlabel;
1039100979Srwatson	struct nameidata nd;
1040100979Srwatson	struct mount *mp;
1041105694Srwatson	struct mac mac;
1042105694Srwatson	char *buffer;
1043150914Scsjp	int vfslocked, error;
1044100979Srwatson
1045105694Srwatson	error = copyin(uap->mac_p, &mac, sizeof(mac));
1046100979Srwatson	if (error)
1047105694Srwatson		return (error);
1048100979Srwatson
1049105694Srwatson	error = mac_check_structmac_consistent(&mac);
1050100979Srwatson	if (error)
1051105694Srwatson		return (error);
1052100979Srwatson
1053111119Simp	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
1054105694Srwatson	error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
1055105694Srwatson	if (error) {
1056105694Srwatson		free(buffer, M_MACTEMP);
1057105694Srwatson		return (error);
1058105694Srwatson	}
1059105694Srwatson
1060122524Srwatson	intlabel = mac_vnode_label_alloc();
1061122524Srwatson	error = mac_internalize_vnode_label(intlabel, buffer);
1062105694Srwatson	free(buffer, M_MACTEMP);
1063122524Srwatson	if (error)
1064122524Srwatson		goto out;
1065105694Srwatson
1066150914Scsjp	NDINIT(&nd, LOOKUP, MPSAFE | LOCKLEAF | FOLLOW, UIO_USERSPACE,
1067150914Scsjp	    uap->path_p, td);
1068100979Srwatson	error = namei(&nd);
1069150914Scsjp	vfslocked = NDHASGIANT(&nd);
1070105694Srwatson	if (error == 0) {
1071105694Srwatson		error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH);
1072105694Srwatson		if (error == 0)
1073122524Srwatson			error = vn_setlabel(nd.ni_vp, intlabel,
1074105694Srwatson			    td->td_ucred);
1075105694Srwatson		vn_finished_write(mp);
1076105694Srwatson	}
1077105694Srwatson
1078105694Srwatson	NDFREE(&nd, 0);
1079150914Scsjp	VFS_UNLOCK_GIANT(vfslocked);
1080122524Srwatsonout:
1081122524Srwatson	mac_vnode_label_free(intlabel);
1082105694Srwatson	return (error);
1083105694Srwatson}
1084105694Srwatson
1085105694Srwatson/*
1086105694Srwatson * MPSAFE
1087105694Srwatson */
1088105694Srwatsonint
1089105694Srwatson__mac_set_link(struct thread *td, struct __mac_set_link_args *uap)
1090105694Srwatson{
1091122524Srwatson	struct label *intlabel;
1092105694Srwatson	struct nameidata nd;
1093105694Srwatson	struct mount *mp;
1094105694Srwatson	struct mac mac;
1095105694Srwatson	char *buffer;
1096150914Scsjp	int vfslocked, error;
1097105694Srwatson
1098105694Srwatson	error = copyin(uap->mac_p, &mac, sizeof(mac));
1099100979Srwatson	if (error)
1100105694Srwatson		return (error);
1101105694Srwatson
1102105694Srwatson	error = mac_check_structmac_consistent(&mac);
1103100979Srwatson	if (error)
1104105694Srwatson		return (error);
1105100979Srwatson
1106111119Simp	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
1107105694Srwatson	error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
1108105694Srwatson	if (error) {
1109105694Srwatson		free(buffer, M_MACTEMP);
1110105694Srwatson		return (error);
1111105694Srwatson	}
1112105694Srwatson
1113122524Srwatson	intlabel = mac_vnode_label_alloc();
1114122524Srwatson	error = mac_internalize_vnode_label(intlabel, buffer);
1115105694Srwatson	free(buffer, M_MACTEMP);
1116122524Srwatson	if (error)
1117122524Srwatson		goto out;
1118105694Srwatson
1119150914Scsjp	NDINIT(&nd, LOOKUP, MPSAFE | LOCKLEAF | NOFOLLOW, UIO_USERSPACE,
1120150914Scsjp	    uap->path_p, td);
1121105694Srwatson	error = namei(&nd);
1122150914Scsjp	vfslocked = NDHASGIANT(&nd);
1123105694Srwatson	if (error == 0) {
1124105694Srwatson		error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH);
1125105694Srwatson		if (error == 0)
1126122524Srwatson			error = vn_setlabel(nd.ni_vp, intlabel,
1127105694Srwatson			    td->td_ucred);
1128105694Srwatson		vn_finished_write(mp);
1129105694Srwatson	}
1130105694Srwatson
1131100979Srwatson	NDFREE(&nd, 0);
1132150914Scsjp	VFS_UNLOCK_GIANT(vfslocked);
1133122524Srwatsonout:
1134122524Srwatson	mac_vnode_label_free(intlabel);
1135100979Srwatson	return (error);
1136100979Srwatson}
1137100979Srwatson
1138105694Srwatson/*
1139105694Srwatson * MPSAFE
1140105694Srwatson */
1141102123Srwatsonint
1142102123Srwatsonmac_syscall(struct thread *td, struct mac_syscall_args *uap)
1143102123Srwatson{
1144102123Srwatson	struct mac_policy_conf *mpc;
1145102123Srwatson	char target[MAC_MAX_POLICY_NAME];
1146114806Srwatson	int entrycount, error;
1147102123Srwatson
1148107849Salfred	error = copyinstr(uap->policy, target, sizeof(target), NULL);
1149102123Srwatson	if (error)
1150102123Srwatson		return (error);
1151102123Srwatson
1152102123Srwatson	error = ENOSYS;
1153119494Srwatson	LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) {
1154102123Srwatson		if (strcmp(mpc->mpc_name, target) == 0 &&
1155102123Srwatson		    mpc->mpc_ops->mpo_syscall != NULL) {
1156102123Srwatson			error = mpc->mpc_ops->mpo_syscall(td,
1157107849Salfred			    uap->call, uap->arg);
1158102123Srwatson			goto out;
1159102123Srwatson		}
1160102123Srwatson	}
1161102123Srwatson
1162114806Srwatson	if ((entrycount = mac_policy_list_conditional_busy()) != 0) {
1163114806Srwatson		LIST_FOREACH(mpc, &mac_policy_list, mpc_list) {
1164114806Srwatson			if (strcmp(mpc->mpc_name, target) == 0 &&
1165114806Srwatson			    mpc->mpc_ops->mpo_syscall != NULL) {
1166114806Srwatson				error = mpc->mpc_ops->mpo_syscall(td,
1167114806Srwatson				    uap->call, uap->arg);
1168114806Srwatson				break;
1169114806Srwatson			}
1170114806Srwatson		}
1171114806Srwatson		mac_policy_list_unbusy();
1172114806Srwatson	}
1173102123Srwatsonout:
1174102123Srwatson	return (error);
1175102123Srwatson}
1176102123Srwatson
1177100979SrwatsonSYSINIT(mac, SI_SUB_MAC, SI_ORDER_FIRST, mac_init, NULL);
1178100979SrwatsonSYSINIT(mac_late, SI_SUB_MAC_LATE, SI_ORDER_FIRST, mac_late_init, NULL);
1179100979Srwatson
1180100979Srwatson#else /* !MAC */
1181100979Srwatson
1182100979Srwatsonint
1183105694Srwatson__mac_get_pid(struct thread *td, struct __mac_get_pid_args *uap)
1184105694Srwatson{
1185105694Srwatson
1186105694Srwatson	return (ENOSYS);
1187105694Srwatson}
1188105694Srwatson
1189105694Srwatsonint
1190100979Srwatson__mac_get_proc(struct thread *td, struct __mac_get_proc_args *uap)
1191100979Srwatson{
1192100979Srwatson
1193100894Srwatson	return (ENOSYS);
1194100894Srwatson}
1195100894Srwatson
1196100894Srwatsonint
1197100894Srwatson__mac_set_proc(struct thread *td, struct __mac_set_proc_args *uap)
1198100894Srwatson{
1199100894Srwatson
1200100894Srwatson	return (ENOSYS);
1201100894Srwatson}
1202100894Srwatson
1203100894Srwatsonint
1204100894Srwatson__mac_get_fd(struct thread *td, struct __mac_get_fd_args *uap)
1205100894Srwatson{
1206100894Srwatson
1207100894Srwatson	return (ENOSYS);
1208100894Srwatson}
1209100894Srwatson
1210100894Srwatsonint
1211100894Srwatson__mac_get_file(struct thread *td, struct __mac_get_file_args *uap)
1212100894Srwatson{
1213100894Srwatson
1214100894Srwatson	return (ENOSYS);
1215100894Srwatson}
1216100894Srwatson
1217100894Srwatsonint
1218105694Srwatson__mac_get_link(struct thread *td, struct __mac_get_link_args *uap)
1219105694Srwatson{
1220105694Srwatson
1221105694Srwatson	return (ENOSYS);
1222105694Srwatson}
1223105694Srwatson
1224105694Srwatsonint
1225100894Srwatson__mac_set_fd(struct thread *td, struct __mac_set_fd_args *uap)
1226100894Srwatson{
1227100894Srwatson
1228100894Srwatson	return (ENOSYS);
1229100894Srwatson}
1230100894Srwatson
1231100894Srwatsonint
1232100894Srwatson__mac_set_file(struct thread *td, struct __mac_set_file_args *uap)
1233100894Srwatson{
1234100894Srwatson
1235100894Srwatson	return (ENOSYS);
1236100894Srwatson}
1237100979Srwatson
1238102123Srwatsonint
1239105694Srwatson__mac_set_link(struct thread *td, struct __mac_set_link_args *uap)
1240105694Srwatson{
1241105694Srwatson
1242105694Srwatson	return (ENOSYS);
1243105694Srwatson}
1244105694Srwatson
1245105694Srwatsonint
1246102123Srwatsonmac_syscall(struct thread *td, struct mac_syscall_args *uap)
1247102123Srwatson{
1248102123Srwatson
1249102123Srwatson	return (ENOSYS);
1250102123Srwatson}
1251102123Srwatson
1252128901Srwatson#endif /* !MAC */
1253