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