xref: /freebsd/sys/security/mac_veriexec/mac_veriexec.c (revision db33c6f3ae9d1231087710068ee4ea5398aacca7)
188a3358eSStephen J. Kiernan /*-
288a3358eSStephen J. Kiernan  * SPDX-License-Identifier: BSD-2-Clause
3fb47a376SStephen J. Kiernan  *
48512d82eSSteve Kiernan  * Copyright (c) 2011-2023 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>
538c3e263dSSimon J. Gerraty #ifdef COMPAT_FREEBSD32
548c3e263dSSimon J. Gerraty #include <sys/sysent.h>
558c3e263dSSimon J. Gerraty #include <sys/stdint.h>
568c3e263dSSimon J. Gerraty #include <sys/abi_compat.h>
578c3e263dSSimon J. Gerraty #endif
58fb47a376SStephen J. Kiernan #include <fs/nullfs/null.h>
596ae8d576SSimon J. Gerraty #include <security/mac/mac_framework.h>
60fb47a376SStephen J. Kiernan #include <security/mac/mac_policy.h>
61fb47a376SStephen J. Kiernan 
62fb47a376SStephen J. Kiernan #include "mac_veriexec.h"
63fb47a376SStephen J. Kiernan #include "mac_veriexec_internal.h"
64fb47a376SStephen J. Kiernan 
65fb47a376SStephen J. Kiernan #define	SLOT(l) \
66fb47a376SStephen J. Kiernan 	mac_label_get((l), mac_veriexec_slot)
67fb47a376SStephen J. Kiernan #define	SLOT_SET(l, v) \
68fb47a376SStephen J. Kiernan 	mac_label_set((l), mac_veriexec_slot, (v))
69fb47a376SStephen J. Kiernan 
70d195f39dSSteve Kiernan #ifdef MAC_VERIEXEC_DEBUG
71fb47a376SStephen J. Kiernan #define	MAC_VERIEXEC_DBG(_lvl, _fmt, ...)				\
72fb47a376SStephen J. Kiernan 	do {								\
73fb47a376SStephen J. Kiernan 		VERIEXEC_DEBUG((_lvl), (MAC_VERIEXEC_FULLNAME ": " _fmt	\
74fb47a376SStephen J. Kiernan 		     "\n", ##__VA_ARGS__));				\
75fb47a376SStephen J. Kiernan 	} while(0)
76fb47a376SStephen J. Kiernan #else
77fb47a376SStephen J. Kiernan #define	MAC_VERIEXEC_DBG(_lvl, _fmt, ...)
78fb47a376SStephen J. Kiernan #endif
79fb47a376SStephen J. Kiernan 
80fb47a376SStephen J. Kiernan static int sysctl_mac_veriexec_state(SYSCTL_HANDLER_ARGS);
81fb47a376SStephen J. Kiernan static int sysctl_mac_veriexec_db(SYSCTL_HANDLER_ARGS);
822ef8babaSdl static struct mac_policy_ops mac_veriexec_ops;
83fb47a376SStephen J. Kiernan 
847029da5cSPawel Biernacki SYSCTL_NODE(_security_mac, OID_AUTO, veriexec, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
85fb47a376SStephen J. Kiernan     "MAC/veriexec policy controls");
86fb47a376SStephen J. Kiernan 
87fb47a376SStephen J. Kiernan int	mac_veriexec_debug;
88fb47a376SStephen J. Kiernan SYSCTL_INT(_security_mac_veriexec, OID_AUTO, debug, CTLFLAG_RW,
89fb47a376SStephen J. Kiernan     &mac_veriexec_debug, 0, "Debug level");
90fb47a376SStephen J. Kiernan 
91fb47a376SStephen J. Kiernan static int	mac_veriexec_state;
92fb47a376SStephen J. Kiernan SYSCTL_PROC(_security_mac_veriexec, OID_AUTO, state,
937029da5cSPawel Biernacki     CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_NEEDGIANT,
947029da5cSPawel Biernacki     0, 0, sysctl_mac_veriexec_state, "A",
95fb47a376SStephen J. Kiernan     "Verified execution subsystem state");
96fb47a376SStephen J. Kiernan 
97fb47a376SStephen J. Kiernan SYSCTL_PROC(_security_mac_veriexec, OID_AUTO, db,
987029da5cSPawel Biernacki     CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_SKIP | CTLFLAG_NEEDGIANT,
997029da5cSPawel Biernacki     0, 0, sysctl_mac_veriexec_db,
100fb47a376SStephen J. Kiernan     "A", "Verified execution fingerprint database");
101fb47a376SStephen J. Kiernan 
1022ef8babaSdl 
103fb47a376SStephen J. Kiernan static int mac_veriexec_slot;
104fb47a376SStephen J. Kiernan 
1052ef8babaSdl static int mac_veriexec_block_unlink;
106bb8d4411SZhenlei Huang SYSCTL_INT(_security_mac_veriexec, OID_AUTO, block_unlink, CTLFLAG_RDTUN,
107bb8d4411SZhenlei Huang     &mac_veriexec_block_unlink, 0, "Veriexec unlink protection");
1082ef8babaSdl 
109fb47a376SStephen J. Kiernan MALLOC_DEFINE(M_VERIEXEC, "veriexec", "Verified execution data");
110fb47a376SStephen J. Kiernan 
111fb47a376SStephen J. Kiernan /**
112fb47a376SStephen J. Kiernan  * @internal
113fb47a376SStephen J. Kiernan  * @brief Handler for security.mac.veriexec.db sysctl
114fb47a376SStephen J. Kiernan  *
115fb47a376SStephen J. Kiernan  * Display a human-readable form of the current fingerprint database.
116fb47a376SStephen J. Kiernan  */
117fb47a376SStephen J. Kiernan static int
sysctl_mac_veriexec_db(SYSCTL_HANDLER_ARGS)118fb47a376SStephen J. Kiernan sysctl_mac_veriexec_db(SYSCTL_HANDLER_ARGS)
119fb47a376SStephen J. Kiernan {
120fb47a376SStephen J. Kiernan 	struct sbuf sb;
121fb47a376SStephen J. Kiernan 	int error;
122fb47a376SStephen J. Kiernan 
123fb47a376SStephen J. Kiernan 	error = sysctl_wire_old_buffer(req, 0);
124fb47a376SStephen J. Kiernan 	if (error != 0)
125fb47a376SStephen J. Kiernan 		return (error);
126fb47a376SStephen J. Kiernan 
127fb47a376SStephen J. Kiernan 	sbuf_new_for_sysctl(&sb, NULL, 1024, req);
1281db017d0SStephen J. Kiernan 	mac_veriexec_metadata_print_db(&sb);
129fb47a376SStephen J. Kiernan 	error = sbuf_finish(&sb);
130fb47a376SStephen J. Kiernan 	sbuf_delete(&sb);
131fb47a376SStephen J. Kiernan 
132fb47a376SStephen J. Kiernan 	return (error);
133fb47a376SStephen J. Kiernan }
134fb47a376SStephen J. Kiernan 
135fb47a376SStephen J. Kiernan /**
136fb47a376SStephen J. Kiernan  * @internal
137fb47a376SStephen J. Kiernan  * @brief Generate human-readable output about the current verified execution
138fb47a376SStephen J. Kiernan  *        state.
139fb47a376SStephen J. Kiernan  *
140fb47a376SStephen J. Kiernan  * @param sbp		sbuf to write output to
141fb47a376SStephen J. Kiernan  */
142fb47a376SStephen J. Kiernan static void
mac_veriexec_print_state(struct sbuf * sbp)143fb47a376SStephen J. Kiernan mac_veriexec_print_state(struct sbuf *sbp)
144fb47a376SStephen J. Kiernan {
145fb47a376SStephen J. Kiernan 
146fb47a376SStephen J. Kiernan 	if (mac_veriexec_state & VERIEXEC_STATE_INACTIVE)
147fb47a376SStephen J. Kiernan 		sbuf_printf(sbp, "inactive ");
148fb47a376SStephen J. Kiernan 	if (mac_veriexec_state & VERIEXEC_STATE_LOADED)
149fb47a376SStephen J. Kiernan 		sbuf_printf(sbp, "loaded ");
150fb47a376SStephen J. Kiernan 	if (mac_veriexec_state & VERIEXEC_STATE_ACTIVE)
151fb47a376SStephen J. Kiernan 		sbuf_printf(sbp, "active ");
152fb47a376SStephen J. Kiernan 	if (mac_veriexec_state & VERIEXEC_STATE_ENFORCE)
153fb47a376SStephen J. Kiernan 		sbuf_printf(sbp, "enforce ");
154fb47a376SStephen J. Kiernan 	if (mac_veriexec_state & VERIEXEC_STATE_LOCKED)
155fb47a376SStephen J. Kiernan 		sbuf_printf(sbp, "locked ");
156fb47a376SStephen J. Kiernan 	if (mac_veriexec_state != 0)
157fb47a376SStephen J. Kiernan 		sbuf_trim(sbp);
158fb47a376SStephen J. Kiernan }
159fb47a376SStephen J. Kiernan 
160fb47a376SStephen J. Kiernan /**
161fb47a376SStephen J. Kiernan  * @internal
162fb47a376SStephen J. Kiernan  * @brief Handler for security.mac.veriexec.state sysctl
163fb47a376SStephen J. Kiernan  *
164fb47a376SStephen J. Kiernan  * Display a human-readable form of the current verified execution subsystem
165fb47a376SStephen J. Kiernan  * state.
166fb47a376SStephen J. Kiernan  */
167fb47a376SStephen J. Kiernan static int
sysctl_mac_veriexec_state(SYSCTL_HANDLER_ARGS)168fb47a376SStephen J. Kiernan sysctl_mac_veriexec_state(SYSCTL_HANDLER_ARGS)
169fb47a376SStephen J. Kiernan {
170fb47a376SStephen J. Kiernan 	struct sbuf sb;
171fb47a376SStephen J. Kiernan 	int error;
172fb47a376SStephen J. Kiernan 
173fb47a376SStephen J. Kiernan 	sbuf_new(&sb, NULL, 128, SBUF_AUTOEXTEND);
174fb47a376SStephen J. Kiernan 	mac_veriexec_print_state(&sb);
175fb47a376SStephen J. Kiernan 	sbuf_finish(&sb);
176fb47a376SStephen J. Kiernan 
177fb47a376SStephen J. Kiernan 	error = SYSCTL_OUT(req, sbuf_data(&sb), sbuf_len(&sb));
178fb47a376SStephen J. Kiernan 	sbuf_delete(&sb);
179fb47a376SStephen J. Kiernan 	return (error);
180fb47a376SStephen J. Kiernan }
181fb47a376SStephen J. Kiernan 
182fb47a376SStephen J. Kiernan /**
183fb47a376SStephen J. Kiernan  * @internal
184fb47a376SStephen J. Kiernan  * @brief Event handler called when a virtual file system is mounted.
185fb47a376SStephen J. Kiernan  *
186fb47a376SStephen J. Kiernan  * We need to record the file system identifier in the MAC per-policy slot
187fb47a376SStephen J. Kiernan  * assigned to veriexec, so we have a key to use in order to reference the
188fb47a376SStephen J. Kiernan  * mount point in the meta-data store.
189fb47a376SStephen J. Kiernan  *
190fb47a376SStephen J. Kiernan  * @param arg		unused argument
191fb47a376SStephen J. Kiernan  * @param mp		mount point that is being mounted
192fb47a376SStephen J. Kiernan  * @param fsrootvp	vnode of the file system root
193fb47a376SStephen J. Kiernan  * @param td		calling thread
194fb47a376SStephen J. Kiernan  */
195fb47a376SStephen J. Kiernan static void
mac_veriexec_vfs_mounted(void * arg __unused,struct mount * mp,struct vnode * fsrootvp,struct thread * td)196fb47a376SStephen J. Kiernan mac_veriexec_vfs_mounted(void *arg __unused, struct mount *mp,
197fb47a376SStephen J. Kiernan     struct vnode *fsrootvp, struct thread *td)
198fb47a376SStephen J. Kiernan {
199fb47a376SStephen J. Kiernan 	struct vattr va;
200fb47a376SStephen J. Kiernan 	int error;
201fb47a376SStephen J. Kiernan 
202fb47a376SStephen J. Kiernan 	error = VOP_GETATTR(fsrootvp, &va, td->td_ucred);
203fb47a376SStephen J. Kiernan 	if (error)
204fb47a376SStephen J. Kiernan 		return;
205fb47a376SStephen J. Kiernan 
206fb47a376SStephen J. Kiernan 	SLOT_SET(mp->mnt_label, va.va_fsid);
2073d53cd0fSStephen J. Kiernan 	MAC_VERIEXEC_DBG(3, "set fsid to %ju for mount %p",
2083d53cd0fSStephen J. Kiernan 	    (uintmax_t)va.va_fsid, mp);
209fb47a376SStephen J. Kiernan }
210fb47a376SStephen J. Kiernan 
211fb47a376SStephen J. Kiernan /**
212fb47a376SStephen J. Kiernan  * @internal
213fb47a376SStephen J. Kiernan  * @brief Event handler called when a virtual file system is unmounted.
214fb47a376SStephen J. Kiernan  *
215fb47a376SStephen J. Kiernan  * If we recorded a file system identifier in the MAC per-policy slot assigned
216fb47a376SStephen J. Kiernan  * to veriexec, then we need to tell the meta-data store to clean up.
217fb47a376SStephen J. Kiernan  *
218fb47a376SStephen J. Kiernan  * @param arg		unused argument
219fb47a376SStephen J. Kiernan  * @param mp		mount point that is being unmounted
220fb47a376SStephen J. Kiernan  * @param td		calling thread
221fb47a376SStephen J. Kiernan  */
222fb47a376SStephen J. Kiernan static void
mac_veriexec_vfs_unmounted(void * arg __unused,struct mount * mp,struct thread * td)223fb47a376SStephen J. Kiernan mac_veriexec_vfs_unmounted(void *arg __unused, struct mount *mp,
224fb47a376SStephen J. Kiernan     struct thread *td)
225fb47a376SStephen J. Kiernan {
226fb47a376SStephen J. Kiernan 	dev_t fsid;
227fb47a376SStephen J. Kiernan 
228fb47a376SStephen J. Kiernan 	fsid = SLOT(mp->mnt_label);
229fb47a376SStephen J. Kiernan 	if (fsid) {
2303d53cd0fSStephen J. Kiernan 		MAC_VERIEXEC_DBG(3, "fsid %ju, cleaning up mount",
2313d53cd0fSStephen J. Kiernan 		    (uintmax_t)fsid);
232fb47a376SStephen J. Kiernan 		mac_veriexec_metadata_unmounted(fsid, td);
233fb47a376SStephen J. Kiernan 	}
234fb47a376SStephen J. Kiernan }
235fb47a376SStephen J. Kiernan 
236fb47a376SStephen J. Kiernan /**
237fb47a376SStephen J. Kiernan  * @internal
238fb47a376SStephen J. Kiernan  * @brief The mount point is being initialized, set the value in the MAC
239fb47a376SStephen J. Kiernan  *     per-policy slot for veriexec to zero.
240fb47a376SStephen J. Kiernan  *
241fb47a376SStephen J. Kiernan  * @note A value of zero in this slot indicates no file system identifier
242fb47a376SStephen J. Kiernan  *     is assigned.
243fb47a376SStephen J. Kiernan  *
244fb47a376SStephen J. Kiernan  * @param label the label that is being initialized
245fb47a376SStephen J. Kiernan  */
246fb47a376SStephen J. Kiernan static void
mac_veriexec_mount_init_label(struct label * label)247fb47a376SStephen J. Kiernan mac_veriexec_mount_init_label(struct label *label)
248fb47a376SStephen J. Kiernan {
249fb47a376SStephen J. Kiernan 
250fb47a376SStephen J. Kiernan 	SLOT_SET(label, 0);
251fb47a376SStephen J. Kiernan }
252fb47a376SStephen J. Kiernan 
253fb47a376SStephen J. Kiernan /**
254fb47a376SStephen J. Kiernan  * @internal
255fb47a376SStephen J. Kiernan  * @brief The mount-point is being destroyed, reset the value in the MAC
256fb47a376SStephen J. Kiernan  *     per-policy slot for veriexec back to zero.
257fb47a376SStephen J. Kiernan  *
258fb47a376SStephen J. Kiernan  * @note A value of zero in this slot indicates no file system identifier
259fb47a376SStephen J. Kiernan  *     is assigned.
260fb47a376SStephen J. Kiernan  *
261fb47a376SStephen J. Kiernan  * @param label the label that is being destroyed
262fb47a376SStephen J. Kiernan  */
263fb47a376SStephen J. Kiernan static void
mac_veriexec_mount_destroy_label(struct label * label)264fb47a376SStephen J. Kiernan mac_veriexec_mount_destroy_label(struct label *label)
265fb47a376SStephen J. Kiernan {
266fb47a376SStephen J. Kiernan 
267fb47a376SStephen J. Kiernan 	SLOT_SET(label, 0);
268fb47a376SStephen J. Kiernan }
269fb47a376SStephen J. Kiernan 
270fb47a376SStephen J. Kiernan /**
271fb47a376SStephen J. Kiernan  * @internal
272fb47a376SStephen J. Kiernan  * @brief The vnode label is being initialized, set the value in the MAC
273fb47a376SStephen J. Kiernan  *     per-policy slot for veriexec to @c FINGERPRINT_INVALID
274fb47a376SStephen J. Kiernan  *
275fb47a376SStephen J. Kiernan  * @note @c FINGERPRINT_INVALID indicates the fingerprint is invalid.
276fb47a376SStephen J. Kiernan  *
277fb47a376SStephen J. Kiernan  * @param label		the label that is being initialized
278fb47a376SStephen J. Kiernan  */
279fb47a376SStephen J. Kiernan static void
mac_veriexec_vnode_init_label(struct label * label)280fb47a376SStephen J. Kiernan mac_veriexec_vnode_init_label(struct label *label)
281fb47a376SStephen J. Kiernan {
282fb47a376SStephen J. Kiernan 
283fb47a376SStephen J. Kiernan 	SLOT_SET(label, FINGERPRINT_INVALID);
284fb47a376SStephen J. Kiernan }
285fb47a376SStephen J. Kiernan 
286fb47a376SStephen J. Kiernan /**
287fb47a376SStephen J. Kiernan  * @internal
288fb47a376SStephen J. Kiernan  * @brief The vnode label is being destroyed, reset the value in the MAC
289fb47a376SStephen J. Kiernan  *        per-policy slot for veriexec back to @c FINGERPRINT_INVALID
290fb47a376SStephen J. Kiernan  *
291fb47a376SStephen J. Kiernan  * @note @c FINGERPRINT_INVALID indicates the fingerprint is invalid.
292fb47a376SStephen J. Kiernan  *
293fb47a376SStephen J. Kiernan  * @param label		the label that is being destroyed
294fb47a376SStephen J. Kiernan  */
295fb47a376SStephen J. Kiernan static void
mac_veriexec_vnode_destroy_label(struct label * label)296fb47a376SStephen J. Kiernan mac_veriexec_vnode_destroy_label(struct label *label)
297fb47a376SStephen J. Kiernan {
298fb47a376SStephen J. Kiernan 
299fb47a376SStephen J. Kiernan 	SLOT_SET(label, FINGERPRINT_INVALID);
300fb47a376SStephen J. Kiernan }
301fb47a376SStephen J. Kiernan 
302fb47a376SStephen J. Kiernan /**
303fb47a376SStephen J. Kiernan  * @internal
304fb47a376SStephen J. Kiernan  * @brief Copy the value in the MAC per-policy slot assigned to veriexec from
305fb47a376SStephen J. Kiernan  *        the @p src label to the @p dest label
306fb47a376SStephen J. Kiernan  */
307fb47a376SStephen J. Kiernan static void
mac_veriexec_copy_label(struct label * src,struct label * dest)308fb47a376SStephen J. Kiernan mac_veriexec_copy_label(struct label *src, struct label *dest)
309fb47a376SStephen J. Kiernan {
310fb47a376SStephen J. Kiernan 
311fb47a376SStephen J. Kiernan 	SLOT_SET(dest, SLOT(src));
312fb47a376SStephen J. Kiernan }
313fb47a376SStephen J. Kiernan 
314fb47a376SStephen J. Kiernan /**
315fb47a376SStephen J. Kiernan  * @internal
316fb47a376SStephen J. Kiernan  * @brief Check if the requested process can be debugged
317fb47a376SStephen J. Kiernan  *
318fb47a376SStephen J. Kiernan  * @param cred		credentials to use
319fb47a376SStephen J. Kiernan  * @param p		process to debug
320fb47a376SStephen J. Kiernan  *
321fb47a376SStephen J. Kiernan  * @return 0 if debugging is allowed, otherwise an error code.
322fb47a376SStephen J. Kiernan  */
323fb47a376SStephen J. Kiernan static int
mac_veriexec_proc_check_debug(struct ucred * cred,struct proc * p)324fb47a376SStephen J. Kiernan mac_veriexec_proc_check_debug(struct ucred *cred, struct proc *p)
325fb47a376SStephen J. Kiernan {
326fb47a376SStephen J. Kiernan 	int error, flags;
327fb47a376SStephen J. Kiernan 
328fb47a376SStephen J. Kiernan 	/* If we are not enforcing veriexec, nothing for us to check */
329fb47a376SStephen J. Kiernan 	if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0)
330fb47a376SStephen J. Kiernan 		return (0);
331fb47a376SStephen J. Kiernan 
332fb47a376SStephen J. Kiernan 	error = mac_veriexec_metadata_get_executable_flags(cred, p, &flags, 0);
333fb47a376SStephen J. Kiernan 	if (error != 0)
334fb47a376SStephen J. Kiernan 		return (0);
335fb47a376SStephen J. Kiernan 
3368512d82eSSteve Kiernan 	error = (flags & (VERIEXEC_NOTRACE|VERIEXEC_TRUSTED)) ? EACCES : 0;
3378512d82eSSteve Kiernan 	MAC_VERIEXEC_DBG(4, "%s flags=%#x error=%d", __func__, flags, error);
3388512d82eSSteve Kiernan 
3398512d82eSSteve Kiernan 	return (error);
340fb47a376SStephen J. Kiernan }
341fb47a376SStephen J. Kiernan 
342fb47a376SStephen J. Kiernan /**
343fb47a376SStephen J. Kiernan  * @internal
344fb47a376SStephen J. Kiernan  * @brief A KLD load has been requested and needs to be validated.
345fb47a376SStephen J. Kiernan  *
346fb47a376SStephen J. Kiernan  * @param cred		credentials to use
347fb47a376SStephen J. Kiernan  * @param vp		vnode of the KLD that has been requested
348fb47a376SStephen J. Kiernan  * @param vlabel	vnode label assigned to the vnode
349fb47a376SStephen J. Kiernan  *
350fb47a376SStephen J. Kiernan  * @return 0 if the KLD load is allowed, otherwise an error code.
351fb47a376SStephen J. Kiernan  */
352fb47a376SStephen J. Kiernan static int
mac_veriexec_kld_check_load(struct ucred * cred,struct vnode * vp,struct label * vlabel)353fb47a376SStephen J. Kiernan mac_veriexec_kld_check_load(struct ucred *cred, struct vnode *vp,
354fb47a376SStephen J. Kiernan     struct label *vlabel)
355fb47a376SStephen J. Kiernan {
356fb47a376SStephen J. Kiernan 	struct vattr va;
357fb47a376SStephen J. Kiernan 	struct thread *td = curthread;
358fb47a376SStephen J. Kiernan 	fingerprint_status_t status;
359fb47a376SStephen J. Kiernan 	int error;
360fb47a376SStephen J. Kiernan 
361fb47a376SStephen J. Kiernan 	/*
362fb47a376SStephen J. Kiernan 	 * If we are not actively enforcing, allow it
363fb47a376SStephen J. Kiernan 	 */
364fb47a376SStephen J. Kiernan 	if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0)
365fb47a376SStephen J. Kiernan 		return (0);
366fb47a376SStephen J. Kiernan 
367fb47a376SStephen J. Kiernan 	/* Get vnode attributes */
368fb47a376SStephen J. Kiernan 	error = VOP_GETATTR(vp, &va, cred);
369fb47a376SStephen J. Kiernan 	if (error)
370fb47a376SStephen J. Kiernan 		return (error);
371fb47a376SStephen J. Kiernan 
372fb47a376SStephen J. Kiernan 	/*
373fb47a376SStephen J. Kiernan 	 * Fetch the fingerprint status for the vnode
374fb47a376SStephen J. Kiernan 	 * (starting with files first)
375fb47a376SStephen J. Kiernan 	 */
376fb47a376SStephen J. Kiernan 	error = mac_veriexec_metadata_fetch_fingerprint_status(vp, &va, td,
377fb47a376SStephen J. Kiernan 	    VERIEXEC_FILES_FIRST);
378fb47a376SStephen J. Kiernan 	if (error && error != EAUTH)
379fb47a376SStephen J. Kiernan 		return (error);
380fb47a376SStephen J. Kiernan 
381fb47a376SStephen J. Kiernan 	/*
382fb47a376SStephen J. Kiernan 	 * By now we should have status...
383fb47a376SStephen J. Kiernan 	 */
384fb47a376SStephen J. Kiernan 	status = mac_veriexec_get_fingerprint_status(vp);
385fb47a376SStephen J. Kiernan 	switch (status) {
386fb47a376SStephen J. Kiernan 	case FINGERPRINT_FILE:
387fb47a376SStephen J. Kiernan 	case FINGERPRINT_VALID:
388fb47a376SStephen J. Kiernan 	case FINGERPRINT_INDIRECT:
389fb47a376SStephen J. Kiernan 		if (error)
390fb47a376SStephen J. Kiernan 			return (error);
391fb47a376SStephen J. Kiernan 		break;
392fb47a376SStephen J. Kiernan 	default:
393fb47a376SStephen J. Kiernan 		/*
394fb47a376SStephen J. Kiernan 		 * kldload should fail unless there is a valid fingerprint
395fb47a376SStephen J. Kiernan 		 * registered.
396fb47a376SStephen J. Kiernan 		 */
3973d53cd0fSStephen J. Kiernan 		MAC_VERIEXEC_DBG(2, "fingerprint status is %d for dev %ju, "
3983d53cd0fSStephen J. Kiernan 		    "file %ju.%ju\n", status, (uintmax_t)va.va_fsid,
3993d53cd0fSStephen J. Kiernan 		    (uintmax_t)va.va_fileid, (uintmax_t)va.va_gen);
400fb47a376SStephen J. Kiernan 		return (EAUTH);
401fb47a376SStephen J. Kiernan 	}
402fb47a376SStephen J. Kiernan 
403fb47a376SStephen J. Kiernan 	/* Everything is good, allow the KLD to be loaded */
404fb47a376SStephen J. Kiernan 	return (0);
405fb47a376SStephen J. Kiernan }
406fb47a376SStephen J. Kiernan 
407fb47a376SStephen J. Kiernan /**
408fb47a376SStephen J. Kiernan  * @internal
409fb47a376SStephen J. Kiernan  * @brief Check privileges that veriexec needs to be concerned about.
410fb47a376SStephen J. Kiernan  *
411fb47a376SStephen J. Kiernan  * The following privileges are checked by this function:
412fb47a376SStephen J. Kiernan  *  - PRIV_KMEM_WRITE\n
413fb47a376SStephen J. Kiernan  *    Check if writes to /dev/mem and /dev/kmem are allowed\n
414fb47a376SStephen J. Kiernan  *    (Only trusted processes are allowed)
4158512d82eSSteve Kiernan  *  - PRIV_VERIEXEC_CONTROL\n
4168512d82eSSteve Kiernan  *    Check if manipulating veriexec is allowed\n
4178512d82eSSteve Kiernan  *    (only trusted processes are allowed)
418fb47a376SStephen J. Kiernan  *
419fb47a376SStephen J. Kiernan  * @param cred		credentials to use
420fb47a376SStephen J. Kiernan  * @param priv		privilege to check
421fb47a376SStephen J. Kiernan  *
422fb47a376SStephen J. Kiernan  * @return 0 if the privilege is allowed, error code otherwise.
423fb47a376SStephen J. Kiernan  */
424fb47a376SStephen J. Kiernan static int
mac_veriexec_priv_check(struct ucred * cred,int priv)425fb47a376SStephen J. Kiernan mac_veriexec_priv_check(struct ucred *cred, int priv)
426fb47a376SStephen J. Kiernan {
4278512d82eSSteve Kiernan 	int error;
428fb47a376SStephen J. Kiernan 
429fb47a376SStephen J. Kiernan 	/* If we are not enforcing veriexec, nothing for us to check */
430fb47a376SStephen J. Kiernan 	if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0)
431fb47a376SStephen J. Kiernan 		return (0);
432fb47a376SStephen J. Kiernan 
4338512d82eSSteve Kiernan 	error = 0;
434fb47a376SStephen J. Kiernan 	switch (priv) {
435fb47a376SStephen J. Kiernan 	case PRIV_KMEM_WRITE:
436*4a5fa108SSimon J. Gerraty 	case PRIV_PROC_MEM_WRITE:
4378512d82eSSteve Kiernan 	case PRIV_VERIEXEC_CONTROL:
4388512d82eSSteve Kiernan 		/*
4398512d82eSSteve Kiernan 		 * Do not allow writing to memory or manipulating veriexec,
4408512d82eSSteve Kiernan 		 * unless trusted
4418512d82eSSteve Kiernan 		 */
4428512d82eSSteve Kiernan 		if (mac_veriexec_proc_is_trusted(cred, curproc) == 0 &&
4438512d82eSSteve Kiernan 		    mac_priv_grant(cred, priv) != 0)
4448512d82eSSteve Kiernan 			error = EPERM;
4458512d82eSSteve Kiernan 		MAC_VERIEXEC_DBG(4, "%s priv=%d error=%d", __func__, priv,
4468512d82eSSteve Kiernan 		    error);
447fb47a376SStephen J. Kiernan 		break;
448fb47a376SStephen J. Kiernan 	default:
449fb47a376SStephen J. Kiernan 		break;
450fb47a376SStephen J. Kiernan 	}
4518512d82eSSteve Kiernan 	return (error);
452fb47a376SStephen J. Kiernan }
453fb47a376SStephen J. Kiernan 
4546ae8d576SSimon J. Gerraty /**
4556ae8d576SSimon J. Gerraty  * @internal
4566ae8d576SSimon J. Gerraty  * @brief Check if the requested sysctl should be allowed
4576ae8d576SSimon J. Gerraty  *
4586ae8d576SSimon J. Gerraty  * @param cred         credentials to use
4596ae8d576SSimon J. Gerraty  * @param oidp         sysctl OID
4606ae8d576SSimon J. Gerraty  * @param arg1         first sysctl argument
4616ae8d576SSimon J. Gerraty  * @param arg2         second sysctl argument
4626ae8d576SSimon J. Gerraty  * @param req          sysctl request information
4636ae8d576SSimon J. Gerraty  *
4646ae8d576SSimon J. Gerraty  * @return 0 if the sysctl should be allowed, otherwise an error code.
4656ae8d576SSimon J. Gerraty  */
466ed377cf4SStephen J. Kiernan static int
mac_veriexec_sysctl_check(struct ucred * cred,struct sysctl_oid * oidp,void * arg1,int arg2,struct sysctl_req * req)467ed377cf4SStephen J. Kiernan mac_veriexec_sysctl_check(struct ucred *cred, struct sysctl_oid *oidp,
468ed377cf4SStephen J. Kiernan     void *arg1, int arg2, struct sysctl_req *req)
469ed377cf4SStephen J. Kiernan {
470ed377cf4SStephen J. Kiernan 	struct sysctl_oid *oid;
471ed377cf4SStephen J. Kiernan 
472ed377cf4SStephen J. Kiernan 	/* If we are not enforcing veriexec, nothing for us to check */
473ed377cf4SStephen J. Kiernan 	if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0)
474ed377cf4SStephen J. Kiernan 		return (0);
475ed377cf4SStephen J. Kiernan 
476ed377cf4SStephen J. Kiernan 	oid = oidp;
47715c362aeSWojciech Macek 	if (req->newptr && (oid->oid_kind & CTLFLAG_SECURE)) {
478ed377cf4SStephen J. Kiernan 		return (EPERM);		/* XXX call mac_veriexec_priv_check? */
479ed377cf4SStephen J. Kiernan 	}
480ed377cf4SStephen J. Kiernan 	return 0;
481ed377cf4SStephen J. Kiernan }
482ed377cf4SStephen J. Kiernan 
483fb47a376SStephen J. Kiernan /**
484fb47a376SStephen J. Kiernan  * @internal
485fb47a376SStephen J. Kiernan  * @brief A program is being executed and needs to be validated.
486fb47a376SStephen J. Kiernan  *
487fb47a376SStephen J. Kiernan  * @param cred		credentials to use
488fb47a376SStephen J. Kiernan  * @param vp		vnode of the program that is being executed
489fb47a376SStephen J. Kiernan  * @param label		vnode label assigned to the vnode
490fb47a376SStephen J. Kiernan  * @param imgp		parameters for the image to be executed
491fb47a376SStephen J. Kiernan  * @param execlabel	optional exec label
492fb47a376SStephen J. Kiernan  *
493fb47a376SStephen J. Kiernan  * @return 0 if the program should be allowed to execute, otherwise an error
494fb47a376SStephen J. Kiernan  *     code.
495fb47a376SStephen J. Kiernan  */
496fb47a376SStephen J. Kiernan static int
mac_veriexec_vnode_check_exec(struct ucred * cred __unused,struct vnode * vp __unused,struct label * label __unused,struct image_params * imgp,struct label * execlabel __unused)497fb47a376SStephen J. Kiernan mac_veriexec_vnode_check_exec(struct ucred *cred __unused,
498fb47a376SStephen J. Kiernan     struct vnode *vp __unused, struct label *label __unused,
499fb47a376SStephen J. Kiernan     struct image_params *imgp, struct label *execlabel __unused)
500fb47a376SStephen J. Kiernan {
501fb47a376SStephen J. Kiernan 	struct thread *td = curthread;
502fb47a376SStephen J. Kiernan 	int error;
503fb47a376SStephen J. Kiernan 
504fb47a376SStephen J. Kiernan 	error = mac_veriexec_fingerprint_check_image(imgp, 0, td);
505fb47a376SStephen J. Kiernan 	return (error);
506fb47a376SStephen J. Kiernan }
507fb47a376SStephen J. Kiernan 
508fb47a376SStephen J. Kiernan /**
509fb47a376SStephen J. Kiernan  * @brief Check fingerprint for the specified vnode and validate it
510fb47a376SStephen J. Kiernan  *
511fb47a376SStephen J. Kiernan  * @param cred		credentials to use
512fb47a376SStephen J. Kiernan  * @param vp		vnode of the file
513fb47a376SStephen J. Kiernan  * @param accmode	access mode to check (read, write, append, create,
514fb47a376SStephen J. Kiernan  *			verify, etc.)
515fb47a376SStephen J. Kiernan  *
516fb47a376SStephen J. Kiernan  * @return 0 if the file validated, otherwise an error code.
517fb47a376SStephen J. Kiernan  */
518fb47a376SStephen J. Kiernan static int
mac_veriexec_check_vp(struct ucred * cred,struct vnode * vp,accmode_t accmode)519fb47a376SStephen J. Kiernan mac_veriexec_check_vp(struct ucred *cred, struct vnode *vp, accmode_t accmode)
520fb47a376SStephen J. Kiernan {
521fb47a376SStephen J. Kiernan 	struct vattr va;
522fb47a376SStephen J. Kiernan 	struct thread *td = curthread;
523fb47a376SStephen J. Kiernan 	fingerprint_status_t status;
524fb47a376SStephen J. Kiernan 	int error;
525fb47a376SStephen J. Kiernan 
526fb47a376SStephen J. Kiernan 	/* Get vnode attributes */
527fb47a376SStephen J. Kiernan 	error = VOP_GETATTR(vp, &va, cred);
528fb47a376SStephen J. Kiernan 	if (error)
529fb47a376SStephen J. Kiernan 		return (error);
530fb47a376SStephen J. Kiernan 
531fb47a376SStephen J. Kiernan 	/* Get the fingerprint status for the file */
532fb47a376SStephen J. Kiernan 	error = mac_veriexec_metadata_fetch_fingerprint_status(vp, &va, td,
533fb47a376SStephen J. Kiernan 	    VERIEXEC_FILES_FIRST);
534fb47a376SStephen J. Kiernan 	if (error && error != EAUTH)
535fb47a376SStephen J. Kiernan 		return (error);
536fb47a376SStephen J. Kiernan 
537fb47a376SStephen J. Kiernan 	/*
538fb47a376SStephen J. Kiernan 	 * By now we should have status...
539fb47a376SStephen J. Kiernan 	 */
540fb47a376SStephen J. Kiernan 	status = mac_veriexec_get_fingerprint_status(vp);
541fb47a376SStephen J. Kiernan 	if (accmode & VWRITE) {
542fb47a376SStephen J. Kiernan 		/*
543fb47a376SStephen J. Kiernan 		 * If file has a fingerprint then deny the write request,
544fb47a376SStephen J. Kiernan 		 * otherwise invalidate the status so we don't keep checking
545fb47a376SStephen J. Kiernan 		 * for the file having a fingerprint.
546fb47a376SStephen J. Kiernan 		 */
547fb47a376SStephen J. Kiernan 		switch (status) {
548fb47a376SStephen J. Kiernan 		case FINGERPRINT_FILE:
549fb47a376SStephen J. Kiernan 		case FINGERPRINT_VALID:
550fb47a376SStephen J. Kiernan 		case FINGERPRINT_INDIRECT:
551fb47a376SStephen J. Kiernan 			MAC_VERIEXEC_DBG(2,
552fb47a376SStephen J. Kiernan 			    "attempted write to fingerprinted file for dev "
5533d53cd0fSStephen J. Kiernan 			    "%ju, file %ju.%ju\n", (uintmax_t)va.va_fsid,
5543d53cd0fSStephen J. Kiernan 			    (uintmax_t)va.va_fileid, (uintmax_t)va.va_gen);
555fb47a376SStephen J. Kiernan 			return (EPERM);
556fb47a376SStephen J. Kiernan 		default:
557fb47a376SStephen J. Kiernan 			break;
558fb47a376SStephen J. Kiernan 		}
559fb47a376SStephen J. Kiernan 	}
560fb47a376SStephen J. Kiernan 	if (accmode & VVERIFY) {
561fb47a376SStephen J. Kiernan 		switch (status) {
562fb47a376SStephen J. Kiernan 		case FINGERPRINT_FILE:
563fb47a376SStephen J. Kiernan 		case FINGERPRINT_VALID:
564fb47a376SStephen J. Kiernan 		case FINGERPRINT_INDIRECT:
565fb47a376SStephen J. Kiernan 			if (error)
566fb47a376SStephen J. Kiernan 				return (error);
567fb47a376SStephen J. Kiernan 			break;
568fb47a376SStephen J. Kiernan 		default:
5696ae8d576SSimon J. Gerraty 			/* Allow for overriding verification requirement */
5706ae8d576SSimon J. Gerraty 			if (mac_priv_grant(cred, PRIV_VERIEXEC_NOVERIFY) == 0)
5716ae8d576SSimon J. Gerraty 				return (0);
572fb47a376SStephen J. Kiernan 			/*
573fb47a376SStephen J. Kiernan 			 * Caller wants open to fail unless there is a valid
574fb47a376SStephen J. Kiernan 			 * fingerprint registered.
575fb47a376SStephen J. Kiernan 			 */
576fb47a376SStephen J. Kiernan 			MAC_VERIEXEC_DBG(2, "fingerprint status is %d for dev "
5773d53cd0fSStephen J. Kiernan 			    "%ju, file %ju.%ju\n", status,
5783d53cd0fSStephen J. Kiernan 			    (uintmax_t)va.va_fsid, (uintmax_t)va.va_fileid,
5793d53cd0fSStephen J. Kiernan 			    (uintmax_t)va.va_gen);
580fb47a376SStephen J. Kiernan 			return (EAUTH);
581fb47a376SStephen J. Kiernan 		}
582fb47a376SStephen J. Kiernan 	}
583fb47a376SStephen J. Kiernan 	return (0);
584fb47a376SStephen J. Kiernan }
585fb47a376SStephen J. Kiernan 
586fb47a376SStephen J. Kiernan /**
587fb47a376SStephen J. Kiernan  * @brief Opening a file has been requested and may need to be validated.
588fb47a376SStephen J. Kiernan  *
589fb47a376SStephen J. Kiernan  * @param cred		credentials to use
590fb47a376SStephen J. Kiernan  * @param vp		vnode of the file to open
591fb47a376SStephen J. Kiernan  * @param label		vnode label assigned to the vnode
592fb47a376SStephen J. Kiernan  * @param accmode	access mode to use for opening the file (read, write,
593fb47a376SStephen J. Kiernan  * 			append, create, verify, etc.)
594fb47a376SStephen J. Kiernan  *
595fb47a376SStephen J. Kiernan  * @return 0 if opening the file should be allowed, otherwise an error code.
596fb47a376SStephen J. Kiernan  */
597fb47a376SStephen J. Kiernan static int
mac_veriexec_vnode_check_open(struct ucred * cred,struct vnode * vp,struct label * label __unused,accmode_t accmode)598fb47a376SStephen J. Kiernan mac_veriexec_vnode_check_open(struct ucred *cred, struct vnode *vp,
599fb47a376SStephen J. Kiernan 	struct label *label __unused, accmode_t accmode)
600fb47a376SStephen J. Kiernan {
601fb47a376SStephen J. Kiernan 	int error;
602fb47a376SStephen J. Kiernan 
603fb47a376SStephen J. Kiernan 	/*
604fb47a376SStephen J. Kiernan 	 * Look for the file on the fingerprint lists iff it has not been seen
605fb47a376SStephen J. Kiernan 	 * before.
606fb47a376SStephen J. Kiernan 	 */
607fb47a376SStephen J. Kiernan 	if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0)
608fb47a376SStephen J. Kiernan 		return (0);
609fb47a376SStephen J. Kiernan 
610fb47a376SStephen J. Kiernan 	error = mac_veriexec_check_vp(cred, vp, accmode);
611fb47a376SStephen J. Kiernan 	return (error);
612fb47a376SStephen J. Kiernan }
613fb47a376SStephen J. Kiernan 
614fb47a376SStephen J. Kiernan /**
6152ef8babaSdl  * @brief Unlink on a file has been requested and may need to be validated.
6162ef8babaSdl  *
6172ef8babaSdl  * @param cred		credentials to use
6182ef8babaSdl  * @param dvp		parent directory for file vnode vp
6192ef8babaSdl  * @param dlabel	vnode label assigned to the directory vnode
6202ef8babaSdl  * @param vp		vnode of the file to unlink
6212ef8babaSdl  * @param label		vnode label assigned to the vnode
6222ef8babaSdl  * @param cnp		component name for vp
6232ef8babaSdl  *
6242ef8babaSdl  *
6252ef8babaSdl  * @return 0 if opening the file should be allowed, otherwise an error code.
6262ef8babaSdl  */
6272ef8babaSdl static int
mac_veriexec_vnode_check_unlink(struct ucred * cred,struct vnode * dvp __unused,struct label * dvplabel __unused,struct vnode * vp,struct label * label __unused,struct componentname * cnp __unused)6282ef8babaSdl mac_veriexec_vnode_check_unlink(struct ucred *cred, struct vnode *dvp __unused,
6292ef8babaSdl     struct label *dvplabel __unused, struct vnode *vp,
6302ef8babaSdl     struct label *label __unused, struct componentname *cnp __unused)
6312ef8babaSdl {
6322ef8babaSdl 	int error;
6332ef8babaSdl 
6342ef8babaSdl 	/*
6352ef8babaSdl 	 * Look for the file on the fingerprint lists iff it has not been seen
6362ef8babaSdl 	 * before.
6372ef8babaSdl 	 */
6382ef8babaSdl 	if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0)
6392ef8babaSdl 		return (0);
6402ef8babaSdl 
6412ef8babaSdl 	error = mac_veriexec_check_vp(cred, vp, VVERIFY);
642559e41a1SWarner Losh 	if (error == 0) {
643559e41a1SWarner Losh 		/*
644559e41a1SWarner Losh 		 * The target is verified, so disallow replacement.
645559e41a1SWarner Losh 		 */
6462ef8babaSdl 		MAC_VERIEXEC_DBG(2,
6472ef8babaSdl     "(UNLINK) attempted to unlink a protected file (euid: %u)", cred->cr_uid);
6482ef8babaSdl 
6492ef8babaSdl 		return (EAUTH);
6502ef8babaSdl 	}
6512ef8babaSdl 	return (0);
6522ef8babaSdl }
6532ef8babaSdl 
6542ef8babaSdl /**
6552ef8babaSdl  * @brief Rename the file has been requested and may need to be validated.
6562ef8babaSdl  *
6572ef8babaSdl  * @param cred		credentials to use
6582ef8babaSdl  * @param dvp		parent directory for file vnode vp
6592ef8babaSdl  * @param dlabel	vnode label assigned to the directory vnode
6602ef8babaSdl  * @param vp		vnode of the file to rename
6612ef8babaSdl  * @param label		vnode label assigned to the vnode
6622ef8babaSdl  * @param cnp		component name for vp
6632ef8babaSdl  *
6642ef8babaSdl  *
6652ef8babaSdl  * @return 0 if opening the file should be allowed, otherwise an error code.
6662ef8babaSdl  */
6672ef8babaSdl static int
mac_veriexec_vnode_check_rename_from(struct ucred * cred,struct vnode * dvp __unused,struct label * dvplabel __unused,struct vnode * vp,struct label * label __unused,struct componentname * cnp __unused)6682ef8babaSdl mac_veriexec_vnode_check_rename_from(struct ucred *cred,
6692ef8babaSdl     struct vnode *dvp __unused, struct label *dvplabel __unused,
6702ef8babaSdl     struct vnode *vp, struct label *label __unused,
6712ef8babaSdl     struct componentname *cnp __unused)
6722ef8babaSdl {
6732ef8babaSdl 	int error;
6742ef8babaSdl 
6752ef8babaSdl 	/*
6762ef8babaSdl 	 * Look for the file on the fingerprint lists iff it has not been seen
6772ef8babaSdl 	 * before.
6782ef8babaSdl 	 */
6792ef8babaSdl 	if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0)
6802ef8babaSdl 		return (0);
6812ef8babaSdl 
6822ef8babaSdl 	error = mac_veriexec_check_vp(cred, vp, VVERIFY);
683559e41a1SWarner Losh 	if (error == 0) {
684559e41a1SWarner Losh 		/*
685559e41a1SWarner Losh 		 * The target is verified, so disallow replacement.
686559e41a1SWarner Losh 		 */
6872ef8babaSdl 		MAC_VERIEXEC_DBG(2,
6882ef8babaSdl     "(RENAME_FROM) attempted to rename a protected file (euid: %u)", cred->cr_uid);
6892ef8babaSdl 		return (EAUTH);
6902ef8babaSdl 	}
6912ef8babaSdl 	return (0);
6922ef8babaSdl }
6932ef8babaSdl 
6942ef8babaSdl 
6952ef8babaSdl /**
6962ef8babaSdl  * @brief Rename to file into the directory (overwrite the file name) has been
6972ef8babaSdl  * requested and may need to be validated.
6982ef8babaSdl  *
6992ef8babaSdl  * @param cred		credentials to use
7002ef8babaSdl  * @param dvp		parent directory for file vnode vp
7012ef8babaSdl  * @param dlabel	vnode label assigned to the directory vnode
7022ef8babaSdl  * @param vp		vnode of the overwritten file
7032ef8babaSdl  * @param label		vnode label assigned to the vnode
7042ef8babaSdl  * @param samedir	1 if the source and destination directories are the same
7052ef8babaSdl  * @param cnp		component name for vp
7062ef8babaSdl  *
7072ef8babaSdl  *
7082ef8babaSdl  * @return 0 if opening the file should be allowed, otherwise an error code.
7092ef8babaSdl  */
7102ef8babaSdl 	static int
mac_veriexec_vnode_check_rename_to(struct ucred * cred,struct vnode * dvp __unused,struct label * dvplabel __unused,struct vnode * vp,struct label * label __unused,int samedir __unused,struct componentname * cnp __unused)7112ef8babaSdl mac_veriexec_vnode_check_rename_to(struct ucred *cred, struct vnode *dvp __unused,
7122ef8babaSdl     struct label *dvplabel __unused, struct vnode *vp,
7132ef8babaSdl     struct label *label __unused, int samedir __unused,
7142ef8babaSdl     struct componentname *cnp __unused)
7152ef8babaSdl {
7162ef8babaSdl 	int error;
7172ef8babaSdl 	/*
7182ef8babaSdl 	 * If there is no existing file to overwrite, vp and label will be
7192ef8babaSdl 	 * NULL.
7202ef8babaSdl 	 */
7212ef8babaSdl 	if (vp == NULL)
7222ef8babaSdl 		return (0);
7232ef8babaSdl 
7242ef8babaSdl 	/*
7252ef8babaSdl 	 * Look for the file on the fingerprint lists iff it has not been seen
7262ef8babaSdl 	 * before.
7272ef8babaSdl 	 */
7282ef8babaSdl 	if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0)
7292ef8babaSdl 		return (0);
7302ef8babaSdl 
7312ef8babaSdl 	error = mac_veriexec_check_vp(cred, vp, VVERIFY);
732559e41a1SWarner Losh 	if (error == 0) {
733559e41a1SWarner Losh 		/*
734559e41a1SWarner Losh 		 * The target is verified, so disallow replacement.
735559e41a1SWarner Losh 		 */
7362ef8babaSdl 		MAC_VERIEXEC_DBG(2,
7372ef8babaSdl     "(RENAME_TO) attempted to overwrite a protected file (euid: %u)", cred->cr_uid);
7382ef8babaSdl 		return (EAUTH);
7392ef8babaSdl 	}
7402ef8babaSdl 	return (0);
7412ef8babaSdl }
7422ef8babaSdl 
7432ef8babaSdl 
7442ef8babaSdl /**
745ade97886SStephen J. Kiernan  * @brief Check mode changes on file to ensure they should be allowed.
746ade97886SStephen J. Kiernan  *
747ade97886SStephen J. Kiernan  * We cannot allow chmod of SUID or SGID on verified files.
748ade97886SStephen J. Kiernan  *
749ade97886SStephen J. Kiernan  * @param cred		credentials to use
750ade97886SStephen J. Kiernan  * @param vp		vnode of the file to open
751ade97886SStephen J. Kiernan  * @param label		vnode label assigned to the vnode
752ade97886SStephen J. Kiernan  * @param mode		mode flags to set
753ade97886SStephen J. Kiernan  *
754ade97886SStephen J. Kiernan  * @return 0 if the mode change should be allowed, EAUTH otherwise.
755ade97886SStephen J. Kiernan  */
756ade97886SStephen J. Kiernan static int
mac_veriexec_vnode_check_setmode(struct ucred * cred,struct vnode * vp,struct label * label __unused,mode_t mode)757ade97886SStephen J. Kiernan mac_veriexec_vnode_check_setmode(struct ucred *cred, struct vnode *vp,
758ade97886SStephen J. Kiernan     struct label *label __unused, mode_t mode)
759ade97886SStephen J. Kiernan {
760ade97886SStephen J. Kiernan 	int error;
761ade97886SStephen J. Kiernan 
762ade97886SStephen J. Kiernan 	if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0)
763ade97886SStephen J. Kiernan 		return (0);
764ade97886SStephen J. Kiernan 
765ade97886SStephen J. Kiernan 	/*
766559e41a1SWarner Losh 	 * Prohibit chmod of verified set-[gu]id file.
767ade97886SStephen J. Kiernan 	 */
768ade97886SStephen J. Kiernan 	error = mac_veriexec_check_vp(cred, vp, VVERIFY);
769559e41a1SWarner Losh 	if (error == EAUTH)		/* target not verified */
770ade97886SStephen J. Kiernan 		return (0);
771ade97886SStephen J. Kiernan 	if (error == 0 && (mode & (S_ISUID|S_ISGID)) != 0)
772ade97886SStephen J. Kiernan 		return (EAUTH);
773559e41a1SWarner Losh 
774ade97886SStephen J. Kiernan 	return (0);
775ade97886SStephen J. Kiernan }
776ade97886SStephen J. Kiernan 
777ade97886SStephen J. Kiernan /**
778fb47a376SStephen J. Kiernan  * @internal
779fb47a376SStephen J. Kiernan  * @brief Initialize the mac_veriexec MAC policy
780fb47a376SStephen J. Kiernan  *
781fb47a376SStephen J. Kiernan  * @param mpc		MAC policy configuration
782fb47a376SStephen J. Kiernan  */
783fb47a376SStephen J. Kiernan static void
mac_veriexec_init(struct mac_policy_conf * mpc __unused)784fb47a376SStephen J. Kiernan mac_veriexec_init(struct mac_policy_conf *mpc __unused)
785fb47a376SStephen J. Kiernan {
786fb47a376SStephen J. Kiernan 	/* Initialize state */
787fb47a376SStephen J. Kiernan 	mac_veriexec_state = VERIEXEC_STATE_INACTIVE;
788fb47a376SStephen J. Kiernan 
789fb47a376SStephen J. Kiernan 	/* Initialize meta-data storage */
790fb47a376SStephen J. Kiernan 	mac_veriexec_metadata_init();
791fb47a376SStephen J. Kiernan 
792fb47a376SStephen J. Kiernan 	/* Initialize fingerprint ops */
793fb47a376SStephen J. Kiernan 	mac_veriexec_fingerprint_init();
794fb47a376SStephen J. Kiernan 
795fb47a376SStephen J. Kiernan 	/* Register event handlers */
796fb47a376SStephen J. Kiernan 	EVENTHANDLER_REGISTER(vfs_mounted, mac_veriexec_vfs_mounted, NULL,
797fb47a376SStephen J. Kiernan 	    EVENTHANDLER_PRI_FIRST);
798fb47a376SStephen J. Kiernan 	EVENTHANDLER_REGISTER(vfs_unmounted, mac_veriexec_vfs_unmounted, NULL,
799fb47a376SStephen J. Kiernan 	    EVENTHANDLER_PRI_LAST);
8002ef8babaSdl 
8012ef8babaSdl 	/* Check if unlink control is activated via tunable value */
8022ef8babaSdl 	if (!mac_veriexec_block_unlink)
8032ef8babaSdl 		mac_veriexec_ops.mpo_vnode_check_unlink = NULL;
804fb47a376SStephen J. Kiernan }
805fb47a376SStephen J. Kiernan 
8068c3e263dSSimon J. Gerraty #ifdef COMPAT_FREEBSD32
8078c3e263dSSimon J. Gerraty struct mac_veriexec_syscall_params32  {
8088c3e263dSSimon J. Gerraty 	char fp_type[VERIEXEC_FPTYPELEN];
8098c3e263dSSimon J. Gerraty 	unsigned char fingerprint[MAXFINGERPRINTLEN];
8108c3e263dSSimon J. Gerraty 	char label[MAXLABELLEN];
8118c3e263dSSimon J. Gerraty 	uint32_t labellen;
8128c3e263dSSimon J. Gerraty 	unsigned char flags;
8138c3e263dSSimon J. Gerraty };
8148c3e263dSSimon J. Gerraty 
8158c3e263dSSimon J. Gerraty struct mac_veriexec_syscall_params_args32 {
8168c3e263dSSimon J. Gerraty 	union {
8178c3e263dSSimon J. Gerraty 		pid_t pid;
8188c3e263dSSimon J. Gerraty 		uint32_t filename;
8198c3e263dSSimon J. Gerraty 	} u;				  /* input only */
8208c3e263dSSimon J. Gerraty 	uint32_t params;		  /* result */
8218c3e263dSSimon J. Gerraty };
8228c3e263dSSimon J. Gerraty #endif
8238c3e263dSSimon J. Gerraty 
824fb47a376SStephen J. Kiernan /**
825fb47a376SStephen J. Kiernan  * @internal
826fb47a376SStephen J. Kiernan  * @brief MAC policy-specific syscall for mac_veriexec
827fb47a376SStephen J. Kiernan  *
828fb47a376SStephen J. Kiernan  * The following syscalls are implemented:
829fb47a376SStephen J. Kiernan  *   - @c MAC_VERIEXEC_CHECK_SYSCALL
830fb47a376SStephen J. Kiernan  *        Check if the file referenced by a file descriptor has a fingerprint
831fb47a376SStephen J. Kiernan  *        registered in the meta-data store.
832fb47a376SStephen J. Kiernan  *
833fb47a376SStephen J. Kiernan  * @param td		calling thread
834fb47a376SStephen J. Kiernan  * @param call		system call number
835fb47a376SStephen J. Kiernan  * @param arg		arugments to the syscall
836fb47a376SStephen J. Kiernan  *
837fb47a376SStephen J. Kiernan  * @return 0 on success, otherwise an error code.
838fb47a376SStephen J. Kiernan  */
839fb47a376SStephen J. Kiernan static int
mac_veriexec_syscall(struct thread * td,int call,void * arg)840fb47a376SStephen J. Kiernan mac_veriexec_syscall(struct thread *td, int call, void *arg)
841fb47a376SStephen J. Kiernan {
842fb47a376SStephen J. Kiernan 	struct image_params img;
843fb47a376SStephen J. Kiernan 	struct nameidata nd;
844fb47a376SStephen J. Kiernan 	cap_rights_t rights;
845fb47a376SStephen J. Kiernan 	struct vattr va;
846fb47a376SStephen J. Kiernan 	struct file *fp;
8478512d82eSSteve Kiernan 	struct mac_veriexec_syscall_params_args pargs;
8488512d82eSSteve Kiernan 	struct mac_veriexec_syscall_params result;
8498c3e263dSSimon J. Gerraty #ifdef COMPAT_FREEBSD32
8508c3e263dSSimon J. Gerraty 	struct mac_veriexec_syscall_params_args32 pargs32;
8518c3e263dSSimon J. Gerraty 	struct mac_veriexec_syscall_params32 result32;
8528c3e263dSSimon J. Gerraty #endif
8538512d82eSSteve Kiernan 	struct mac_veriexec_file_info *ip;
8548512d82eSSteve Kiernan 	struct proc *proc;
8558512d82eSSteve Kiernan 	struct vnode *textvp;
8568512d82eSSteve Kiernan 	int error, flags, proc_locked;
8578512d82eSSteve Kiernan 
8588512d82eSSteve Kiernan 	nd.ni_vp = NULL;
8598512d82eSSteve Kiernan 	proc_locked = 0;
8608512d82eSSteve Kiernan 	textvp = NULL;
8618512d82eSSteve Kiernan 	switch (call) {
8628512d82eSSteve Kiernan 	case MAC_VERIEXEC_GET_PARAMS_PID_SYSCALL:
8638512d82eSSteve Kiernan 	case MAC_VERIEXEC_GET_PARAMS_PATH_SYSCALL:
8648c3e263dSSimon J. Gerraty #ifdef COMPAT_FREEBSD32
8658c3e263dSSimon J. Gerraty 		if (SV_PROC_FLAG(td->td_proc, SV_ILP32)) {
8668c3e263dSSimon J. Gerraty 			error = copyin(arg, &pargs32, sizeof(pargs32));
8678c3e263dSSimon J. Gerraty 			if (error)
8688c3e263dSSimon J. Gerraty 				return error;
8698c3e263dSSimon J. Gerraty 			bzero(&pargs, sizeof(pargs));
8708c3e263dSSimon J. Gerraty 			switch (call) {
8718c3e263dSSimon J. Gerraty 			case MAC_VERIEXEC_GET_PARAMS_PID_SYSCALL:
8728c3e263dSSimon J. Gerraty 				CP(pargs32, pargs, u.pid);
8738c3e263dSSimon J. Gerraty 				break;
8748c3e263dSSimon J. Gerraty 			case MAC_VERIEXEC_GET_PARAMS_PATH_SYSCALL:
8758c3e263dSSimon J. Gerraty 				PTRIN_CP(pargs32, pargs, u.filename);
8768c3e263dSSimon J. Gerraty 				break;
8778c3e263dSSimon J. Gerraty 			}
8788c3e263dSSimon J. Gerraty 			PTRIN_CP(pargs32, pargs, params);
8798c3e263dSSimon J. Gerraty 		} else
8808c3e263dSSimon J. Gerraty #endif
8818512d82eSSteve Kiernan 		error = copyin(arg, &pargs, sizeof(pargs));
8828512d82eSSteve Kiernan 		if (error)
8838512d82eSSteve Kiernan 			return error;
8848512d82eSSteve Kiernan 		break;
8858512d82eSSteve Kiernan 	}
886fb47a376SStephen J. Kiernan 
887fb47a376SStephen J. Kiernan 	switch (call) {
888fb47a376SStephen J. Kiernan 	case MAC_VERIEXEC_CHECK_FD_SYSCALL:
889fb47a376SStephen J. Kiernan 		/* Get the vnode associated with the file descriptor passed */
8906b3a9a0fSMateusz Guzik 		error = getvnode(td, (uintptr_t) arg,
8916b3a9a0fSMateusz Guzik 		    cap_rights_init_one(&rights, CAP_READ), &fp);
892fb47a376SStephen J. Kiernan 		if (error)
893fb47a376SStephen J. Kiernan 			return (error);
894fb47a376SStephen J. Kiernan 		if (fp->f_type != DTYPE_VNODE) {
895fb47a376SStephen J. Kiernan 			MAC_VERIEXEC_DBG(3, "MAC_VERIEXEC_CHECK_SYSCALL: "
896fb47a376SStephen J. Kiernan 			    "file is not vnode type (type=0x%x)",
897fb47a376SStephen J. Kiernan 			    fp->f_type);
898fb47a376SStephen J. Kiernan 			error = EINVAL;
899fb47a376SStephen J. Kiernan 			goto cleanup_file;
900fb47a376SStephen J. Kiernan 		}
901fb47a376SStephen J. Kiernan 
902fb47a376SStephen J. Kiernan 		/*
903fb47a376SStephen J. Kiernan 		 * setup the bits of image_params that are used by
904fb47a376SStephen J. Kiernan 		 * mac_veriexec_check_fingerprint().
905fb47a376SStephen J. Kiernan 		 */
906fb47a376SStephen J. Kiernan 		bzero(&img, sizeof(img));
907fb47a376SStephen J. Kiernan 		img.proc = td->td_proc;
908fb47a376SStephen J. Kiernan 		img.vp = fp->f_vnode;
909fb47a376SStephen J. Kiernan 		img.attr = &va;
910fb47a376SStephen J. Kiernan 
911fb47a376SStephen J. Kiernan 		/*
912fb47a376SStephen J. Kiernan 		 * Get vnode attributes
913fb47a376SStephen J. Kiernan 		 * (need to obtain a lock on the vnode first)
914fb47a376SStephen J. Kiernan 		 */
915fb47a376SStephen J. Kiernan 		vn_lock(img.vp, LK_EXCLUSIVE | LK_RETRY);
916fb47a376SStephen J. Kiernan 		error = VOP_GETATTR(fp->f_vnode, &va,  td->td_ucred);
917fb47a376SStephen J. Kiernan 		if (error)
918fb47a376SStephen J. Kiernan 			goto check_done;
919fb47a376SStephen J. Kiernan 
920fb47a376SStephen J. Kiernan 		MAC_VERIEXEC_DBG(2, "mac_veriexec_fingerprint_check_image: "
921fb47a376SStephen J. Kiernan 		    "va_mode=%o, check_files=%d\n", va.va_mode,
922fb47a376SStephen J. Kiernan 		    ((va.va_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0));
923fb47a376SStephen J. Kiernan 		error = mac_veriexec_fingerprint_check_image(&img,
924fb47a376SStephen J. Kiernan 		    ((va.va_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0), td);
925fb47a376SStephen J. Kiernan check_done:
926fb47a376SStephen J. Kiernan 		/* Release the lock we obtained earlier */
927b249ce48SMateusz Guzik 		VOP_UNLOCK(img.vp);
928fb47a376SStephen J. Kiernan cleanup_file:
929fb47a376SStephen J. Kiernan 		fdrop(fp, td);
930fb47a376SStephen J. Kiernan 		break;
931fb47a376SStephen J. Kiernan 	case MAC_VERIEXEC_CHECK_PATH_SYSCALL:
932fb47a376SStephen J. Kiernan 		/* Look up the path to get the vnode */
9336cbc9703SStephen J. Kiernan 		NDINIT(&nd, LOOKUP,
9346cbc9703SStephen J. Kiernan 		    FOLLOW | LOCKLEAF | LOCKSHARED | AUDITVNODE1,
9357e1d3eefSMateusz Guzik 		    UIO_USERSPACE, arg);
9368512d82eSSteve Kiernan 		flags = FREAD;
9378512d82eSSteve Kiernan 		error = vn_open(&nd, &flags, 0, NULL);
938fb47a376SStephen J. Kiernan 		if (error != 0)
939fb47a376SStephen J. Kiernan 			break;
940bb92cd7bSMateusz Guzik 		NDFREE_PNBUF(&nd);
941fb47a376SStephen J. Kiernan 
942fb47a376SStephen J. Kiernan 		/* Check the fingerprint status of the vnode */
943fb47a376SStephen J. Kiernan 		error = mac_veriexec_check_vp(td->td_ucred, nd.ni_vp, VVERIFY);
9448512d82eSSteve Kiernan 		/* nd.ni_vp cleaned up below */
9458512d82eSSteve Kiernan 		break;
9468512d82eSSteve Kiernan 	case MAC_VERIEXEC_GET_PARAMS_PID_SYSCALL:
9478512d82eSSteve Kiernan 		if (pargs.u.pid == 0 || pargs.u.pid == curproc->p_pid) {
9488512d82eSSteve Kiernan 			proc = curproc;
9498512d82eSSteve Kiernan 		} else {
9508512d82eSSteve Kiernan 			proc = pfind(pargs.u.pid);
9518512d82eSSteve Kiernan 			if (proc == NULL)
9528512d82eSSteve Kiernan 				return (EINVAL);
9538512d82eSSteve Kiernan 			proc_locked = 1;
9548512d82eSSteve Kiernan 		}
9558512d82eSSteve Kiernan 		textvp = proc->p_textvp;
9568512d82eSSteve Kiernan 		/* FALLTHROUGH */
9578512d82eSSteve Kiernan 	case MAC_VERIEXEC_GET_PARAMS_PATH_SYSCALL:
9588512d82eSSteve Kiernan 		if (textvp == NULL) {
9598512d82eSSteve Kiernan 			/* Look up the path to get the vnode */
9608512d82eSSteve Kiernan 			NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | AUDITVNODE1,
9618512d82eSSteve Kiernan 			    UIO_USERSPACE, pargs.u.filename);
9628512d82eSSteve Kiernan 			flags = FREAD;
9638512d82eSSteve Kiernan 			error = vn_open(&nd, &flags, 0, NULL);
9648512d82eSSteve Kiernan 			if (error != 0)
9658512d82eSSteve Kiernan 				break;
9668512d82eSSteve Kiernan 
9678512d82eSSteve Kiernan 			NDFREE_PNBUF(&nd);
9688512d82eSSteve Kiernan 			textvp = nd.ni_vp;
9698512d82eSSteve Kiernan 		}
9708512d82eSSteve Kiernan 		error = VOP_GETATTR(textvp, &va, curproc->p_ucred);
9718512d82eSSteve Kiernan 		if (proc_locked)
9728512d82eSSteve Kiernan 			PROC_UNLOCK(proc);
9738512d82eSSteve Kiernan 		if (error != 0)
9748512d82eSSteve Kiernan 			break;
9758512d82eSSteve Kiernan 
9768512d82eSSteve Kiernan 		error = mac_veriexec_metadata_get_file_info(va.va_fsid,
9778512d82eSSteve Kiernan 		    va.va_fileid, va.va_gen, NULL, &ip, FALSE);
9788512d82eSSteve Kiernan 		if (error != 0)
9798512d82eSSteve Kiernan 			break;
9808512d82eSSteve Kiernan 
9818c3e263dSSimon J. Gerraty #ifdef COMPAT_FREEBSD32
9828c3e263dSSimon J. Gerraty 		if (SV_PROC_FLAG(td->td_proc, SV_ILP32)) {
9838c3e263dSSimon J. Gerraty 			bzero(&result32, sizeof(result32));
9848c3e263dSSimon J. Gerraty 			result32.flags = ip->flags;
9858c3e263dSSimon J. Gerraty 			strlcpy(result32.fp_type, ip->ops->type, sizeof(result32.fp_type));
9868c3e263dSSimon J. Gerraty 			result.labellen = ip->labellen;
9878c3e263dSSimon J. Gerraty 			CP(result, result32, labellen);
9888c3e263dSSimon J. Gerraty 			if (ip->labellen > 0)
9898c3e263dSSimon J. Gerraty 				strlcpy(result32.label, ip->label, sizeof(result32.label));
9908c3e263dSSimon J. Gerraty 			result32.label[result.labellen] = '\0';
9918c3e263dSSimon J. Gerraty 			memcpy(result32.fingerprint, ip->fingerprint,
9928c3e263dSSimon J. Gerraty 			    ip->ops->digest_len);
9938c3e263dSSimon J. Gerraty 
9948c3e263dSSimon J. Gerraty 			error = copyout(&result32, pargs.params, sizeof(result32));
9958c3e263dSSimon J. Gerraty 			break;		/* yes */
9968c3e263dSSimon J. Gerraty 		}
9978c3e263dSSimon J. Gerraty #endif
9988c3e263dSSimon J. Gerraty 		bzero(&result, sizeof(result));
9998512d82eSSteve Kiernan 		result.flags = ip->flags;
10008512d82eSSteve Kiernan 		strlcpy(result.fp_type, ip->ops->type, sizeof(result.fp_type));
10018512d82eSSteve Kiernan 		result.labellen = ip->labellen;
10028512d82eSSteve Kiernan 		if (ip->labellen > 0)
10038512d82eSSteve Kiernan 			strlcpy(result.label, ip->label, sizeof(result.label));
10048512d82eSSteve Kiernan 		result.label[result.labellen] = '\0';
10058512d82eSSteve Kiernan 		memcpy(result.fingerprint, ip->fingerprint,
10068512d82eSSteve Kiernan 		    ip->ops->digest_len);
10078512d82eSSteve Kiernan 
10088512d82eSSteve Kiernan 		error = copyout(&result, pargs.params, sizeof(result));
1009fb47a376SStephen J. Kiernan 		break;
1010fb47a376SStephen J. Kiernan 	default:
1011fb47a376SStephen J. Kiernan 		error = EOPNOTSUPP;
1012fb47a376SStephen J. Kiernan 	}
10138512d82eSSteve Kiernan 	if (nd.ni_vp != NULL) {
10148512d82eSSteve Kiernan 		VOP_UNLOCK(nd.ni_vp);
10158512d82eSSteve Kiernan 		vn_close(nd.ni_vp, FREAD, td->td_ucred, td);
10168512d82eSSteve Kiernan 	}
1017fb47a376SStephen J. Kiernan 	return (error);
1018fb47a376SStephen J. Kiernan }
1019fb47a376SStephen J. Kiernan 
1020fb47a376SStephen J. Kiernan static struct mac_policy_ops mac_veriexec_ops =
1021fb47a376SStephen J. Kiernan {
1022fb47a376SStephen J. Kiernan 	.mpo_init = mac_veriexec_init,
1023fb47a376SStephen J. Kiernan 	.mpo_kld_check_load = mac_veriexec_kld_check_load,
1024fb47a376SStephen J. Kiernan 	.mpo_mount_destroy_label = mac_veriexec_mount_destroy_label,
1025fb47a376SStephen J. Kiernan 	.mpo_mount_init_label = mac_veriexec_mount_init_label,
1026fb47a376SStephen J. Kiernan 	.mpo_priv_check = mac_veriexec_priv_check,
1027fb47a376SStephen J. Kiernan 	.mpo_proc_check_debug = mac_veriexec_proc_check_debug,
1028ed377cf4SStephen J. Kiernan 	.mpo_syscall = mac_veriexec_syscall,
1029ed377cf4SStephen J. Kiernan 	.mpo_system_check_sysctl = mac_veriexec_sysctl_check,
1030fb47a376SStephen J. Kiernan 	.mpo_vnode_check_exec = mac_veriexec_vnode_check_exec,
1031fb47a376SStephen J. Kiernan 	.mpo_vnode_check_open = mac_veriexec_vnode_check_open,
10322ef8babaSdl 	.mpo_vnode_check_unlink = mac_veriexec_vnode_check_unlink,
10332ef8babaSdl 	.mpo_vnode_check_rename_to = mac_veriexec_vnode_check_rename_to,
10342ef8babaSdl 	.mpo_vnode_check_rename_from = mac_veriexec_vnode_check_rename_from,
1035ade97886SStephen J. Kiernan 	.mpo_vnode_check_setmode = mac_veriexec_vnode_check_setmode,
1036fb47a376SStephen J. Kiernan 	.mpo_vnode_copy_label = mac_veriexec_copy_label,
1037fb47a376SStephen J. Kiernan 	.mpo_vnode_destroy_label = mac_veriexec_vnode_destroy_label,
1038fb47a376SStephen J. Kiernan 	.mpo_vnode_init_label = mac_veriexec_vnode_init_label,
1039fb47a376SStephen J. Kiernan };
1040fb47a376SStephen J. Kiernan 
1041fb47a376SStephen J. Kiernan MAC_POLICY_SET(&mac_veriexec_ops, mac_veriexec, MAC_VERIEXEC_FULLNAME,
1042fb47a376SStephen J. Kiernan     MPC_LOADTIME_FLAG_NOTLATE, &mac_veriexec_slot);
1043fe8ce390SWojciech Macek MODULE_VERSION(mac_veriexec, MAC_VERIEXEC_VERSION);
1044fb47a376SStephen J. Kiernan 
1045478368caSMateusz Guzik static struct vnode *
mac_veriexec_bottom_vnode(struct vnode * vp)1046478368caSMateusz Guzik mac_veriexec_bottom_vnode(struct vnode *vp)
1047478368caSMateusz Guzik {
1048478368caSMateusz Guzik 	struct vnode *ldvp = NULL;
1049478368caSMateusz Guzik 
1050478368caSMateusz Guzik 	/*
1051478368caSMateusz Guzik 	 * XXX This code is bogus. nullfs is not the only stacking
1052478368caSMateusz Guzik 	 * filesystem. Less bogus code would add a VOP to reach bottom
1053478368caSMateusz Guzik 	 * vnode and would not make assumptions how to get there.
1054478368caSMateusz Guzik 	 */
1055478368caSMateusz Guzik 	if (vp->v_mount != NULL &&
1056478368caSMateusz Guzik 	    strcmp(vp->v_mount->mnt_vfc->vfc_name, "nullfs") == 0)
1057478368caSMateusz Guzik 		ldvp = NULLVPTOLOWERVP(vp);
1058478368caSMateusz Guzik 	return (ldvp);
1059478368caSMateusz Guzik }
1060478368caSMateusz Guzik 
1061fb47a376SStephen J. Kiernan /**
1062fb47a376SStephen J. Kiernan  * @brief Get the fingerprint status set on a vnode.
1063fb47a376SStephen J. Kiernan  *
1064fb47a376SStephen J. Kiernan  * @param vp		vnode to obtain fingerprint status from
1065fb47a376SStephen J. Kiernan  *
1066fb47a376SStephen J. Kiernan  * @return Fingerprint status assigned to the vnode.
1067fb47a376SStephen J. Kiernan  */
1068fb47a376SStephen J. Kiernan fingerprint_status_t
mac_veriexec_get_fingerprint_status(struct vnode * vp)1069fb47a376SStephen J. Kiernan mac_veriexec_get_fingerprint_status(struct vnode *vp)
1070fb47a376SStephen J. Kiernan {
1071fb47a376SStephen J. Kiernan 	fingerprint_status_t fps;
1072478368caSMateusz Guzik 	struct vnode *ldvp;
1073fb47a376SStephen J. Kiernan 
1074fb47a376SStephen J. Kiernan 	fps = SLOT(vp->v_label);
1075fb47a376SStephen J. Kiernan 	switch (fps) {
1076fb47a376SStephen J. Kiernan 	case FINGERPRINT_VALID:
1077fb47a376SStephen J. Kiernan 	case FINGERPRINT_INDIRECT:
1078fb47a376SStephen J. Kiernan 	case FINGERPRINT_FILE:
1079fb47a376SStephen J. Kiernan 		break;
1080fb47a376SStephen J. Kiernan 	default:
1081fb47a376SStephen J. Kiernan 		/* we may need to recurse */
1082478368caSMateusz Guzik 		ldvp = mac_veriexec_bottom_vnode(vp);
1083478368caSMateusz Guzik 		if (ldvp != NULL)
1084fb47a376SStephen J. Kiernan 			return mac_veriexec_get_fingerprint_status(ldvp);
1085fb47a376SStephen J. Kiernan 		break;
1086fb47a376SStephen J. Kiernan 	}
1087fb47a376SStephen J. Kiernan 	return fps;
1088fb47a376SStephen J. Kiernan }
1089fb47a376SStephen J. Kiernan 
1090fb47a376SStephen J. Kiernan /**
1091fb47a376SStephen J. Kiernan  * @brief Get the current verified execution subsystem state.
1092fb47a376SStephen J. Kiernan  *
1093fb47a376SStephen J. Kiernan  * @return Current set of verified execution subsystem state flags.
1094fb47a376SStephen J. Kiernan  */
1095fb47a376SStephen J. Kiernan int
mac_veriexec_get_state(void)1096fb47a376SStephen J. Kiernan mac_veriexec_get_state(void)
1097fb47a376SStephen J. Kiernan {
1098fb47a376SStephen J. Kiernan 
1099fb47a376SStephen J. Kiernan 	return (mac_veriexec_state);
1100fb47a376SStephen J. Kiernan }
1101fb47a376SStephen J. Kiernan 
1102fb47a376SStephen J. Kiernan /**
1103fb47a376SStephen J. Kiernan  * @brief Determine if the verified execution subsystem state has specific
1104fb47a376SStephen J. Kiernan  *     flags set.
1105fb47a376SStephen J. Kiernan  *
1106fb47a376SStephen J. Kiernan  * @param state		mask of flags to check
1107fb47a376SStephen J. Kiernan  *
1108fb47a376SStephen J. Kiernan  * @return State flags set within the masked bits
1109fb47a376SStephen J. Kiernan  */
1110fb47a376SStephen J. Kiernan int
mac_veriexec_in_state(int state)1111fb47a376SStephen J. Kiernan mac_veriexec_in_state(int state)
1112fb47a376SStephen J. Kiernan {
1113fb47a376SStephen J. Kiernan 
1114fb47a376SStephen J. Kiernan 	return (mac_veriexec_state & state);
1115fb47a376SStephen J. Kiernan }
1116fb47a376SStephen J. Kiernan 
1117fb47a376SStephen J. Kiernan /**
1118fb47a376SStephen J. Kiernan  * @brief Set the fingerprint status for a vnode
1119fb47a376SStephen J. Kiernan  *
1120fb47a376SStephen J. Kiernan  * Fingerprint status is stored in the MAC per-policy slot assigned to
1121fb47a376SStephen J. Kiernan  * mac_veriexec.
1122fb47a376SStephen J. Kiernan  *
1123fb47a376SStephen J. Kiernan  * @param vp		vnode to store the fingerprint status on
1124fb47a376SStephen J. Kiernan  * @param fp_status	fingerprint status to store
1125fb47a376SStephen J. Kiernan  */
1126fb47a376SStephen J. Kiernan void
mac_veriexec_set_fingerprint_status(struct vnode * vp,fingerprint_status_t fp_status)1127fb47a376SStephen J. Kiernan mac_veriexec_set_fingerprint_status(struct vnode *vp,
1128fb47a376SStephen J. Kiernan     fingerprint_status_t fp_status)
1129fb47a376SStephen J. Kiernan {
1130fb47a376SStephen J. Kiernan 	struct vnode *ldvp;
1131fb47a376SStephen J. Kiernan 
1132478368caSMateusz Guzik 	/* recurse until we find the real storage */
1133478368caSMateusz Guzik 	ldvp = mac_veriexec_bottom_vnode(vp);
1134478368caSMateusz Guzik 	if (ldvp != NULL) {
1135fb47a376SStephen J. Kiernan 		mac_veriexec_set_fingerprint_status(ldvp, fp_status);
1136fb47a376SStephen J. Kiernan 		return;
1137fb47a376SStephen J. Kiernan 	}
1138fb47a376SStephen J. Kiernan 	SLOT_SET(vp->v_label, fp_status);
1139fb47a376SStephen J. Kiernan }
1140fb47a376SStephen J. Kiernan 
1141fb47a376SStephen J. Kiernan /**
1142fb47a376SStephen J. Kiernan  * @brief Set verified execution subsystem state flags
1143fb47a376SStephen J. Kiernan  *
1144fb47a376SStephen J. Kiernan  * @note Flags can only be added to the current state, not removed.
1145fb47a376SStephen J. Kiernan  *
1146fb47a376SStephen J. Kiernan  * @param state		state flags to add to the current state
1147fb47a376SStephen J. Kiernan  */
1148fb47a376SStephen J. Kiernan void
mac_veriexec_set_state(int state)1149fb47a376SStephen J. Kiernan mac_veriexec_set_state(int state)
1150fb47a376SStephen J. Kiernan {
1151fb47a376SStephen J. Kiernan 
1152fb47a376SStephen J. Kiernan 	mac_veriexec_state |= state;
1153fb47a376SStephen J. Kiernan }
1154fb47a376SStephen J. Kiernan 
1155fb47a376SStephen J. Kiernan /**
1156fb47a376SStephen J. Kiernan  * @brief Determine if the process is trusted
1157fb47a376SStephen J. Kiernan  *
1158fb47a376SStephen J. Kiernan  * @param cred		credentials to use
1159fb47a376SStephen J. Kiernan  * @param p		the process in question
1160fb47a376SStephen J. Kiernan  *
1161fb47a376SStephen J. Kiernan  * @return 1 if the process is trusted, otherwise 0.
1162fb47a376SStephen J. Kiernan  */
1163fb47a376SStephen J. Kiernan int
mac_veriexec_proc_is_trusted(struct ucred * cred,struct proc * p)1164fb47a376SStephen J. Kiernan mac_veriexec_proc_is_trusted(struct ucred *cred, struct proc *p)
1165fb47a376SStephen J. Kiernan {
11663da3012aSStephen J. Kiernan 	int already_locked, error, flags;
11673da3012aSStephen J. Kiernan 
11683da3012aSStephen J. Kiernan 	/* Make sure we lock the process if we do not already have the lock */
11693da3012aSStephen J. Kiernan 	already_locked = PROC_LOCKED(p);
11703da3012aSStephen J. Kiernan 	if (!already_locked)
11713da3012aSStephen J. Kiernan 		PROC_LOCK(p);
1172fb47a376SStephen J. Kiernan 
1173fb47a376SStephen J. Kiernan 	error = mac_veriexec_metadata_get_executable_flags(cred, p, &flags, 0);
1174fb47a376SStephen J. Kiernan 
11753da3012aSStephen J. Kiernan 	/* Unlock the process if we locked it previously */
11763da3012aSStephen J. Kiernan 	if (!already_locked)
11773da3012aSStephen J. Kiernan 		PROC_UNLOCK(p);
11783da3012aSStephen J. Kiernan 
1179fb47a376SStephen J. Kiernan 	/* Any errors, deny access */
1180fb47a376SStephen J. Kiernan 	if (error != 0)
1181fb47a376SStephen J. Kiernan 		return (0);
1182fb47a376SStephen J. Kiernan 
1183fb47a376SStephen J. Kiernan 	/* Check that the trusted flag is set */
1184fb47a376SStephen J. Kiernan 	return ((flags & VERIEXEC_TRUSTED) == VERIEXEC_TRUSTED);
1185fb47a376SStephen J. Kiernan }
1186