xref: /freebsd/sys/security/mac_veriexec/mac_veriexec.c (revision 7029da5c36f2d3cf6bb6c81bf551229f416399e8)
1fb47a376SStephen J. Kiernan /*
2fb47a376SStephen J. Kiernan  * $FreeBSD$
3fb47a376SStephen J. Kiernan  *
4ed377cf4SStephen J. Kiernan  * Copyright (c) 2011, 2012, 2013, 2015, 2016, 2019 Juniper Networks, Inc.
5fb47a376SStephen J. Kiernan  * All rights reserved.
6fb47a376SStephen J. Kiernan  *
7fb47a376SStephen J. Kiernan  * Redistribution and use in source and binary forms, with or without
8fb47a376SStephen J. Kiernan  * modification, are permitted provided that the following conditions
9fb47a376SStephen J. Kiernan  * are met:
10fb47a376SStephen J. Kiernan  * 1. Redistributions of source code must retain the above copyright
11fb47a376SStephen J. Kiernan  *    notice, this list of conditions and the following disclaimer.
12fb47a376SStephen J. Kiernan  * 2. Redistributions in binary form must reproduce the above copyright
13fb47a376SStephen J. Kiernan  *    notice, this list of conditions and the following disclaimer in the
14fb47a376SStephen J. Kiernan  *    documentation and/or other materials provided with the distribution.
15fb47a376SStephen J. Kiernan  *
16fb47a376SStephen J. Kiernan  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17fb47a376SStephen J. Kiernan  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18fb47a376SStephen J. Kiernan  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19fb47a376SStephen J. Kiernan  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20fb47a376SStephen J. Kiernan  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21fb47a376SStephen J. Kiernan  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22fb47a376SStephen J. Kiernan  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23fb47a376SStephen J. Kiernan  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24fb47a376SStephen J. Kiernan  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25fb47a376SStephen J. Kiernan  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26fb47a376SStephen J. Kiernan  * SUCH DAMAGE.
27fb47a376SStephen J. Kiernan  */
28fb47a376SStephen J. Kiernan 
29fb47a376SStephen J. Kiernan #include <sys/cdefs.h>
30fb47a376SStephen J. Kiernan 
31fb47a376SStephen J. Kiernan #include "opt_capsicum.h"
32fb47a376SStephen J. Kiernan #include "opt_mac.h"
33fb47a376SStephen J. Kiernan 
34fb47a376SStephen J. Kiernan #include <sys/param.h>
35fb47a376SStephen J. Kiernan #include <sys/systm.h>
36fb47a376SStephen J. Kiernan #include <sys/capsicum.h>
37fb47a376SStephen J. Kiernan #include <sys/eventhandler.h>
38fb47a376SStephen J. Kiernan #include <sys/fcntl.h>
39fb47a376SStephen J. Kiernan #include <sys/file.h>
40fb47a376SStephen J. Kiernan #include <sys/filedesc.h>
41fb47a376SStephen J. Kiernan #include <sys/imgact.h>
42fb47a376SStephen J. Kiernan #include <sys/jail.h>
43fb47a376SStephen J. Kiernan #include <sys/kernel.h>
44fb47a376SStephen J. Kiernan #include <sys/mac.h>
45fb47a376SStephen J. Kiernan #include <sys/mount.h>
46fb47a376SStephen J. Kiernan #include <sys/namei.h>
47fb47a376SStephen J. Kiernan #include <sys/priv.h>
48fb47a376SStephen J. Kiernan #include <sys/proc.h>
49fb47a376SStephen J. Kiernan #include <sys/sbuf.h>
50fb47a376SStephen J. Kiernan #include <sys/stat.h>
51fb47a376SStephen J. Kiernan #include <sys/sysctl.h>
52fb47a376SStephen J. Kiernan #include <sys/vnode.h>
53fb47a376SStephen J. Kiernan #include <fs/nullfs/null.h>
54fb47a376SStephen J. Kiernan #include <security/mac/mac_policy.h>
55fb47a376SStephen J. Kiernan 
56fb47a376SStephen J. Kiernan #include "mac_veriexec.h"
57fb47a376SStephen J. Kiernan #include "mac_veriexec_internal.h"
58fb47a376SStephen J. Kiernan 
59fb47a376SStephen J. Kiernan #define	SLOT(l) \
60fb47a376SStephen J. Kiernan 	mac_label_get((l), mac_veriexec_slot)
61fb47a376SStephen J. Kiernan #define	SLOT_SET(l, v) \
62fb47a376SStephen J. Kiernan 	mac_label_set((l), mac_veriexec_slot, (v))
63fb47a376SStephen J. Kiernan 
64fb47a376SStephen J. Kiernan #ifdef MAC_DEBUG
65fb47a376SStephen J. Kiernan #define	MAC_VERIEXEC_DBG(_lvl, _fmt, ...)				\
66fb47a376SStephen J. Kiernan 	do {								\
67fb47a376SStephen J. Kiernan 		VERIEXEC_DEBUG((_lvl), (MAC_VERIEXEC_FULLNAME ": " _fmt	\
68fb47a376SStephen J. Kiernan 		     "\n", ##__VA_ARGS__));				\
69fb47a376SStephen J. Kiernan 	} while(0)
70fb47a376SStephen J. Kiernan #else
71fb47a376SStephen J. Kiernan #define	MAC_VERIEXEC_DBG(_lvl, _fmt, ...)
72fb47a376SStephen J. Kiernan #endif
73fb47a376SStephen J. Kiernan 
74fb47a376SStephen J. Kiernan static int sysctl_mac_veriexec_state(SYSCTL_HANDLER_ARGS);
75fb47a376SStephen J. Kiernan static int sysctl_mac_veriexec_db(SYSCTL_HANDLER_ARGS);
76fb47a376SStephen J. Kiernan 
77fb47a376SStephen J. Kiernan SYSCTL_DECL(_security_mac);
78fb47a376SStephen J. Kiernan 
79*7029da5cSPawel Biernacki SYSCTL_NODE(_security_mac, OID_AUTO, veriexec, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
80fb47a376SStephen J. Kiernan     "MAC/veriexec policy controls");
81fb47a376SStephen J. Kiernan 
82fb47a376SStephen J. Kiernan int	mac_veriexec_debug;
83fb47a376SStephen J. Kiernan SYSCTL_INT(_security_mac_veriexec, OID_AUTO, debug, CTLFLAG_RW,
84fb47a376SStephen J. Kiernan     &mac_veriexec_debug, 0, "Debug level");
85fb47a376SStephen J. Kiernan 
86fb47a376SStephen J. Kiernan static int	mac_veriexec_state;
87fb47a376SStephen J. Kiernan SYSCTL_PROC(_security_mac_veriexec, OID_AUTO, state,
88*7029da5cSPawel Biernacki     CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_NEEDGIANT,
89*7029da5cSPawel Biernacki     0, 0, sysctl_mac_veriexec_state, "A",
90fb47a376SStephen J. Kiernan     "Verified execution subsystem state");
91fb47a376SStephen J. Kiernan 
92fb47a376SStephen J. Kiernan SYSCTL_PROC(_security_mac_veriexec, OID_AUTO, db,
93*7029da5cSPawel Biernacki     CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_SKIP | CTLFLAG_NEEDGIANT,
94*7029da5cSPawel Biernacki     0, 0, sysctl_mac_veriexec_db,
95fb47a376SStephen J. Kiernan     "A", "Verified execution fingerprint database");
96fb47a376SStephen J. Kiernan 
97fb47a376SStephen J. Kiernan static int mac_veriexec_slot;
98fb47a376SStephen J. Kiernan 
99fb47a376SStephen J. Kiernan MALLOC_DEFINE(M_VERIEXEC, "veriexec", "Verified execution data");
100fb47a376SStephen J. Kiernan 
101fb47a376SStephen J. Kiernan /**
102fb47a376SStephen J. Kiernan  * @internal
103fb47a376SStephen J. Kiernan  * @brief Handler for security.mac.veriexec.db sysctl
104fb47a376SStephen J. Kiernan  *
105fb47a376SStephen J. Kiernan  * Display a human-readable form of the current fingerprint database.
106fb47a376SStephen J. Kiernan  */
107fb47a376SStephen J. Kiernan static int
108fb47a376SStephen J. Kiernan sysctl_mac_veriexec_db(SYSCTL_HANDLER_ARGS)
109fb47a376SStephen J. Kiernan {
110fb47a376SStephen J. Kiernan 	struct sbuf sb;
111fb47a376SStephen J. Kiernan 	int error;
112fb47a376SStephen J. Kiernan 
113fb47a376SStephen J. Kiernan 	error = sysctl_wire_old_buffer(req, 0);
114fb47a376SStephen J. Kiernan 	if (error != 0)
115fb47a376SStephen J. Kiernan 		return (error);
116fb47a376SStephen J. Kiernan 
117fb47a376SStephen J. Kiernan 	sbuf_new_for_sysctl(&sb, NULL, 1024, req);
1181db017d0SStephen J. Kiernan 	mac_veriexec_metadata_print_db(&sb);
119fb47a376SStephen J. Kiernan 	error = sbuf_finish(&sb);
120fb47a376SStephen J. Kiernan 	sbuf_delete(&sb);
121fb47a376SStephen J. Kiernan 
122fb47a376SStephen J. Kiernan 	return (error);
123fb47a376SStephen J. Kiernan }
124fb47a376SStephen J. Kiernan 
125fb47a376SStephen J. Kiernan /**
126fb47a376SStephen J. Kiernan  * @internal
127fb47a376SStephen J. Kiernan  * @brief Generate human-readable output about the current verified execution
128fb47a376SStephen J. Kiernan  *        state.
129fb47a376SStephen J. Kiernan  *
130fb47a376SStephen J. Kiernan  * @param sbp		sbuf to write output to
131fb47a376SStephen J. Kiernan  */
132fb47a376SStephen J. Kiernan static void
133fb47a376SStephen J. Kiernan mac_veriexec_print_state(struct sbuf *sbp)
134fb47a376SStephen J. Kiernan {
135fb47a376SStephen J. Kiernan 
136fb47a376SStephen J. Kiernan 	if (mac_veriexec_state & VERIEXEC_STATE_INACTIVE)
137fb47a376SStephen J. Kiernan 		sbuf_printf(sbp, "inactive ");
138fb47a376SStephen J. Kiernan 	if (mac_veriexec_state & VERIEXEC_STATE_LOADED)
139fb47a376SStephen J. Kiernan 		sbuf_printf(sbp, "loaded ");
140fb47a376SStephen J. Kiernan 	if (mac_veriexec_state & VERIEXEC_STATE_ACTIVE)
141fb47a376SStephen J. Kiernan 		sbuf_printf(sbp, "active ");
142fb47a376SStephen J. Kiernan 	if (mac_veriexec_state & VERIEXEC_STATE_ENFORCE)
143fb47a376SStephen J. Kiernan 		sbuf_printf(sbp, "enforce ");
144fb47a376SStephen J. Kiernan 	if (mac_veriexec_state & VERIEXEC_STATE_LOCKED)
145fb47a376SStephen J. Kiernan 		sbuf_printf(sbp, "locked ");
146fb47a376SStephen J. Kiernan 	if (mac_veriexec_state != 0)
147fb47a376SStephen J. Kiernan 		sbuf_trim(sbp);
148fb47a376SStephen J. Kiernan }
149fb47a376SStephen J. Kiernan 
150fb47a376SStephen J. Kiernan /**
151fb47a376SStephen J. Kiernan  * @internal
152fb47a376SStephen J. Kiernan  * @brief Handler for security.mac.veriexec.state sysctl
153fb47a376SStephen J. Kiernan  *
154fb47a376SStephen J. Kiernan  * Display a human-readable form of the current verified execution subsystem
155fb47a376SStephen J. Kiernan  * state.
156fb47a376SStephen J. Kiernan  */
157fb47a376SStephen J. Kiernan static int
158fb47a376SStephen J. Kiernan sysctl_mac_veriexec_state(SYSCTL_HANDLER_ARGS)
159fb47a376SStephen J. Kiernan {
160fb47a376SStephen J. Kiernan 	struct sbuf sb;
161fb47a376SStephen J. Kiernan 	int error;
162fb47a376SStephen J. Kiernan 
163fb47a376SStephen J. Kiernan 	sbuf_new(&sb, NULL, 128, SBUF_AUTOEXTEND);
164fb47a376SStephen J. Kiernan 	mac_veriexec_print_state(&sb);
165fb47a376SStephen J. Kiernan 	sbuf_finish(&sb);
166fb47a376SStephen J. Kiernan 
167fb47a376SStephen J. Kiernan 	error = SYSCTL_OUT(req, sbuf_data(&sb), sbuf_len(&sb));
168fb47a376SStephen J. Kiernan 	sbuf_delete(&sb);
169fb47a376SStephen J. Kiernan 	return (error);
170fb47a376SStephen J. Kiernan }
171fb47a376SStephen J. Kiernan 
172fb47a376SStephen J. Kiernan /**
173fb47a376SStephen J. Kiernan  * @internal
174fb47a376SStephen J. Kiernan  * @brief Event handler called when a virtual file system is mounted.
175fb47a376SStephen J. Kiernan  *
176fb47a376SStephen J. Kiernan  * We need to record the file system identifier in the MAC per-policy slot
177fb47a376SStephen J. Kiernan  * assigned to veriexec, so we have a key to use in order to reference the
178fb47a376SStephen J. Kiernan  * mount point in the meta-data store.
179fb47a376SStephen J. Kiernan  *
180fb47a376SStephen J. Kiernan  * @param arg		unused argument
181fb47a376SStephen J. Kiernan  * @param mp		mount point that is being mounted
182fb47a376SStephen J. Kiernan  * @param fsrootvp	vnode of the file system root
183fb47a376SStephen J. Kiernan  * @param td		calling thread
184fb47a376SStephen J. Kiernan  */
185fb47a376SStephen J. Kiernan static void
186fb47a376SStephen J. Kiernan mac_veriexec_vfs_mounted(void *arg __unused, struct mount *mp,
187fb47a376SStephen J. Kiernan     struct vnode *fsrootvp, struct thread *td)
188fb47a376SStephen J. Kiernan {
189fb47a376SStephen J. Kiernan 	struct vattr va;
190fb47a376SStephen J. Kiernan 	int error;
191fb47a376SStephen J. Kiernan 
192fb47a376SStephen J. Kiernan 	error = VOP_GETATTR(fsrootvp, &va, td->td_ucred);
193fb47a376SStephen J. Kiernan 	if (error)
194fb47a376SStephen J. Kiernan 		return;
195fb47a376SStephen J. Kiernan 
196fb47a376SStephen J. Kiernan 	SLOT_SET(mp->mnt_label, va.va_fsid);
197fb47a376SStephen J. Kiernan #ifdef MAC_DEBUG
1983d53cd0fSStephen J. Kiernan 	MAC_VERIEXEC_DBG(3, "set fsid to %ju for mount %p",
1993d53cd0fSStephen J. Kiernan 	    (uintmax_t)va.va_fsid, mp);
200fb47a376SStephen J. Kiernan #endif
201fb47a376SStephen J. Kiernan }
202fb47a376SStephen J. Kiernan 
203fb47a376SStephen J. Kiernan /**
204fb47a376SStephen J. Kiernan  * @internal
205fb47a376SStephen J. Kiernan  * @brief Event handler called when a virtual file system is unmounted.
206fb47a376SStephen J. Kiernan  *
207fb47a376SStephen J. Kiernan  * If we recorded a file system identifier in the MAC per-policy slot assigned
208fb47a376SStephen J. Kiernan  * to veriexec, then we need to tell the meta-data store to clean up.
209fb47a376SStephen J. Kiernan  *
210fb47a376SStephen J. Kiernan  * @param arg		unused argument
211fb47a376SStephen J. Kiernan  * @param mp		mount point that is being unmounted
212fb47a376SStephen J. Kiernan  * @param td		calling thread
213fb47a376SStephen J. Kiernan  */
214fb47a376SStephen J. Kiernan static void
215fb47a376SStephen J. Kiernan mac_veriexec_vfs_unmounted(void *arg __unused, struct mount *mp,
216fb47a376SStephen J. Kiernan     struct thread *td)
217fb47a376SStephen J. Kiernan {
218fb47a376SStephen J. Kiernan 	dev_t fsid;
219fb47a376SStephen J. Kiernan 
220fb47a376SStephen J. Kiernan 	fsid = SLOT(mp->mnt_label);
221fb47a376SStephen J. Kiernan 	if (fsid) {
2223d53cd0fSStephen J. Kiernan 		MAC_VERIEXEC_DBG(3, "fsid %ju, cleaning up mount",
2233d53cd0fSStephen J. Kiernan 		    (uintmax_t)fsid);
224fb47a376SStephen J. Kiernan 		mac_veriexec_metadata_unmounted(fsid, td);
225fb47a376SStephen J. Kiernan 	}
226fb47a376SStephen J. Kiernan }
227fb47a376SStephen J. Kiernan 
228fb47a376SStephen J. Kiernan /**
229fb47a376SStephen J. Kiernan  * @internal
230fb47a376SStephen J. Kiernan  * @brief The mount point is being initialized, set the value in the MAC
231fb47a376SStephen J. Kiernan  *     per-policy slot for veriexec to zero.
232fb47a376SStephen J. Kiernan  *
233fb47a376SStephen J. Kiernan  * @note A value of zero in this slot indicates no file system identifier
234fb47a376SStephen J. Kiernan  *     is assigned.
235fb47a376SStephen J. Kiernan  *
236fb47a376SStephen J. Kiernan  * @param label the label that is being initialized
237fb47a376SStephen J. Kiernan  */
238fb47a376SStephen J. Kiernan static void
239fb47a376SStephen J. Kiernan mac_veriexec_mount_init_label(struct label *label)
240fb47a376SStephen J. Kiernan {
241fb47a376SStephen J. Kiernan 
242fb47a376SStephen J. Kiernan 	SLOT_SET(label, 0);
243fb47a376SStephen J. Kiernan }
244fb47a376SStephen J. Kiernan 
245fb47a376SStephen J. Kiernan /**
246fb47a376SStephen J. Kiernan  * @internal
247fb47a376SStephen J. Kiernan  * @brief The mount-point is being destroyed, reset the value in the MAC
248fb47a376SStephen J. Kiernan  *     per-policy slot for veriexec back to zero.
249fb47a376SStephen J. Kiernan  *
250fb47a376SStephen J. Kiernan  * @note A value of zero in this slot indicates no file system identifier
251fb47a376SStephen J. Kiernan  *     is assigned.
252fb47a376SStephen J. Kiernan  *
253fb47a376SStephen J. Kiernan  * @param label the label that is being destroyed
254fb47a376SStephen J. Kiernan  */
255fb47a376SStephen J. Kiernan static void
256fb47a376SStephen J. Kiernan mac_veriexec_mount_destroy_label(struct label *label)
257fb47a376SStephen J. Kiernan {
258fb47a376SStephen J. Kiernan 
259fb47a376SStephen J. Kiernan 	SLOT_SET(label, 0);
260fb47a376SStephen J. Kiernan }
261fb47a376SStephen J. Kiernan 
262fb47a376SStephen J. Kiernan /**
263fb47a376SStephen J. Kiernan  * @internal
264fb47a376SStephen J. Kiernan  * @brief The vnode label is being initialized, set the value in the MAC
265fb47a376SStephen J. Kiernan  *     per-policy slot for veriexec to @c FINGERPRINT_INVALID
266fb47a376SStephen J. Kiernan  *
267fb47a376SStephen J. Kiernan  * @note @c FINGERPRINT_INVALID indicates the fingerprint is invalid.
268fb47a376SStephen J. Kiernan  *
269fb47a376SStephen J. Kiernan  * @param label		the label that is being initialized
270fb47a376SStephen J. Kiernan  */
271fb47a376SStephen J. Kiernan static void
272fb47a376SStephen J. Kiernan mac_veriexec_vnode_init_label(struct label *label)
273fb47a376SStephen J. Kiernan {
274fb47a376SStephen J. Kiernan 
275fb47a376SStephen J. Kiernan 	SLOT_SET(label, FINGERPRINT_INVALID);
276fb47a376SStephen J. Kiernan }
277fb47a376SStephen J. Kiernan 
278fb47a376SStephen J. Kiernan /**
279fb47a376SStephen J. Kiernan  * @internal
280fb47a376SStephen J. Kiernan  * @brief The vnode label is being destroyed, reset the value in the MAC
281fb47a376SStephen J. Kiernan  *        per-policy slot for veriexec back to @c FINGERPRINT_INVALID
282fb47a376SStephen J. Kiernan  *
283fb47a376SStephen J. Kiernan  * @note @c FINGERPRINT_INVALID indicates the fingerprint is invalid.
284fb47a376SStephen J. Kiernan  *
285fb47a376SStephen J. Kiernan  * @param label		the label that is being destroyed
286fb47a376SStephen J. Kiernan  */
287fb47a376SStephen J. Kiernan static void
288fb47a376SStephen J. Kiernan mac_veriexec_vnode_destroy_label(struct label *label)
289fb47a376SStephen J. Kiernan {
290fb47a376SStephen J. Kiernan 
291fb47a376SStephen J. Kiernan 	SLOT_SET(label, FINGERPRINT_INVALID);
292fb47a376SStephen J. Kiernan }
293fb47a376SStephen J. Kiernan 
294fb47a376SStephen J. Kiernan /**
295fb47a376SStephen J. Kiernan  * @internal
296fb47a376SStephen J. Kiernan  * @brief Copy the value in the MAC per-policy slot assigned to veriexec from
297fb47a376SStephen J. Kiernan  *        the @p src label to the @p dest label
298fb47a376SStephen J. Kiernan  */
299fb47a376SStephen J. Kiernan static void
300fb47a376SStephen J. Kiernan mac_veriexec_copy_label(struct label *src, struct label *dest)
301fb47a376SStephen J. Kiernan {
302fb47a376SStephen J. Kiernan 
303fb47a376SStephen J. Kiernan 	SLOT_SET(dest, SLOT(src));
304fb47a376SStephen J. Kiernan }
305fb47a376SStephen J. Kiernan 
306fb47a376SStephen J. Kiernan /**
307fb47a376SStephen J. Kiernan  * @internal
308fb47a376SStephen J. Kiernan  * @brief Check if the requested process can be debugged
309fb47a376SStephen J. Kiernan  *
310fb47a376SStephen J. Kiernan  * @param cred		credentials to use
311fb47a376SStephen J. Kiernan  * @param p		process to debug
312fb47a376SStephen J. Kiernan  *
313fb47a376SStephen J. Kiernan  * @return 0 if debugging is allowed, otherwise an error code.
314fb47a376SStephen J. Kiernan  */
315fb47a376SStephen J. Kiernan static int
316fb47a376SStephen J. Kiernan mac_veriexec_proc_check_debug(struct ucred *cred, struct proc *p)
317fb47a376SStephen J. Kiernan {
318fb47a376SStephen J. Kiernan 	int error, flags;
319fb47a376SStephen J. Kiernan 
320fb47a376SStephen J. Kiernan 	/* If we are not enforcing veriexec, nothing for us to check */
321fb47a376SStephen J. Kiernan 	if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0)
322fb47a376SStephen J. Kiernan 		return (0);
323fb47a376SStephen J. Kiernan 
324fb47a376SStephen J. Kiernan 	error = mac_veriexec_metadata_get_executable_flags(cred, p, &flags, 0);
325fb47a376SStephen J. Kiernan 	if (error != 0)
326fb47a376SStephen J. Kiernan 		return (0);
327fb47a376SStephen J. Kiernan 
328fb47a376SStephen J. Kiernan 	return ((flags & VERIEXEC_NOTRACE) ? EACCES : 0);
329fb47a376SStephen J. Kiernan }
330fb47a376SStephen J. Kiernan 
331fb47a376SStephen J. Kiernan /**
332fb47a376SStephen J. Kiernan  * @internal
333fb47a376SStephen J. Kiernan  * @brief A KLD load has been requested and needs to be validated.
334fb47a376SStephen J. Kiernan  *
335fb47a376SStephen J. Kiernan  * @param cred		credentials to use
336fb47a376SStephen J. Kiernan  * @param vp		vnode of the KLD that has been requested
337fb47a376SStephen J. Kiernan  * @param vlabel	vnode label assigned to the vnode
338fb47a376SStephen J. Kiernan  *
339fb47a376SStephen J. Kiernan  * @return 0 if the KLD load is allowed, otherwise an error code.
340fb47a376SStephen J. Kiernan  */
341fb47a376SStephen J. Kiernan static int
342fb47a376SStephen J. Kiernan mac_veriexec_kld_check_load(struct ucred *cred, struct vnode *vp,
343fb47a376SStephen J. Kiernan     struct label *vlabel)
344fb47a376SStephen J. Kiernan {
345fb47a376SStephen J. Kiernan 	struct vattr va;
346fb47a376SStephen J. Kiernan 	struct thread *td = curthread;
347fb47a376SStephen J. Kiernan 	fingerprint_status_t status;
348fb47a376SStephen J. Kiernan 	int error;
349fb47a376SStephen J. Kiernan 
350fb47a376SStephen J. Kiernan 	/*
351fb47a376SStephen J. Kiernan 	 * If we are not actively enforcing, allow it
352fb47a376SStephen J. Kiernan 	 */
353fb47a376SStephen J. Kiernan 	if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0)
354fb47a376SStephen J. Kiernan 		return (0);
355fb47a376SStephen J. Kiernan 
356fb47a376SStephen J. Kiernan 	/* Get vnode attributes */
357fb47a376SStephen J. Kiernan 	error = VOP_GETATTR(vp, &va, cred);
358fb47a376SStephen J. Kiernan 	if (error)
359fb47a376SStephen J. Kiernan 		return (error);
360fb47a376SStephen J. Kiernan 
361fb47a376SStephen J. Kiernan 	/*
362fb47a376SStephen J. Kiernan 	 * Fetch the fingerprint status for the vnode
363fb47a376SStephen J. Kiernan 	 * (starting with files first)
364fb47a376SStephen J. Kiernan 	 */
365fb47a376SStephen J. Kiernan 	error = mac_veriexec_metadata_fetch_fingerprint_status(vp, &va, td,
366fb47a376SStephen J. Kiernan 	    VERIEXEC_FILES_FIRST);
367fb47a376SStephen J. Kiernan 	if (error && error != EAUTH)
368fb47a376SStephen J. Kiernan 		return (error);
369fb47a376SStephen J. Kiernan 
370fb47a376SStephen J. Kiernan 	/*
371fb47a376SStephen J. Kiernan 	 * By now we should have status...
372fb47a376SStephen J. Kiernan 	 */
373fb47a376SStephen J. Kiernan 	status = mac_veriexec_get_fingerprint_status(vp);
374fb47a376SStephen J. Kiernan 	switch (status) {
375fb47a376SStephen J. Kiernan 	case FINGERPRINT_FILE:
376fb47a376SStephen J. Kiernan 	case FINGERPRINT_VALID:
377fb47a376SStephen J. Kiernan 	case FINGERPRINT_INDIRECT:
378fb47a376SStephen J. Kiernan 		if (error)
379fb47a376SStephen J. Kiernan 			return (error);
380fb47a376SStephen J. Kiernan 		break;
381fb47a376SStephen J. Kiernan 	default:
382fb47a376SStephen J. Kiernan 		/*
383fb47a376SStephen J. Kiernan 		 * kldload should fail unless there is a valid fingerprint
384fb47a376SStephen J. Kiernan 		 * registered.
385fb47a376SStephen J. Kiernan 		 */
3863d53cd0fSStephen J. Kiernan 		MAC_VERIEXEC_DBG(2, "fingerprint status is %d for dev %ju, "
3873d53cd0fSStephen J. Kiernan 		    "file %ju.%ju\n", status, (uintmax_t)va.va_fsid,
3883d53cd0fSStephen J. Kiernan 		    (uintmax_t)va.va_fileid, (uintmax_t)va.va_gen);
389fb47a376SStephen J. Kiernan 		return (EAUTH);
390fb47a376SStephen J. Kiernan 	}
391fb47a376SStephen J. Kiernan 
392fb47a376SStephen J. Kiernan 	/* Everything is good, allow the KLD to be loaded */
393fb47a376SStephen J. Kiernan 	return (0);
394fb47a376SStephen J. Kiernan }
395fb47a376SStephen J. Kiernan 
396fb47a376SStephen J. Kiernan /**
397fb47a376SStephen J. Kiernan  * @internal
398fb47a376SStephen J. Kiernan  * @brief Check privileges that veriexec needs to be concerned about.
399fb47a376SStephen J. Kiernan  *
400fb47a376SStephen J. Kiernan  * The following privileges are checked by this function:
401fb47a376SStephen J. Kiernan  *  - PRIV_KMEM_WRITE\n
402fb47a376SStephen J. Kiernan  *    Check if writes to /dev/mem and /dev/kmem are allowed\n
403fb47a376SStephen J. Kiernan  *    (Only trusted processes are allowed)
404fb47a376SStephen J. Kiernan  *
405fb47a376SStephen J. Kiernan  * @param cred		credentials to use
406fb47a376SStephen J. Kiernan  * @param priv		privilege to check
407fb47a376SStephen J. Kiernan  *
408fb47a376SStephen J. Kiernan  * @return 0 if the privilege is allowed, error code otherwise.
409fb47a376SStephen J. Kiernan  */
410fb47a376SStephen J. Kiernan static int
411fb47a376SStephen J. Kiernan mac_veriexec_priv_check(struct ucred *cred, int priv)
412fb47a376SStephen J. Kiernan {
413fb47a376SStephen J. Kiernan 
414fb47a376SStephen J. Kiernan 	/* If we are not enforcing veriexec, nothing for us to check */
415fb47a376SStephen J. Kiernan 	if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0)
416fb47a376SStephen J. Kiernan 		return (0);
417fb47a376SStephen J. Kiernan 
418fb47a376SStephen J. Kiernan 	switch (priv) {
419fb47a376SStephen J. Kiernan 	case PRIV_KMEM_WRITE:
420fb47a376SStephen J. Kiernan 		if (!mac_veriexec_proc_is_trusted(cred, curproc))
421fb47a376SStephen J. Kiernan 			return (EPERM);
422fb47a376SStephen J. Kiernan 		break;
423fb47a376SStephen J. Kiernan 	default:
424fb47a376SStephen J. Kiernan 		break;
425fb47a376SStephen J. Kiernan 	}
426fb47a376SStephen J. Kiernan 	return (0);
427fb47a376SStephen J. Kiernan }
428fb47a376SStephen J. Kiernan 
429ed377cf4SStephen J. Kiernan static int
430ed377cf4SStephen J. Kiernan mac_veriexec_sysctl_check(struct ucred *cred, struct sysctl_oid *oidp,
431ed377cf4SStephen J. Kiernan     void *arg1, int arg2, struct sysctl_req *req)
432ed377cf4SStephen J. Kiernan {
433ed377cf4SStephen J. Kiernan 	struct sysctl_oid *oid;
434ed377cf4SStephen J. Kiernan 
435ed377cf4SStephen J. Kiernan 	/* If we are not enforcing veriexec, nothing for us to check */
436ed377cf4SStephen J. Kiernan 	if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0)
437ed377cf4SStephen J. Kiernan 		return (0);
438ed377cf4SStephen J. Kiernan 
439ed377cf4SStephen J. Kiernan 	oid = oidp;
440ed377cf4SStephen J. Kiernan 	if (oid->oid_kind & CTLFLAG_SECURE) {
441ed377cf4SStephen J. Kiernan 		return (EPERM);		/* XXX call mac_veriexec_priv_check? */
442ed377cf4SStephen J. Kiernan 	}
443ed377cf4SStephen J. Kiernan 	return 0;
444ed377cf4SStephen J. Kiernan }
445ed377cf4SStephen J. Kiernan 
446fb47a376SStephen J. Kiernan /**
447fb47a376SStephen J. Kiernan  * @internal
448fb47a376SStephen J. Kiernan  * @brief A program is being executed and needs to be validated.
449fb47a376SStephen J. Kiernan  *
450fb47a376SStephen J. Kiernan  * @param cred		credentials to use
451fb47a376SStephen J. Kiernan  * @param vp		vnode of the program that is being executed
452fb47a376SStephen J. Kiernan  * @param label		vnode label assigned to the vnode
453fb47a376SStephen J. Kiernan  * @param imgp		parameters for the image to be executed
454fb47a376SStephen J. Kiernan  * @param execlabel	optional exec label
455fb47a376SStephen J. Kiernan  *
456fb47a376SStephen J. Kiernan  * @return 0 if the program should be allowed to execute, otherwise an error
457fb47a376SStephen J. Kiernan  *     code.
458fb47a376SStephen J. Kiernan  */
459fb47a376SStephen J. Kiernan static int
460fb47a376SStephen J. Kiernan mac_veriexec_vnode_check_exec(struct ucred *cred __unused,
461fb47a376SStephen J. Kiernan     struct vnode *vp __unused, struct label *label __unused,
462fb47a376SStephen J. Kiernan     struct image_params *imgp, struct label *execlabel __unused)
463fb47a376SStephen J. Kiernan {
464fb47a376SStephen J. Kiernan 	struct thread *td = curthread;
465fb47a376SStephen J. Kiernan 	int error;
466fb47a376SStephen J. Kiernan 
467fb47a376SStephen J. Kiernan 	error = mac_veriexec_fingerprint_check_image(imgp, 0, td);
468fb47a376SStephen J. Kiernan 	return (error);
469fb47a376SStephen J. Kiernan }
470fb47a376SStephen J. Kiernan 
471fb47a376SStephen J. Kiernan /**
472fb47a376SStephen J. Kiernan  * @brief Check fingerprint for the specified vnode and validate it
473fb47a376SStephen J. Kiernan  *
474fb47a376SStephen J. Kiernan  * @param cred		credentials to use
475fb47a376SStephen J. Kiernan  * @param vp		vnode of the file
476fb47a376SStephen J. Kiernan  * @param accmode	access mode to check (read, write, append, create,
477fb47a376SStephen J. Kiernan  *			verify, etc.)
478fb47a376SStephen J. Kiernan  *
479fb47a376SStephen J. Kiernan  * @return 0 if the file validated, otherwise an error code.
480fb47a376SStephen J. Kiernan  */
481fb47a376SStephen J. Kiernan static int
482fb47a376SStephen J. Kiernan mac_veriexec_check_vp(struct ucred *cred, struct vnode *vp, accmode_t accmode)
483fb47a376SStephen J. Kiernan {
484fb47a376SStephen J. Kiernan 	struct vattr va;
485fb47a376SStephen J. Kiernan 	struct thread *td = curthread;
486fb47a376SStephen J. Kiernan 	fingerprint_status_t status;
487fb47a376SStephen J. Kiernan 	int error;
488fb47a376SStephen J. Kiernan 
489fb47a376SStephen J. Kiernan 	/* Get vnode attributes */
490fb47a376SStephen J. Kiernan 	error = VOP_GETATTR(vp, &va, cred);
491fb47a376SStephen J. Kiernan 	if (error)
492fb47a376SStephen J. Kiernan 		return (error);
493fb47a376SStephen J. Kiernan 
494fb47a376SStephen J. Kiernan 	/* Get the fingerprint status for the file */
495fb47a376SStephen J. Kiernan 	error = mac_veriexec_metadata_fetch_fingerprint_status(vp, &va, td,
496fb47a376SStephen J. Kiernan 	    VERIEXEC_FILES_FIRST);
497fb47a376SStephen J. Kiernan 	if (error && error != EAUTH)
498fb47a376SStephen J. Kiernan 		return (error);
499fb47a376SStephen J. Kiernan 
500fb47a376SStephen J. Kiernan 	/*
501fb47a376SStephen J. Kiernan 	 * By now we should have status...
502fb47a376SStephen J. Kiernan 	 */
503fb47a376SStephen J. Kiernan 	status = mac_veriexec_get_fingerprint_status(vp);
504fb47a376SStephen J. Kiernan 	if (accmode & VWRITE) {
505fb47a376SStephen J. Kiernan 		/*
506fb47a376SStephen J. Kiernan 		 * If file has a fingerprint then deny the write request,
507fb47a376SStephen J. Kiernan 		 * otherwise invalidate the status so we don't keep checking
508fb47a376SStephen J. Kiernan 		 * for the file having a fingerprint.
509fb47a376SStephen J. Kiernan 		 */
510fb47a376SStephen J. Kiernan 		switch (status) {
511fb47a376SStephen J. Kiernan 		case FINGERPRINT_FILE:
512fb47a376SStephen J. Kiernan 		case FINGERPRINT_VALID:
513fb47a376SStephen J. Kiernan 		case FINGERPRINT_INDIRECT:
514fb47a376SStephen J. Kiernan 			MAC_VERIEXEC_DBG(2,
515fb47a376SStephen J. Kiernan 			    "attempted write to fingerprinted file for dev "
5163d53cd0fSStephen J. Kiernan 			    "%ju, file %ju.%ju\n", (uintmax_t)va.va_fsid,
5173d53cd0fSStephen J. Kiernan 			    (uintmax_t)va.va_fileid, (uintmax_t)va.va_gen);
518fb47a376SStephen J. Kiernan 			return (EPERM);
519fb47a376SStephen J. Kiernan 		default:
520fb47a376SStephen J. Kiernan 			break;
521fb47a376SStephen J. Kiernan 		}
522fb47a376SStephen J. Kiernan 	}
523fb47a376SStephen J. Kiernan 	if (accmode & VVERIFY) {
524fb47a376SStephen J. Kiernan 		switch (status) {
525fb47a376SStephen J. Kiernan 		case FINGERPRINT_FILE:
526fb47a376SStephen J. Kiernan 		case FINGERPRINT_VALID:
527fb47a376SStephen J. Kiernan 		case FINGERPRINT_INDIRECT:
528fb47a376SStephen J. Kiernan 			if (error)
529fb47a376SStephen J. Kiernan 				return (error);
530fb47a376SStephen J. Kiernan 			break;
531fb47a376SStephen J. Kiernan 		default:
532fb47a376SStephen J. Kiernan 			/*
533fb47a376SStephen J. Kiernan 			 * Caller wants open to fail unless there is a valid
534fb47a376SStephen J. Kiernan 			 * fingerprint registered.
535fb47a376SStephen J. Kiernan 			 */
536fb47a376SStephen J. Kiernan 			MAC_VERIEXEC_DBG(2, "fingerprint status is %d for dev "
5373d53cd0fSStephen J. Kiernan 			    "%ju, file %ju.%ju\n", status,
5383d53cd0fSStephen J. Kiernan 			    (uintmax_t)va.va_fsid, (uintmax_t)va.va_fileid,
5393d53cd0fSStephen J. Kiernan 			    (uintmax_t)va.va_gen);
540fb47a376SStephen J. Kiernan 			return (EAUTH);
541fb47a376SStephen J. Kiernan 		}
542fb47a376SStephen J. Kiernan 	}
543fb47a376SStephen J. Kiernan 	return (0);
544fb47a376SStephen J. Kiernan }
545fb47a376SStephen J. Kiernan 
546fb47a376SStephen J. Kiernan /**
547fb47a376SStephen J. Kiernan  * @brief Opening a file has been requested and may need to be validated.
548fb47a376SStephen J. Kiernan  *
549fb47a376SStephen J. Kiernan  * @param cred		credentials to use
550fb47a376SStephen J. Kiernan  * @param vp		vnode of the file to open
551fb47a376SStephen J. Kiernan  * @param label		vnode label assigned to the vnode
552fb47a376SStephen J. Kiernan  * @param accmode	access mode to use for opening the file (read, write,
553fb47a376SStephen J. Kiernan  * 			append, create, verify, etc.)
554fb47a376SStephen J. Kiernan  *
555fb47a376SStephen J. Kiernan  * @return 0 if opening the file should be allowed, otherwise an error code.
556fb47a376SStephen J. Kiernan  */
557fb47a376SStephen J. Kiernan static int
558fb47a376SStephen J. Kiernan mac_veriexec_vnode_check_open(struct ucred *cred, struct vnode *vp,
559fb47a376SStephen J. Kiernan 	struct label *label __unused, accmode_t accmode)
560fb47a376SStephen J. Kiernan {
561fb47a376SStephen J. Kiernan 	int error;
562fb47a376SStephen J. Kiernan 
563fb47a376SStephen J. Kiernan 	/*
564fb47a376SStephen J. Kiernan 	 * Look for the file on the fingerprint lists iff it has not been seen
565fb47a376SStephen J. Kiernan 	 * before.
566fb47a376SStephen J. Kiernan 	 */
567fb47a376SStephen J. Kiernan 	if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0)
568fb47a376SStephen J. Kiernan 		return (0);
569fb47a376SStephen J. Kiernan 
570fb47a376SStephen J. Kiernan 	error = mac_veriexec_check_vp(cred, vp, accmode);
571fb47a376SStephen J. Kiernan 	return (error);
572fb47a376SStephen J. Kiernan }
573fb47a376SStephen J. Kiernan 
574fb47a376SStephen J. Kiernan /**
575ade97886SStephen J. Kiernan  * @brief Check mode changes on file to ensure they should be allowed.
576ade97886SStephen J. Kiernan  *
577ade97886SStephen J. Kiernan  * We cannot allow chmod of SUID or SGID on verified files.
578ade97886SStephen J. Kiernan  *
579ade97886SStephen J. Kiernan  * @param cred		credentials to use
580ade97886SStephen J. Kiernan  * @param vp		vnode of the file to open
581ade97886SStephen J. Kiernan  * @param label		vnode label assigned to the vnode
582ade97886SStephen J. Kiernan  * @param mode		mode flags to set
583ade97886SStephen J. Kiernan  *
584ade97886SStephen J. Kiernan  * @return 0 if the mode change should be allowed, EAUTH otherwise.
585ade97886SStephen J. Kiernan  */
586ade97886SStephen J. Kiernan static int
587ade97886SStephen J. Kiernan mac_veriexec_vnode_check_setmode(struct ucred *cred, struct vnode *vp,
588ade97886SStephen J. Kiernan     struct label *label __unused, mode_t mode)
589ade97886SStephen J. Kiernan {
590ade97886SStephen J. Kiernan 	int error;
591ade97886SStephen J. Kiernan 
592ade97886SStephen J. Kiernan 	if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0)
593ade97886SStephen J. Kiernan 		return (0);
594ade97886SStephen J. Kiernan 
595ade97886SStephen J. Kiernan 	/*
596ade97886SStephen J. Kiernan 	 * Do not allow chmod (set-[gu]id) of verified file
597ade97886SStephen J. Kiernan 	 */
598ade97886SStephen J. Kiernan 	error = mac_veriexec_check_vp(cred, vp, VVERIFY);
599ade97886SStephen J. Kiernan 	if (error == EAUTH)             /* it isn't verified */
600ade97886SStephen J. Kiernan 		return (0);
601ade97886SStephen J. Kiernan 	if (error == 0 && (mode & (S_ISUID|S_ISGID)) != 0)
602ade97886SStephen J. Kiernan 		return (EAUTH);
603ade97886SStephen J. Kiernan 	return (0);
604ade97886SStephen J. Kiernan }
605ade97886SStephen J. Kiernan 
606ade97886SStephen J. Kiernan /**
607fb47a376SStephen J. Kiernan  * @internal
608fb47a376SStephen J. Kiernan  * @brief Initialize the mac_veriexec MAC policy
609fb47a376SStephen J. Kiernan  *
610fb47a376SStephen J. Kiernan  * @param mpc		MAC policy configuration
611fb47a376SStephen J. Kiernan  */
612fb47a376SStephen J. Kiernan static void
613fb47a376SStephen J. Kiernan mac_veriexec_init(struct mac_policy_conf *mpc __unused)
614fb47a376SStephen J. Kiernan {
615fb47a376SStephen J. Kiernan 	/* Initialize state */
616fb47a376SStephen J. Kiernan 	mac_veriexec_state = VERIEXEC_STATE_INACTIVE;
617fb47a376SStephen J. Kiernan 
618fb47a376SStephen J. Kiernan 	/* Initialize meta-data storage */
619fb47a376SStephen J. Kiernan 	mac_veriexec_metadata_init();
620fb47a376SStephen J. Kiernan 
621fb47a376SStephen J. Kiernan 	/* Initialize fingerprint ops */
622fb47a376SStephen J. Kiernan 	mac_veriexec_fingerprint_init();
623fb47a376SStephen J. Kiernan 
624fb47a376SStephen J. Kiernan 	/* Register event handlers */
625fb47a376SStephen J. Kiernan 	EVENTHANDLER_REGISTER(vfs_mounted, mac_veriexec_vfs_mounted, NULL,
626fb47a376SStephen J. Kiernan 	    EVENTHANDLER_PRI_FIRST);
627fb47a376SStephen J. Kiernan 	EVENTHANDLER_REGISTER(vfs_unmounted, mac_veriexec_vfs_unmounted, NULL,
628fb47a376SStephen J. Kiernan 	    EVENTHANDLER_PRI_LAST);
629fb47a376SStephen J. Kiernan }
630fb47a376SStephen J. Kiernan 
631fb47a376SStephen J. Kiernan /**
632fb47a376SStephen J. Kiernan  * @internal
633fb47a376SStephen J. Kiernan  * @brief MAC policy-specific syscall for mac_veriexec
634fb47a376SStephen J. Kiernan  *
635fb47a376SStephen J. Kiernan  * The following syscalls are implemented:
636fb47a376SStephen J. Kiernan  *   - @c MAC_VERIEXEC_CHECK_SYSCALL
637fb47a376SStephen J. Kiernan  *        Check if the file referenced by a file descriptor has a fingerprint
638fb47a376SStephen J. Kiernan  *        registered in the meta-data store.
639fb47a376SStephen J. Kiernan  *
640fb47a376SStephen J. Kiernan  * @param td		calling thread
641fb47a376SStephen J. Kiernan  * @param call		system call number
642fb47a376SStephen J. Kiernan  * @param arg		arugments to the syscall
643fb47a376SStephen J. Kiernan  *
644fb47a376SStephen J. Kiernan  * @return 0 on success, otherwise an error code.
645fb47a376SStephen J. Kiernan  */
646fb47a376SStephen J. Kiernan static int
647fb47a376SStephen J. Kiernan mac_veriexec_syscall(struct thread *td, int call, void *arg)
648fb47a376SStephen J. Kiernan {
649fb47a376SStephen J. Kiernan 	struct image_params img;
650fb47a376SStephen J. Kiernan 	struct nameidata nd;
651fb47a376SStephen J. Kiernan 	cap_rights_t rights;
652fb47a376SStephen J. Kiernan 	struct vattr va;
653fb47a376SStephen J. Kiernan 	struct file *fp;
654fb47a376SStephen J. Kiernan 	int error;
655fb47a376SStephen J. Kiernan 
656fb47a376SStephen J. Kiernan 	switch (call) {
657fb47a376SStephen J. Kiernan 	case MAC_VERIEXEC_CHECK_FD_SYSCALL:
658fb47a376SStephen J. Kiernan 		/* Get the vnode associated with the file descriptor passed */
659fb47a376SStephen J. Kiernan 		error = getvnode(td, (uintptr_t) arg, cap_rights_init(&rights,
660fb47a376SStephen J. Kiernan 		    CAP_READ), &fp);
661fb47a376SStephen J. Kiernan 		if (error)
662fb47a376SStephen J. Kiernan 			return (error);
663fb47a376SStephen J. Kiernan 		if (fp->f_type != DTYPE_VNODE) {
664fb47a376SStephen J. Kiernan 			MAC_VERIEXEC_DBG(3, "MAC_VERIEXEC_CHECK_SYSCALL: "
665fb47a376SStephen J. Kiernan 			    "file is not vnode type (type=0x%x)",
666fb47a376SStephen J. Kiernan 			    fp->f_type);
667fb47a376SStephen J. Kiernan 			error = EINVAL;
668fb47a376SStephen J. Kiernan 			goto cleanup_file;
669fb47a376SStephen J. Kiernan 		}
670fb47a376SStephen J. Kiernan 
671fb47a376SStephen J. Kiernan 		/*
672fb47a376SStephen J. Kiernan 		 * setup the bits of image_params that are used by
673fb47a376SStephen J. Kiernan 		 * mac_veriexec_check_fingerprint().
674fb47a376SStephen J. Kiernan 		 */
675fb47a376SStephen J. Kiernan 		bzero(&img, sizeof(img));
676fb47a376SStephen J. Kiernan 		img.proc = td->td_proc;
677fb47a376SStephen J. Kiernan 		img.vp = fp->f_vnode;
678fb47a376SStephen J. Kiernan 		img.attr = &va;
679fb47a376SStephen J. Kiernan 
680fb47a376SStephen J. Kiernan 		/*
681fb47a376SStephen J. Kiernan 		 * Get vnode attributes
682fb47a376SStephen J. Kiernan 		 * (need to obtain a lock on the vnode first)
683fb47a376SStephen J. Kiernan 		 */
684fb47a376SStephen J. Kiernan 		vn_lock(img.vp, LK_EXCLUSIVE | LK_RETRY);
685fb47a376SStephen J. Kiernan 		error = VOP_GETATTR(fp->f_vnode, &va,  td->td_ucred);
686fb47a376SStephen J. Kiernan 		if (error)
687fb47a376SStephen J. Kiernan 			goto check_done;
688fb47a376SStephen J. Kiernan 
689fb47a376SStephen J. Kiernan 		MAC_VERIEXEC_DBG(2, "mac_veriexec_fingerprint_check_image: "
690fb47a376SStephen J. Kiernan 		    "va_mode=%o, check_files=%d\n", va.va_mode,
691fb47a376SStephen J. Kiernan 		    ((va.va_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0));
692fb47a376SStephen J. Kiernan 		error = mac_veriexec_fingerprint_check_image(&img,
693fb47a376SStephen J. Kiernan 		    ((va.va_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0), td);
694fb47a376SStephen J. Kiernan check_done:
695fb47a376SStephen J. Kiernan 		/* Release the lock we obtained earlier */
696b249ce48SMateusz Guzik 		VOP_UNLOCK(img.vp);
697fb47a376SStephen J. Kiernan cleanup_file:
698fb47a376SStephen J. Kiernan 		fdrop(fp, td);
699fb47a376SStephen J. Kiernan 		break;
700fb47a376SStephen J. Kiernan 	case MAC_VERIEXEC_CHECK_PATH_SYSCALL:
701fb47a376SStephen J. Kiernan 		/* Look up the path to get the vnode */
7026cbc9703SStephen J. Kiernan 		NDINIT(&nd, LOOKUP,
7036cbc9703SStephen J. Kiernan 		    FOLLOW | LOCKLEAF | LOCKSHARED | AUDITVNODE1,
704fb47a376SStephen J. Kiernan 		    UIO_USERSPACE, arg, td);
705fb47a376SStephen J. Kiernan 		error = namei(&nd);
706fb47a376SStephen J. Kiernan 		if (error != 0)
707fb47a376SStephen J. Kiernan 			break;
708fb47a376SStephen J. Kiernan 		NDFREE(&nd, NDF_ONLY_PNBUF);
709fb47a376SStephen J. Kiernan 
710fb47a376SStephen J. Kiernan 		/* Check the fingerprint status of the vnode */
711fb47a376SStephen J. Kiernan 		error = mac_veriexec_check_vp(td->td_ucred, nd.ni_vp, VVERIFY);
712fb47a376SStephen J. Kiernan 		vput(nd.ni_vp);
713fb47a376SStephen J. Kiernan 		break;
714fb47a376SStephen J. Kiernan 	default:
715fb47a376SStephen J. Kiernan 		error = EOPNOTSUPP;
716fb47a376SStephen J. Kiernan 	}
717fb47a376SStephen J. Kiernan 	return (error);
718fb47a376SStephen J. Kiernan }
719fb47a376SStephen J. Kiernan 
720fb47a376SStephen J. Kiernan static struct mac_policy_ops mac_veriexec_ops =
721fb47a376SStephen J. Kiernan {
722fb47a376SStephen J. Kiernan 	.mpo_init = mac_veriexec_init,
723fb47a376SStephen J. Kiernan 	.mpo_kld_check_load = mac_veriexec_kld_check_load,
724fb47a376SStephen J. Kiernan 	.mpo_mount_destroy_label = mac_veriexec_mount_destroy_label,
725fb47a376SStephen J. Kiernan 	.mpo_mount_init_label = mac_veriexec_mount_init_label,
726fb47a376SStephen J. Kiernan 	.mpo_priv_check = mac_veriexec_priv_check,
727fb47a376SStephen J. Kiernan 	.mpo_proc_check_debug = mac_veriexec_proc_check_debug,
728ed377cf4SStephen J. Kiernan 	.mpo_syscall = mac_veriexec_syscall,
729ed377cf4SStephen J. Kiernan 	.mpo_system_check_sysctl = mac_veriexec_sysctl_check,
730fb47a376SStephen J. Kiernan 	.mpo_vnode_check_exec = mac_veriexec_vnode_check_exec,
731fb47a376SStephen J. Kiernan 	.mpo_vnode_check_open = mac_veriexec_vnode_check_open,
732ade97886SStephen J. Kiernan 	.mpo_vnode_check_setmode = mac_veriexec_vnode_check_setmode,
733fb47a376SStephen J. Kiernan 	.mpo_vnode_copy_label = mac_veriexec_copy_label,
734fb47a376SStephen J. Kiernan 	.mpo_vnode_destroy_label = mac_veriexec_vnode_destroy_label,
735fb47a376SStephen J. Kiernan 	.mpo_vnode_init_label = mac_veriexec_vnode_init_label,
736fb47a376SStephen J. Kiernan };
737fb47a376SStephen J. Kiernan 
738fb47a376SStephen J. Kiernan MAC_POLICY_SET(&mac_veriexec_ops, mac_veriexec, MAC_VERIEXEC_FULLNAME,
739fb47a376SStephen J. Kiernan     MPC_LOADTIME_FLAG_NOTLATE, &mac_veriexec_slot);
740fb47a376SStephen J. Kiernan MODULE_VERSION(mac_veriexec, 1);
741fb47a376SStephen J. Kiernan 
742478368caSMateusz Guzik static struct vnode *
743478368caSMateusz Guzik mac_veriexec_bottom_vnode(struct vnode *vp)
744478368caSMateusz Guzik {
745478368caSMateusz Guzik 	struct vnode *ldvp = NULL;
746478368caSMateusz Guzik 
747478368caSMateusz Guzik 	/*
748478368caSMateusz Guzik 	 * XXX This code is bogus. nullfs is not the only stacking
749478368caSMateusz Guzik 	 * filesystem. Less bogus code would add a VOP to reach bottom
750478368caSMateusz Guzik 	 * vnode and would not make assumptions how to get there.
751478368caSMateusz Guzik 	 */
752478368caSMateusz Guzik 	if (vp->v_mount != NULL &&
753478368caSMateusz Guzik 	    strcmp(vp->v_mount->mnt_vfc->vfc_name, "nullfs") == 0)
754478368caSMateusz Guzik 		ldvp = NULLVPTOLOWERVP(vp);
755478368caSMateusz Guzik 	return (ldvp);
756478368caSMateusz Guzik }
757478368caSMateusz Guzik 
758fb47a376SStephen J. Kiernan /**
759fb47a376SStephen J. Kiernan  * @brief Get the fingerprint status set on a vnode.
760fb47a376SStephen J. Kiernan  *
761fb47a376SStephen J. Kiernan  * @param vp		vnode to obtain fingerprint status from
762fb47a376SStephen J. Kiernan  *
763fb47a376SStephen J. Kiernan  * @return Fingerprint status assigned to the vnode.
764fb47a376SStephen J. Kiernan  */
765fb47a376SStephen J. Kiernan fingerprint_status_t
766fb47a376SStephen J. Kiernan mac_veriexec_get_fingerprint_status(struct vnode *vp)
767fb47a376SStephen J. Kiernan {
768fb47a376SStephen J. Kiernan 	fingerprint_status_t fps;
769478368caSMateusz Guzik 	struct vnode *ldvp;
770fb47a376SStephen J. Kiernan 
771fb47a376SStephen J. Kiernan 	fps = SLOT(vp->v_label);
772fb47a376SStephen J. Kiernan 	switch (fps) {
773fb47a376SStephen J. Kiernan 	case FINGERPRINT_VALID:
774fb47a376SStephen J. Kiernan 	case FINGERPRINT_INDIRECT:
775fb47a376SStephen J. Kiernan 	case FINGERPRINT_FILE:
776fb47a376SStephen J. Kiernan 		break;
777fb47a376SStephen J. Kiernan 	default:
778fb47a376SStephen J. Kiernan 		/* we may need to recurse */
779478368caSMateusz Guzik 		ldvp = mac_veriexec_bottom_vnode(vp);
780478368caSMateusz Guzik 		if (ldvp != NULL)
781fb47a376SStephen J. Kiernan 			return mac_veriexec_get_fingerprint_status(ldvp);
782fb47a376SStephen J. Kiernan 		break;
783fb47a376SStephen J. Kiernan 	}
784fb47a376SStephen J. Kiernan 	return fps;
785fb47a376SStephen J. Kiernan }
786fb47a376SStephen J. Kiernan 
787fb47a376SStephen J. Kiernan /**
788fb47a376SStephen J. Kiernan  * @brief Get the current verified execution subsystem state.
789fb47a376SStephen J. Kiernan  *
790fb47a376SStephen J. Kiernan  * @return Current set of verified execution subsystem state flags.
791fb47a376SStephen J. Kiernan  */
792fb47a376SStephen J. Kiernan int
793fb47a376SStephen J. Kiernan mac_veriexec_get_state(void)
794fb47a376SStephen J. Kiernan {
795fb47a376SStephen J. Kiernan 
796fb47a376SStephen J. Kiernan 	return (mac_veriexec_state);
797fb47a376SStephen J. Kiernan }
798fb47a376SStephen J. Kiernan 
799fb47a376SStephen J. Kiernan /**
800fb47a376SStephen J. Kiernan  * @brief Determine if the verified execution subsystem state has specific
801fb47a376SStephen J. Kiernan  *     flags set.
802fb47a376SStephen J. Kiernan  *
803fb47a376SStephen J. Kiernan  * @param state		mask of flags to check
804fb47a376SStephen J. Kiernan  *
805fb47a376SStephen J. Kiernan  * @return State flags set within the masked bits
806fb47a376SStephen J. Kiernan  */
807fb47a376SStephen J. Kiernan int
808fb47a376SStephen J. Kiernan mac_veriexec_in_state(int state)
809fb47a376SStephen J. Kiernan {
810fb47a376SStephen J. Kiernan 
811fb47a376SStephen J. Kiernan 	return (mac_veriexec_state & state);
812fb47a376SStephen J. Kiernan }
813fb47a376SStephen J. Kiernan 
814fb47a376SStephen J. Kiernan /**
815fb47a376SStephen J. Kiernan  * @brief Set the fingerprint status for a vnode
816fb47a376SStephen J. Kiernan  *
817fb47a376SStephen J. Kiernan  * Fingerprint status is stored in the MAC per-policy slot assigned to
818fb47a376SStephen J. Kiernan  * mac_veriexec.
819fb47a376SStephen J. Kiernan  *
820fb47a376SStephen J. Kiernan  * @param vp		vnode to store the fingerprint status on
821fb47a376SStephen J. Kiernan  * @param fp_status	fingerprint status to store
822fb47a376SStephen J. Kiernan  */
823fb47a376SStephen J. Kiernan void
824fb47a376SStephen J. Kiernan mac_veriexec_set_fingerprint_status(struct vnode *vp,
825fb47a376SStephen J. Kiernan     fingerprint_status_t fp_status)
826fb47a376SStephen J. Kiernan {
827fb47a376SStephen J. Kiernan 	struct vnode *ldvp;
828fb47a376SStephen J. Kiernan 
829478368caSMateusz Guzik 	/* recurse until we find the real storage */
830478368caSMateusz Guzik 	ldvp = mac_veriexec_bottom_vnode(vp);
831478368caSMateusz Guzik 	if (ldvp != NULL) {
832fb47a376SStephen J. Kiernan 		mac_veriexec_set_fingerprint_status(ldvp, fp_status);
833fb47a376SStephen J. Kiernan 		return;
834fb47a376SStephen J. Kiernan 	}
835fb47a376SStephen J. Kiernan 	SLOT_SET(vp->v_label, fp_status);
836fb47a376SStephen J. Kiernan }
837fb47a376SStephen J. Kiernan 
838fb47a376SStephen J. Kiernan /**
839fb47a376SStephen J. Kiernan  * @brief Set verified execution subsystem state flags
840fb47a376SStephen J. Kiernan  *
841fb47a376SStephen J. Kiernan  * @note Flags can only be added to the current state, not removed.
842fb47a376SStephen J. Kiernan  *
843fb47a376SStephen J. Kiernan  * @param state		state flags to add to the current state
844fb47a376SStephen J. Kiernan  */
845fb47a376SStephen J. Kiernan void
846fb47a376SStephen J. Kiernan mac_veriexec_set_state(int state)
847fb47a376SStephen J. Kiernan {
848fb47a376SStephen J. Kiernan 
849fb47a376SStephen J. Kiernan 	mac_veriexec_state |= state;
850fb47a376SStephen J. Kiernan }
851fb47a376SStephen J. Kiernan 
852fb47a376SStephen J. Kiernan /**
853fb47a376SStephen J. Kiernan  * @brief Determine if the process is trusted
854fb47a376SStephen J. Kiernan  *
855fb47a376SStephen J. Kiernan  * @param cred		credentials to use
856fb47a376SStephen J. Kiernan  * @param p		the process in question
857fb47a376SStephen J. Kiernan  *
858fb47a376SStephen J. Kiernan  * @return 1 if the process is trusted, otherwise 0.
859fb47a376SStephen J. Kiernan  */
860fb47a376SStephen J. Kiernan int
861fb47a376SStephen J. Kiernan mac_veriexec_proc_is_trusted(struct ucred *cred, struct proc *p)
862fb47a376SStephen J. Kiernan {
8633da3012aSStephen J. Kiernan 	int already_locked, error, flags;
8643da3012aSStephen J. Kiernan 
8653da3012aSStephen J. Kiernan 	/* Make sure we lock the process if we do not already have the lock */
8663da3012aSStephen J. Kiernan 	already_locked = PROC_LOCKED(p);
8673da3012aSStephen J. Kiernan 	if (!already_locked)
8683da3012aSStephen J. Kiernan 		PROC_LOCK(p);
869fb47a376SStephen J. Kiernan 
870fb47a376SStephen J. Kiernan 	error = mac_veriexec_metadata_get_executable_flags(cred, p, &flags, 0);
871fb47a376SStephen J. Kiernan 
8723da3012aSStephen J. Kiernan 	/* Unlock the process if we locked it previously */
8733da3012aSStephen J. Kiernan 	if (!already_locked)
8743da3012aSStephen J. Kiernan 		PROC_UNLOCK(p);
8753da3012aSStephen J. Kiernan 
876fb47a376SStephen J. Kiernan 	/* Any errors, deny access */
877fb47a376SStephen J. Kiernan 	if (error != 0)
878fb47a376SStephen J. Kiernan 		return (0);
879fb47a376SStephen J. Kiernan 
880fb47a376SStephen J. Kiernan 	/* Check that the trusted flag is set */
881fb47a376SStephen J. Kiernan 	return ((flags & VERIEXEC_TRUSTED) == VERIEXEC_TRUSTED);
882fb47a376SStephen J. Kiernan }
883