]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/security/mac_veriexec/mac_veriexec.c
Merge llvm-project release/16.x llvmorg-16.0.4-0-gae42196bc493
[FreeBSD/FreeBSD.git] / sys / security / mac_veriexec / mac_veriexec.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2011-2023 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 #ifdef COMPAT_FREEBSD32
54 #include <sys/sysent.h>
55 #include <sys/stdint.h>
56 #include <sys/abi_compat.h>
57 #endif
58 #include <fs/nullfs/null.h>
59 #include <security/mac/mac_framework.h>
60 #include <security/mac/mac_policy.h>
61
62 #include "mac_veriexec.h"
63 #include "mac_veriexec_internal.h"
64
65 #define SLOT(l) \
66         mac_label_get((l), mac_veriexec_slot)
67 #define SLOT_SET(l, v) \
68         mac_label_set((l), mac_veriexec_slot, (v))
69
70 #ifdef MAC_VERIEXEC_DEBUG
71 #define MAC_VERIEXEC_DBG(_lvl, _fmt, ...)                               \
72         do {                                                            \
73                 VERIEXEC_DEBUG((_lvl), (MAC_VERIEXEC_FULLNAME ": " _fmt \
74                      "\n", ##__VA_ARGS__));                             \
75         } while(0)
76 #else
77 #define MAC_VERIEXEC_DBG(_lvl, _fmt, ...)
78 #endif
79
80 static int sysctl_mac_veriexec_state(SYSCTL_HANDLER_ARGS);
81 static int sysctl_mac_veriexec_db(SYSCTL_HANDLER_ARGS);
82 static struct mac_policy_ops mac_veriexec_ops;
83
84 SYSCTL_DECL(_security_mac);
85
86 SYSCTL_NODE(_security_mac, OID_AUTO, veriexec, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
87     "MAC/veriexec policy controls");
88
89 int     mac_veriexec_debug;
90 SYSCTL_INT(_security_mac_veriexec, OID_AUTO, debug, CTLFLAG_RW,
91     &mac_veriexec_debug, 0, "Debug level");
92
93 static int      mac_veriexec_state;
94 SYSCTL_PROC(_security_mac_veriexec, OID_AUTO, state,
95     CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_NEEDGIANT,
96     0, 0, sysctl_mac_veriexec_state, "A",
97     "Verified execution subsystem state");
98
99 SYSCTL_PROC(_security_mac_veriexec, OID_AUTO, db,
100     CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_SKIP | CTLFLAG_NEEDGIANT,
101     0, 0, sysctl_mac_veriexec_db,
102     "A", "Verified execution fingerprint database");
103
104
105 static int mac_veriexec_slot;
106
107 static int mac_veriexec_block_unlink;
108
109 MALLOC_DEFINE(M_VERIEXEC, "veriexec", "Verified execution data");
110
111 /**
112  * @internal
113  * @brief Handler for security.mac.veriexec.db sysctl
114  *
115  * Display a human-readable form of the current fingerprint database.
116  */
117 static int
118 sysctl_mac_veriexec_db(SYSCTL_HANDLER_ARGS)
119 {
120         struct sbuf sb;
121         int error;
122
123         error = sysctl_wire_old_buffer(req, 0);
124         if (error != 0)
125                 return (error);
126
127         sbuf_new_for_sysctl(&sb, NULL, 1024, req);
128         mac_veriexec_metadata_print_db(&sb);
129         error = sbuf_finish(&sb);
130         sbuf_delete(&sb);
131
132         return (error);
133 }
134
135 /**
136  * @internal
137  * @brief Generate human-readable output about the current verified execution
138  *        state.
139  *
140  * @param sbp           sbuf to write output to
141  */
142 static void
143 mac_veriexec_print_state(struct sbuf *sbp)
144 {
145
146         if (mac_veriexec_state & VERIEXEC_STATE_INACTIVE)
147                 sbuf_printf(sbp, "inactive ");
148         if (mac_veriexec_state & VERIEXEC_STATE_LOADED)
149                 sbuf_printf(sbp, "loaded ");
150         if (mac_veriexec_state & VERIEXEC_STATE_ACTIVE)
151                 sbuf_printf(sbp, "active ");
152         if (mac_veriexec_state & VERIEXEC_STATE_ENFORCE)
153                 sbuf_printf(sbp, "enforce ");
154         if (mac_veriexec_state & VERIEXEC_STATE_LOCKED)
155                 sbuf_printf(sbp, "locked ");
156         if (mac_veriexec_state != 0)
157                 sbuf_trim(sbp);
158 }
159
160 /**
161  * @internal
162  * @brief Handler for security.mac.veriexec.state sysctl
163  *
164  * Display a human-readable form of the current verified execution subsystem
165  * state.
166  */
167 static int
168 sysctl_mac_veriexec_state(SYSCTL_HANDLER_ARGS)
169 {
170         struct sbuf sb;
171         int error;
172
173         sbuf_new(&sb, NULL, 128, SBUF_AUTOEXTEND);
174         mac_veriexec_print_state(&sb);
175         sbuf_finish(&sb);
176
177         error = SYSCTL_OUT(req, sbuf_data(&sb), sbuf_len(&sb));
178         sbuf_delete(&sb);
179         return (error);
180 }
181
182 /**
183  * @internal
184  * @brief Event handler called when a virtual file system is mounted.
185  *
186  * We need to record the file system identifier in the MAC per-policy slot
187  * assigned to veriexec, so we have a key to use in order to reference the
188  * mount point in the meta-data store.
189  *
190  * @param arg           unused argument
191  * @param mp            mount point that is being mounted
192  * @param fsrootvp      vnode of the file system root
193  * @param td            calling thread
194  */
195 static void
196 mac_veriexec_vfs_mounted(void *arg __unused, struct mount *mp,
197     struct vnode *fsrootvp, struct thread *td)
198 {
199         struct vattr va;
200         int error;
201
202         error = VOP_GETATTR(fsrootvp, &va, td->td_ucred);
203         if (error)
204                 return;
205
206         SLOT_SET(mp->mnt_label, va.va_fsid);
207         MAC_VERIEXEC_DBG(3, "set fsid to %ju for mount %p",
208             (uintmax_t)va.va_fsid, mp);
209 }
210
211 /**
212  * @internal
213  * @brief Event handler called when a virtual file system is unmounted.
214  *
215  * If we recorded a file system identifier in the MAC per-policy slot assigned
216  * to veriexec, then we need to tell the meta-data store to clean up.
217  *
218  * @param arg           unused argument
219  * @param mp            mount point that is being unmounted
220  * @param td            calling thread
221  */
222 static void
223 mac_veriexec_vfs_unmounted(void *arg __unused, struct mount *mp,
224     struct thread *td)
225 {
226         dev_t fsid;
227
228         fsid = SLOT(mp->mnt_label);
229         if (fsid) {
230                 MAC_VERIEXEC_DBG(3, "fsid %ju, cleaning up mount",
231                     (uintmax_t)fsid);
232                 mac_veriexec_metadata_unmounted(fsid, td);
233         }
234 }
235
236 /**
237  * @internal
238  * @brief The mount point is being initialized, set the value in the MAC
239  *     per-policy slot for veriexec to zero.
240  *
241  * @note A value of zero in this slot indicates no file system identifier
242  *     is assigned.
243  *
244  * @param label the label that is being initialized
245  */
246 static void
247 mac_veriexec_mount_init_label(struct label *label)
248 {
249
250         SLOT_SET(label, 0);
251 }
252
253 /**
254  * @internal
255  * @brief The mount-point is being destroyed, reset the value in the MAC
256  *     per-policy slot for veriexec back to zero.
257  *
258  * @note A value of zero in this slot indicates no file system identifier
259  *     is assigned.
260  *
261  * @param label the label that is being destroyed
262  */
263 static void
264 mac_veriexec_mount_destroy_label(struct label *label)
265 {
266
267         SLOT_SET(label, 0);
268 }
269
270 /**
271  * @internal
272  * @brief The vnode label is being initialized, set the value in the MAC
273  *     per-policy slot for veriexec to @c FINGERPRINT_INVALID
274  *
275  * @note @c FINGERPRINT_INVALID indicates the fingerprint is invalid.
276  *
277  * @param label         the label that is being initialized
278  */
279 static void
280 mac_veriexec_vnode_init_label(struct label *label)
281 {
282
283         SLOT_SET(label, FINGERPRINT_INVALID);
284 }
285
286 /**
287  * @internal
288  * @brief The vnode label is being destroyed, reset the value in the MAC
289  *        per-policy slot for veriexec back to @c FINGERPRINT_INVALID
290  *
291  * @note @c FINGERPRINT_INVALID indicates the fingerprint is invalid.
292  *
293  * @param label         the label that is being destroyed
294  */
295 static void
296 mac_veriexec_vnode_destroy_label(struct label *label)
297 {
298
299         SLOT_SET(label, FINGERPRINT_INVALID);
300 }
301
302 /**
303  * @internal
304  * @brief Copy the value in the MAC per-policy slot assigned to veriexec from
305  *        the @p src label to the @p dest label
306  */
307 static void
308 mac_veriexec_copy_label(struct label *src, struct label *dest)
309 {
310
311         SLOT_SET(dest, SLOT(src));
312 }
313
314 /**
315  * @internal
316  * @brief Check if the requested process can be debugged
317  *
318  * @param cred          credentials to use
319  * @param p             process to debug
320  *
321  * @return 0 if debugging is allowed, otherwise an error code.
322  */
323 static int
324 mac_veriexec_proc_check_debug(struct ucred *cred, struct proc *p)
325 {
326         int error, flags;
327
328         /* If we are not enforcing veriexec, nothing for us to check */
329         if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0)
330                 return (0);
331
332         error = mac_veriexec_metadata_get_executable_flags(cred, p, &flags, 0);
333         if (error != 0)
334                 return (0);
335
336         error = (flags & (VERIEXEC_NOTRACE|VERIEXEC_TRUSTED)) ? EACCES : 0;
337         MAC_VERIEXEC_DBG(4, "%s flags=%#x error=%d", __func__, flags, error);
338
339         return (error);
340 }
341
342 /**
343  * @internal
344  * @brief A KLD load has been requested and needs to be validated.
345  *
346  * @param cred          credentials to use
347  * @param vp            vnode of the KLD that has been requested
348  * @param vlabel        vnode label assigned to the vnode
349  *
350  * @return 0 if the KLD load is allowed, otherwise an error code.
351  */
352 static int
353 mac_veriexec_kld_check_load(struct ucred *cred, struct vnode *vp,
354     struct label *vlabel)
355 {
356         struct vattr va;
357         struct thread *td = curthread;
358         fingerprint_status_t status;
359         int error;
360
361         /*
362          * If we are not actively enforcing, allow it
363          */
364         if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0)
365                 return (0);
366
367         /* Get vnode attributes */
368         error = VOP_GETATTR(vp, &va, cred);
369         if (error)
370                 return (error);
371
372         /*
373          * Fetch the fingerprint status for the vnode
374          * (starting with files first)
375          */
376         error = mac_veriexec_metadata_fetch_fingerprint_status(vp, &va, td,
377             VERIEXEC_FILES_FIRST);
378         if (error && error != EAUTH)
379                 return (error);
380
381         /*
382          * By now we should have status...
383          */
384         status = mac_veriexec_get_fingerprint_status(vp);
385         switch (status) {
386         case FINGERPRINT_FILE:
387         case FINGERPRINT_VALID:
388         case FINGERPRINT_INDIRECT:
389                 if (error)
390                         return (error);
391                 break;
392         default:
393                 /*
394                  * kldload should fail unless there is a valid fingerprint
395                  * registered.
396                  */
397                 MAC_VERIEXEC_DBG(2, "fingerprint status is %d for dev %ju, "
398                     "file %ju.%ju\n", status, (uintmax_t)va.va_fsid,
399                     (uintmax_t)va.va_fileid, (uintmax_t)va.va_gen);
400                 return (EAUTH);
401         }
402
403         /* Everything is good, allow the KLD to be loaded */
404         return (0);
405 }
406
407 /**
408  * @internal
409  * @brief Check privileges that veriexec needs to be concerned about.
410  *
411  * The following privileges are checked by this function:
412  *  - PRIV_KMEM_WRITE\n
413  *    Check if writes to /dev/mem and /dev/kmem are allowed\n
414  *    (Only trusted processes are allowed)
415  *  - PRIV_VERIEXEC_CONTROL\n
416  *    Check if manipulating veriexec is allowed\n
417  *    (only trusted processes are allowed)
418  *
419  * @param cred          credentials to use
420  * @param priv          privilege to check
421  *
422  * @return 0 if the privilege is allowed, error code otherwise.
423  */
424 static int
425 mac_veriexec_priv_check(struct ucred *cred, int priv)
426 {
427         int error;
428
429         /* If we are not enforcing veriexec, nothing for us to check */
430         if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0)
431                 return (0);
432
433         error = 0;
434         switch (priv) {
435         case PRIV_KMEM_WRITE:
436         case PRIV_VERIEXEC_CONTROL:
437                 /*
438                  * Do not allow writing to memory or manipulating veriexec,
439                  * unless trusted
440                  */
441                 if (mac_veriexec_proc_is_trusted(cred, curproc) == 0 &&
442                     mac_priv_grant(cred, priv) != 0)
443                         error = EPERM;
444                 MAC_VERIEXEC_DBG(4, "%s priv=%d error=%d", __func__, priv,
445                     error);
446                 break;
447         default:
448                 break;
449         }
450         return (error);
451 }
452
453 /**
454  * @internal
455  * @brief Check if the requested sysctl should be allowed
456  *
457  * @param cred         credentials to use
458  * @param oidp         sysctl OID
459  * @param arg1         first sysctl argument
460  * @param arg2         second sysctl argument
461  * @param req          sysctl request information
462  *
463  * @return 0 if the sysctl should be allowed, otherwise an error code.
464  */
465 static int
466 mac_veriexec_sysctl_check(struct ucred *cred, struct sysctl_oid *oidp,
467     void *arg1, int arg2, struct sysctl_req *req)
468 {
469         struct sysctl_oid *oid;
470
471         /* If we are not enforcing veriexec, nothing for us to check */
472         if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0)
473                 return (0);
474
475         oid = oidp;
476         if (req->newptr && (oid->oid_kind & CTLFLAG_SECURE)) {
477                 return (EPERM);         /* XXX call mac_veriexec_priv_check? */
478         }
479         return 0;
480 }
481
482 /**
483  * @internal
484  * @brief A program is being executed and needs to be validated.
485  *
486  * @param cred          credentials to use
487  * @param vp            vnode of the program that is being executed
488  * @param label         vnode label assigned to the vnode
489  * @param imgp          parameters for the image to be executed
490  * @param execlabel     optional exec label
491  *
492  * @return 0 if the program should be allowed to execute, otherwise an error
493  *     code.
494  */
495 static int
496 mac_veriexec_vnode_check_exec(struct ucred *cred __unused,
497     struct vnode *vp __unused, struct label *label __unused,
498     struct image_params *imgp, struct label *execlabel __unused)
499 {
500         struct thread *td = curthread;
501         int error;
502
503         error = mac_veriexec_fingerprint_check_image(imgp, 0, td);
504         return (error);
505 }
506
507 /**
508  * @brief Check fingerprint for the specified vnode and validate it
509  *
510  * @param cred          credentials to use
511  * @param vp            vnode of the file
512  * @param accmode       access mode to check (read, write, append, create,
513  *                      verify, etc.)
514  *
515  * @return 0 if the file validated, otherwise an error code.
516  */
517 static int
518 mac_veriexec_check_vp(struct ucred *cred, struct vnode *vp, accmode_t accmode)
519 {
520         struct vattr va;
521         struct thread *td = curthread;
522         fingerprint_status_t status;
523         int error;
524
525         /* Get vnode attributes */
526         error = VOP_GETATTR(vp, &va, cred);
527         if (error)
528                 return (error);
529
530         /* Get the fingerprint status for the file */
531         error = mac_veriexec_metadata_fetch_fingerprint_status(vp, &va, td,
532             VERIEXEC_FILES_FIRST);
533         if (error && error != EAUTH)
534                 return (error);
535
536         /*
537          * By now we should have status...
538          */
539         status = mac_veriexec_get_fingerprint_status(vp);
540         if (accmode & VWRITE) {
541                 /*
542                  * If file has a fingerprint then deny the write request,
543                  * otherwise invalidate the status so we don't keep checking
544                  * for the file having a fingerprint.
545                  */
546                 switch (status) {
547                 case FINGERPRINT_FILE:
548                 case FINGERPRINT_VALID:
549                 case FINGERPRINT_INDIRECT:
550                         MAC_VERIEXEC_DBG(2,
551                             "attempted write to fingerprinted file for dev "
552                             "%ju, file %ju.%ju\n", (uintmax_t)va.va_fsid,
553                             (uintmax_t)va.va_fileid, (uintmax_t)va.va_gen);
554                         return (EPERM);
555                 default:
556                         break;
557                 }
558         }
559         if (accmode & VVERIFY) {
560                 switch (status) {
561                 case FINGERPRINT_FILE:
562                 case FINGERPRINT_VALID:
563                 case FINGERPRINT_INDIRECT:
564                         if (error)
565                                 return (error);
566                         break;
567                 default:
568                         /* Allow for overriding verification requirement */
569                         if (mac_priv_grant(cred, PRIV_VERIEXEC_NOVERIFY) == 0)
570                                 return (0);
571                         /*
572                          * Caller wants open to fail unless there is a valid
573                          * fingerprint registered.
574                          */
575                         MAC_VERIEXEC_DBG(2, "fingerprint status is %d for dev "
576                             "%ju, file %ju.%ju\n", status,
577                             (uintmax_t)va.va_fsid, (uintmax_t)va.va_fileid,
578                             (uintmax_t)va.va_gen);
579                         return (EAUTH);
580                 }
581         }
582         return (0);
583 }
584
585 /**
586  * @brief Opening a file has been requested and may need to be validated.
587  *
588  * @param cred          credentials to use
589  * @param vp            vnode of the file to open
590  * @param label         vnode label assigned to the vnode
591  * @param accmode       access mode to use for opening the file (read, write,
592  *                      append, create, verify, etc.)
593  *
594  * @return 0 if opening the file should be allowed, otherwise an error code.
595  */
596 static int
597 mac_veriexec_vnode_check_open(struct ucred *cred, struct vnode *vp,
598         struct label *label __unused, accmode_t accmode)
599 {
600         int error;
601
602         /*
603          * Look for the file on the fingerprint lists iff it has not been seen
604          * before.
605          */
606         if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0)
607                 return (0);
608
609         error = mac_veriexec_check_vp(cred, vp, accmode);
610         return (error);
611 }
612
613 /**
614  * @brief Unlink on a file has been requested and may need to be validated.
615  *
616  * @param cred          credentials to use
617  * @param dvp           parent directory for file vnode vp
618  * @param dlabel        vnode label assigned to the directory vnode
619  * @param vp            vnode of the file to unlink
620  * @param label         vnode label assigned to the vnode
621  * @param cnp           component name for vp
622  *
623  *
624  * @return 0 if opening the file should be allowed, otherwise an error code.
625  */
626 static int
627 mac_veriexec_vnode_check_unlink(struct ucred *cred, struct vnode *dvp __unused,
628     struct label *dvplabel __unused, struct vnode *vp,
629     struct label *label __unused, struct componentname *cnp __unused)
630 {
631         int error;
632
633         /*
634          * Look for the file on the fingerprint lists iff it has not been seen
635          * before.
636          */
637         if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0)
638                 return (0);
639
640         error = mac_veriexec_check_vp(cred, vp, VVERIFY);
641         if (error == 0) {
642                 /*
643                  * The target is verified, so disallow replacement.
644                  */
645                 MAC_VERIEXEC_DBG(2,
646     "(UNLINK) attempted to unlink a protected file (euid: %u)", cred->cr_uid);
647
648                 return (EAUTH);
649         }
650         return (0);
651 }
652
653 /**
654  * @brief Rename the file has been requested and may need to be validated.
655  *
656  * @param cred          credentials to use
657  * @param dvp           parent directory for file vnode vp
658  * @param dlabel        vnode label assigned to the directory vnode
659  * @param vp            vnode of the file to rename
660  * @param label         vnode label assigned to the vnode
661  * @param cnp           component name for vp
662  *
663  *
664  * @return 0 if opening the file should be allowed, otherwise an error code.
665  */
666 static int
667 mac_veriexec_vnode_check_rename_from(struct ucred *cred,
668     struct vnode *dvp __unused, struct label *dvplabel __unused,
669     struct vnode *vp, struct label *label __unused,
670     struct componentname *cnp __unused)
671 {
672         int error;
673
674         /*
675          * Look for the file on the fingerprint lists iff it has not been seen
676          * before.
677          */
678         if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0)
679                 return (0);
680
681         error = mac_veriexec_check_vp(cred, vp, VVERIFY);
682         if (error == 0) {
683                 /*
684                  * The target is verified, so disallow replacement.
685                  */
686                 MAC_VERIEXEC_DBG(2,
687     "(RENAME_FROM) attempted to rename a protected file (euid: %u)", cred->cr_uid);
688                 return (EAUTH);
689         }
690         return (0);
691 }
692
693
694 /**
695  * @brief Rename to file into the directory (overwrite the file name) has been
696  * requested and may need to be validated.
697  *
698  * @param cred          credentials to use
699  * @param dvp           parent directory for file vnode vp
700  * @param dlabel        vnode label assigned to the directory vnode
701  * @param vp            vnode of the overwritten file
702  * @param label         vnode label assigned to the vnode
703  * @param samedir       1 if the source and destination directories are the same
704  * @param cnp           component name for vp
705  *
706  *
707  * @return 0 if opening the file should be allowed, otherwise an error code.
708  */
709         static int
710 mac_veriexec_vnode_check_rename_to(struct ucred *cred, struct vnode *dvp __unused,
711     struct label *dvplabel __unused, struct vnode *vp,
712     struct label *label __unused, int samedir __unused,
713     struct componentname *cnp __unused)
714 {
715         int error;
716         /*
717          * If there is no existing file to overwrite, vp and label will be
718          * NULL.
719          */
720         if (vp == NULL)
721                 return (0);
722
723         /*
724          * Look for the file on the fingerprint lists iff it has not been seen
725          * before.
726          */
727         if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0)
728                 return (0);
729
730         error = mac_veriexec_check_vp(cred, vp, VVERIFY);
731         if (error == 0) {
732                 /*
733                  * The target is verified, so disallow replacement.
734                  */
735                 MAC_VERIEXEC_DBG(2,
736     "(RENAME_TO) attempted to overwrite a protected file (euid: %u)", cred->cr_uid);
737                 return (EAUTH);
738         }
739         return (0);
740 }
741
742
743 /**
744  * @brief Check mode changes on file to ensure they should be allowed.
745  *
746  * We cannot allow chmod of SUID or SGID on verified files.
747  *
748  * @param cred          credentials to use
749  * @param vp            vnode of the file to open
750  * @param label         vnode label assigned to the vnode
751  * @param mode          mode flags to set
752  *
753  * @return 0 if the mode change should be allowed, EAUTH otherwise.
754  */
755 static int
756 mac_veriexec_vnode_check_setmode(struct ucred *cred, struct vnode *vp,
757     struct label *label __unused, mode_t mode)
758 {
759         int error;
760
761         if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0)
762                 return (0);
763
764         /*
765          * Prohibit chmod of verified set-[gu]id file.
766          */
767         error = mac_veriexec_check_vp(cred, vp, VVERIFY);
768         if (error == EAUTH)             /* target not verified */
769                 return (0);
770         if (error == 0 && (mode & (S_ISUID|S_ISGID)) != 0)
771                 return (EAUTH);
772
773         return (0);
774 }
775
776 /**
777  * @internal
778  * @brief Initialize the mac_veriexec MAC policy
779  *
780  * @param mpc           MAC policy configuration
781  */
782 static void
783 mac_veriexec_init(struct mac_policy_conf *mpc __unused)
784 {
785         /* Initialize state */
786         mac_veriexec_state = VERIEXEC_STATE_INACTIVE;
787
788         /* Initialize meta-data storage */
789         mac_veriexec_metadata_init();
790
791         /* Initialize fingerprint ops */
792         mac_veriexec_fingerprint_init();
793
794         /* Register event handlers */
795         EVENTHANDLER_REGISTER(vfs_mounted, mac_veriexec_vfs_mounted, NULL,
796             EVENTHANDLER_PRI_FIRST);
797         EVENTHANDLER_REGISTER(vfs_unmounted, mac_veriexec_vfs_unmounted, NULL,
798             EVENTHANDLER_PRI_LAST);
799
800         /* Fetch tunable value in kernel env and define a corresponding read-only sysctl */
801         mac_veriexec_block_unlink = 0;
802         TUNABLE_INT_FETCH("security.mac.veriexec.block_unlink", &mac_veriexec_block_unlink);
803         SYSCTL_INT(_security_mac_veriexec, OID_AUTO, block_unlink,
804             CTLFLAG_RDTUN, &mac_veriexec_block_unlink, 0, "Veriexec unlink protection");
805
806         /* Check if unlink control is activated via tunable value */
807         if (!mac_veriexec_block_unlink)
808                 mac_veriexec_ops.mpo_vnode_check_unlink = NULL;
809 }
810
811 #ifdef COMPAT_FREEBSD32
812 struct mac_veriexec_syscall_params32  {
813         char fp_type[VERIEXEC_FPTYPELEN];
814         unsigned char fingerprint[MAXFINGERPRINTLEN];
815         char label[MAXLABELLEN];
816         uint32_t labellen;
817         unsigned char flags;
818 };
819
820 struct mac_veriexec_syscall_params_args32 {
821         union {
822                 pid_t pid;
823                 uint32_t filename;
824         } u;                              /* input only */
825         uint32_t params;                  /* result */
826 };
827 #endif
828
829 /**
830  * @internal
831  * @brief MAC policy-specific syscall for mac_veriexec
832  *
833  * The following syscalls are implemented:
834  *   - @c MAC_VERIEXEC_CHECK_SYSCALL
835  *        Check if the file referenced by a file descriptor has a fingerprint
836  *        registered in the meta-data store.
837  *
838  * @param td            calling thread
839  * @param call          system call number
840  * @param arg           arugments to the syscall
841  *
842  * @return 0 on success, otherwise an error code.
843  */
844 static int
845 mac_veriexec_syscall(struct thread *td, int call, void *arg)
846 {
847         struct image_params img;
848         struct nameidata nd;
849         cap_rights_t rights;
850         struct vattr va;
851         struct file *fp;
852         struct mac_veriexec_syscall_params_args pargs;
853         struct mac_veriexec_syscall_params result;
854 #ifdef COMPAT_FREEBSD32
855         struct mac_veriexec_syscall_params_args32 pargs32;
856         struct mac_veriexec_syscall_params32 result32;
857 #endif
858         struct mac_veriexec_file_info *ip;
859         struct proc *proc;
860         struct vnode *textvp;
861         int error, flags, proc_locked;
862
863         nd.ni_vp = NULL;
864         proc_locked = 0;
865         textvp = NULL;
866         switch (call) {
867         case MAC_VERIEXEC_GET_PARAMS_PID_SYSCALL:
868         case MAC_VERIEXEC_GET_PARAMS_PATH_SYSCALL:
869 #ifdef COMPAT_FREEBSD32
870                 if (SV_PROC_FLAG(td->td_proc, SV_ILP32)) {
871                         error = copyin(arg, &pargs32, sizeof(pargs32));
872                         if (error)
873                                 return error;
874                         bzero(&pargs, sizeof(pargs));
875                         switch (call) {
876                         case MAC_VERIEXEC_GET_PARAMS_PID_SYSCALL:
877                                 CP(pargs32, pargs, u.pid);
878                                 break;
879                         case MAC_VERIEXEC_GET_PARAMS_PATH_SYSCALL:
880                                 PTRIN_CP(pargs32, pargs, u.filename);
881                                 break;
882                         }
883                         PTRIN_CP(pargs32, pargs, params);
884                 } else
885 #endif
886                 error = copyin(arg, &pargs, sizeof(pargs));
887                 if (error)
888                         return error;
889                 break;
890         }
891
892         switch (call) {
893         case MAC_VERIEXEC_CHECK_FD_SYSCALL:
894                 /* Get the vnode associated with the file descriptor passed */
895                 error = getvnode(td, (uintptr_t) arg,
896                     cap_rights_init_one(&rights, CAP_READ), &fp);
897                 if (error)
898                         return (error);
899                 if (fp->f_type != DTYPE_VNODE) {
900                         MAC_VERIEXEC_DBG(3, "MAC_VERIEXEC_CHECK_SYSCALL: "
901                             "file is not vnode type (type=0x%x)",
902                             fp->f_type);
903                         error = EINVAL;
904                         goto cleanup_file;
905                 }
906
907                 /*
908                  * setup the bits of image_params that are used by
909                  * mac_veriexec_check_fingerprint().
910                  */
911                 bzero(&img, sizeof(img));
912                 img.proc = td->td_proc;
913                 img.vp = fp->f_vnode;
914                 img.attr = &va;
915
916                 /*
917                  * Get vnode attributes
918                  * (need to obtain a lock on the vnode first)
919                  */
920                 vn_lock(img.vp, LK_EXCLUSIVE | LK_RETRY);
921                 error = VOP_GETATTR(fp->f_vnode, &va,  td->td_ucred);
922                 if (error)
923                         goto check_done;
924
925                 MAC_VERIEXEC_DBG(2, "mac_veriexec_fingerprint_check_image: "
926                     "va_mode=%o, check_files=%d\n", va.va_mode,
927                     ((va.va_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0));
928                 error = mac_veriexec_fingerprint_check_image(&img,
929                     ((va.va_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0), td);
930 check_done:
931                 /* Release the lock we obtained earlier */
932                 VOP_UNLOCK(img.vp);
933 cleanup_file:
934                 fdrop(fp, td);
935                 break;
936         case MAC_VERIEXEC_CHECK_PATH_SYSCALL:
937                 /* Look up the path to get the vnode */
938                 NDINIT(&nd, LOOKUP,
939                     FOLLOW | LOCKLEAF | LOCKSHARED | AUDITVNODE1,
940                     UIO_USERSPACE, arg);
941                 flags = FREAD;
942                 error = vn_open(&nd, &flags, 0, NULL);
943                 if (error != 0)
944                         break;
945                 NDFREE_PNBUF(&nd);
946
947                 /* Check the fingerprint status of the vnode */
948                 error = mac_veriexec_check_vp(td->td_ucred, nd.ni_vp, VVERIFY);
949                 /* nd.ni_vp cleaned up below */
950                 break;
951         case MAC_VERIEXEC_GET_PARAMS_PID_SYSCALL:
952                 if (pargs.u.pid == 0 || pargs.u.pid == curproc->p_pid) {
953                         proc = curproc;
954                 } else {
955                         proc = pfind(pargs.u.pid);
956                         if (proc == NULL)
957                                 return (EINVAL);
958                         proc_locked = 1;
959                 }
960                 textvp = proc->p_textvp;
961                 /* FALLTHROUGH */
962         case MAC_VERIEXEC_GET_PARAMS_PATH_SYSCALL:
963                 if (textvp == NULL) {
964                         /* Look up the path to get the vnode */
965                         NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | AUDITVNODE1,
966                             UIO_USERSPACE, pargs.u.filename);
967                         flags = FREAD;
968                         error = vn_open(&nd, &flags, 0, NULL);
969                         if (error != 0)
970                                 break;
971
972                         NDFREE_PNBUF(&nd);
973                         textvp = nd.ni_vp;
974                 }
975                 error = VOP_GETATTR(textvp, &va, curproc->p_ucred);
976                 if (proc_locked)
977                         PROC_UNLOCK(proc);
978                 if (error != 0)
979                         break;
980
981                 error = mac_veriexec_metadata_get_file_info(va.va_fsid,
982                     va.va_fileid, va.va_gen, NULL, &ip, FALSE);
983                 if (error != 0)
984                         break;
985
986 #ifdef COMPAT_FREEBSD32
987                 if (SV_PROC_FLAG(td->td_proc, SV_ILP32)) {
988                         bzero(&result32, sizeof(result32));
989                         result32.flags = ip->flags;
990                         strlcpy(result32.fp_type, ip->ops->type, sizeof(result32.fp_type));
991                         result.labellen = ip->labellen;
992                         CP(result, result32, labellen);
993                         if (ip->labellen > 0)
994                                 strlcpy(result32.label, ip->label, sizeof(result32.label));
995                         result32.label[result.labellen] = '\0';
996                         memcpy(result32.fingerprint, ip->fingerprint,
997                             ip->ops->digest_len);
998
999                         error = copyout(&result32, pargs.params, sizeof(result32));
1000                         break;          /* yes */
1001                 }
1002 #endif
1003                 bzero(&result, sizeof(result));
1004                 result.flags = ip->flags;
1005                 strlcpy(result.fp_type, ip->ops->type, sizeof(result.fp_type));
1006                 result.labellen = ip->labellen;
1007                 if (ip->labellen > 0)
1008                         strlcpy(result.label, ip->label, sizeof(result.label));
1009                 result.label[result.labellen] = '\0';
1010                 memcpy(result.fingerprint, ip->fingerprint,
1011                     ip->ops->digest_len);
1012
1013                 error = copyout(&result, pargs.params, sizeof(result));
1014                 break;
1015         default:
1016                 error = EOPNOTSUPP;
1017         }
1018         if (nd.ni_vp != NULL) {
1019                 VOP_UNLOCK(nd.ni_vp);
1020                 vn_close(nd.ni_vp, FREAD, td->td_ucred, td);
1021         }
1022         return (error);
1023 }
1024
1025 static struct mac_policy_ops mac_veriexec_ops =
1026 {
1027         .mpo_init = mac_veriexec_init,
1028         .mpo_kld_check_load = mac_veriexec_kld_check_load,
1029         .mpo_mount_destroy_label = mac_veriexec_mount_destroy_label,
1030         .mpo_mount_init_label = mac_veriexec_mount_init_label,
1031         .mpo_priv_check = mac_veriexec_priv_check,
1032         .mpo_proc_check_debug = mac_veriexec_proc_check_debug,
1033         .mpo_syscall = mac_veriexec_syscall,
1034         .mpo_system_check_sysctl = mac_veriexec_sysctl_check,
1035         .mpo_vnode_check_exec = mac_veriexec_vnode_check_exec,
1036         .mpo_vnode_check_open = mac_veriexec_vnode_check_open,
1037         .mpo_vnode_check_unlink = mac_veriexec_vnode_check_unlink,
1038         .mpo_vnode_check_rename_to = mac_veriexec_vnode_check_rename_to,
1039         .mpo_vnode_check_rename_from = mac_veriexec_vnode_check_rename_from,
1040         .mpo_vnode_check_setmode = mac_veriexec_vnode_check_setmode,
1041         .mpo_vnode_copy_label = mac_veriexec_copy_label,
1042         .mpo_vnode_destroy_label = mac_veriexec_vnode_destroy_label,
1043         .mpo_vnode_init_label = mac_veriexec_vnode_init_label,
1044 };
1045
1046 MAC_POLICY_SET(&mac_veriexec_ops, mac_veriexec, MAC_VERIEXEC_FULLNAME,
1047     MPC_LOADTIME_FLAG_NOTLATE, &mac_veriexec_slot);
1048 MODULE_VERSION(mac_veriexec, MAC_VERIEXEC_VERSION);
1049
1050 static struct vnode *
1051 mac_veriexec_bottom_vnode(struct vnode *vp)
1052 {
1053         struct vnode *ldvp = NULL;
1054
1055         /*
1056          * XXX This code is bogus. nullfs is not the only stacking
1057          * filesystem. Less bogus code would add a VOP to reach bottom
1058          * vnode and would not make assumptions how to get there.
1059          */
1060         if (vp->v_mount != NULL &&
1061             strcmp(vp->v_mount->mnt_vfc->vfc_name, "nullfs") == 0)
1062                 ldvp = NULLVPTOLOWERVP(vp);
1063         return (ldvp);
1064 }
1065
1066 /**
1067  * @brief Get the fingerprint status set on a vnode.
1068  *
1069  * @param vp            vnode to obtain fingerprint status from
1070  *
1071  * @return Fingerprint status assigned to the vnode.
1072  */
1073 fingerprint_status_t
1074 mac_veriexec_get_fingerprint_status(struct vnode *vp)
1075 {
1076         fingerprint_status_t fps;
1077         struct vnode *ldvp;
1078
1079         fps = SLOT(vp->v_label);
1080         switch (fps) {
1081         case FINGERPRINT_VALID:
1082         case FINGERPRINT_INDIRECT:
1083         case FINGERPRINT_FILE:
1084                 break;
1085         default:
1086                 /* we may need to recurse */
1087                 ldvp = mac_veriexec_bottom_vnode(vp);
1088                 if (ldvp != NULL)
1089                         return mac_veriexec_get_fingerprint_status(ldvp);
1090                 break;
1091         }
1092         return fps;
1093 }
1094
1095 /**
1096  * @brief Get the current verified execution subsystem state.
1097  *
1098  * @return Current set of verified execution subsystem state flags.
1099  */
1100 int
1101 mac_veriexec_get_state(void)
1102 {
1103
1104         return (mac_veriexec_state);
1105 }
1106
1107 /**
1108  * @brief Determine if the verified execution subsystem state has specific
1109  *     flags set.
1110  *
1111  * @param state         mask of flags to check
1112  *
1113  * @return State flags set within the masked bits
1114  */
1115 int
1116 mac_veriexec_in_state(int state)
1117 {
1118
1119         return (mac_veriexec_state & state);
1120 }
1121
1122 /**
1123  * @brief Set the fingerprint status for a vnode
1124  *
1125  * Fingerprint status is stored in the MAC per-policy slot assigned to
1126  * mac_veriexec.
1127  *
1128  * @param vp            vnode to store the fingerprint status on
1129  * @param fp_status     fingerprint status to store
1130  */
1131 void
1132 mac_veriexec_set_fingerprint_status(struct vnode *vp,
1133     fingerprint_status_t fp_status)
1134 {
1135         struct vnode *ldvp;
1136
1137         /* recurse until we find the real storage */
1138         ldvp = mac_veriexec_bottom_vnode(vp);
1139         if (ldvp != NULL) {
1140                 mac_veriexec_set_fingerprint_status(ldvp, fp_status);
1141                 return;
1142         }
1143         SLOT_SET(vp->v_label, fp_status);
1144 }
1145
1146 /**
1147  * @brief Set verified execution subsystem state flags
1148  *
1149  * @note Flags can only be added to the current state, not removed.
1150  *
1151  * @param state         state flags to add to the current state
1152  */
1153 void
1154 mac_veriexec_set_state(int state)
1155 {
1156
1157         mac_veriexec_state |= state;
1158 }
1159
1160 /**
1161  * @brief Determine if the process is trusted
1162  *
1163  * @param cred          credentials to use
1164  * @param p             the process in question
1165  *
1166  * @return 1 if the process is trusted, otherwise 0.
1167  */
1168 int
1169 mac_veriexec_proc_is_trusted(struct ucred *cred, struct proc *p)
1170 {
1171         int already_locked, error, flags;
1172
1173         /* Make sure we lock the process if we do not already have the lock */
1174         already_locked = PROC_LOCKED(p);
1175         if (!already_locked)
1176                 PROC_LOCK(p);
1177
1178         error = mac_veriexec_metadata_get_executable_flags(cred, p, &flags, 0);
1179
1180         /* Unlock the process if we locked it previously */
1181         if (!already_locked)
1182                 PROC_UNLOCK(p);
1183
1184         /* Any errors, deny access */
1185         if (error != 0)
1186                 return (0);
1187
1188         /* Check that the trusted flag is set */
1189         return ((flags & VERIEXEC_TRUSTED) == VERIEXEC_TRUSTED);
1190 }