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