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