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