xref: /freebsd/sys/dev/veriexec/verified_exec.c (revision 780fb4a2)
1 /*
2  * $FreeBSD$
3  *
4  * Copyright (c) 2011-2013, 2015, 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 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/buf.h>
33 #include <sys/conf.h>
34 #include <sys/errno.h>
35 #include <sys/fcntl.h>
36 #include <sys/file.h>
37 #include <sys/filedesc.h>
38 #include <sys/ioccom.h>
39 #include <sys/jail.h>
40 #include <sys/kernel.h>
41 #include <sys/lock.h>
42 #include <sys/malloc.h>
43 #include <sys/mdioctl.h>
44 #include <sys/mount.h>
45 #include <sys/mutex.h>
46 #include <sys/namei.h>
47 #include <sys/proc.h>
48 #include <sys/queue.h>
49 #include <sys/vnode.h>
50 
51 #include <security/mac_veriexec/mac_veriexec.h>
52 #include <security/mac_veriexec/mac_veriexec_internal.h>
53 
54 #include "veriexec_ioctl.h"
55 
56 /*
57  * We need a mutex while updating lists etc.
58  */
59 extern struct mtx ve_mutex;
60 
61 /*
62  * Handle the ioctl for the device
63  */
64 static int
65 verifiedexecioctl(struct cdev *dev __unused, u_long cmd, caddr_t data,
66     int flags, struct thread *td)
67 {
68 	struct nameidata nid;
69 	struct vattr vattr;
70 	struct verified_exec_params *params;
71 	int error = 0;
72 
73 	params = (struct verified_exec_params *)data;
74 	switch (cmd) {
75 	case VERIEXEC_ACTIVE:
76 		mtx_lock(&ve_mutex);
77 		if (mac_veriexec_in_state(VERIEXEC_STATE_LOADED))
78 			mac_veriexec_set_state(VERIEXEC_STATE_ACTIVE);
79 		else
80 			error = EINVAL;
81 		mtx_unlock(&ve_mutex);
82 		break;
83 	case VERIEXEC_DEBUG_ON:
84 		mtx_lock(&ve_mutex);
85 		{
86 			int *ip = (int *)data;
87 
88 			mac_veriexec_debug++;
89 			if (ip) {
90 				if (*ip > 0)
91 					mac_veriexec_debug = *ip;
92 				*ip = mac_veriexec_debug;
93 			}
94 		}
95 		mtx_unlock(&ve_mutex);
96 		break;
97 	case VERIEXEC_DEBUG_OFF:
98 		mac_veriexec_debug = 0;
99 		break;
100 	case VERIEXEC_ENFORCE:
101 		mtx_lock(&ve_mutex);
102 		if (mac_veriexec_in_state(VERIEXEC_STATE_LOADED))
103 			mac_veriexec_set_state(VERIEXEC_STATE_ACTIVE |
104 			    VERIEXEC_STATE_ENFORCE);
105 		else
106 			error = EINVAL;
107 		mtx_unlock(&ve_mutex);
108 		break;
109 	case VERIEXEC_GETSTATE:
110 		{
111 			int *ip = (int *)data;
112 
113 			if (ip)
114 				*ip = mac_veriexec_get_state();
115 			else
116 			    error = EINVAL;
117 		}
118 		break;
119 	case VERIEXEC_LOCK:
120 		mtx_lock(&ve_mutex);
121 		mac_veriexec_set_state(VERIEXEC_STATE_LOCKED);
122 		mtx_unlock(&ve_mutex);
123 		break;
124 	case VERIEXEC_LOAD:
125 	    	if (prison0.pr_securelevel > 0)
126 			return (EPERM);	/* no updates when secure */
127 
128 		/* FALLTHROUGH */
129 	case VERIEXEC_SIGNED_LOAD:
130 		/*
131 		 * If we use a loader that will only use a
132 		 * digitally signed hash list - which it verifies.
133 		 * We can load fingerprints provided veriexec is not locked.
134 		 */
135 	    	if (prison0.pr_securelevel > 0 &&
136 		    !mac_veriexec_in_state(VERIEXEC_STATE_LOADED)) {
137 			/*
138 			 * If securelevel has been raised and we
139 			 * do not have any fingerprints loaded,
140 			 * it would dangerous to do so now.
141 			 */
142 			return (EPERM);
143 		}
144 		if (mac_veriexec_in_state(VERIEXEC_STATE_LOCKED))
145 			error = EPERM;
146 		else {
147 			int flags = FREAD;
148 			int override = (cmd == VERIEXEC_SIGNED_LOAD);
149 
150 			/*
151 			 * Get the attributes for the file name passed
152 			 * stash the file's device id and inode number
153 			 * along with it's fingerprint in a list for
154 			 * exec to use later.
155 			 */
156 			/*
157 			 * FreeBSD seems to copy the args to kernel space
158 			 */
159                         NDINIT(&nid, LOOKUP, FOLLOW, UIO_SYSSPACE,
160                                params->file, td);
161 			if ((error = vn_open(&nid, &flags, 0, NULL)) != 0)
162 				return (error);
163 
164 			error = VOP_GETATTR(nid.ni_vp, &vattr, td->td_ucred);
165 			if (error != 0) {
166 				mac_veriexec_set_fingerprint_status(nid.ni_vp,
167 				    FINGERPRINT_INVALID);
168 				VOP_UNLOCK(nid.ni_vp, 0);
169 				(void) vn_close(nid.ni_vp, FREAD, td->td_ucred,
170 				    td);
171 				return (error);
172 			}
173 			if (override) {
174 				/*
175 				 * If the file is on a "verified" filesystem
176 				 * someone may be playing games.
177 				 */
178 				if ((nid.ni_vp->v_mount->mnt_flag &
179 				    MNT_VERIFIED) != 0)
180 					override = 0;
181 			}
182 
183 			/*
184 			 * invalidate the node fingerprint status
185 			 * which will have been set in the vn_open
186 			 * and would always be FINGERPRINT_NOTFOUND
187 			 */
188 			mac_veriexec_set_fingerprint_status(nid.ni_vp,
189 			    FINGERPRINT_INVALID);
190 			VOP_UNLOCK(nid.ni_vp, 0);
191 			(void) vn_close(nid.ni_vp, FREAD, td->td_ucred, td);
192 
193 			mtx_lock(&ve_mutex);
194 			error = mac_veriexec_metadata_add_file(
195 			    ((params->flags & VERIEXEC_FILE) != 0),
196 			    vattr.va_fsid, vattr.va_fileid, vattr.va_gen,
197 			    params->fingerprint, params->flags,
198 			    params->fp_type, override);
199 
200 			mac_veriexec_set_state(VERIEXEC_STATE_LOADED);
201 			mtx_unlock(&ve_mutex);
202 		}
203 		break;
204 	default:
205 		error = ENODEV;
206 	}
207 	return (error);
208 }
209 
210 struct cdevsw veriexec_cdevsw = {
211 	.d_version =	D_VERSION,
212 	.d_ioctl =	verifiedexecioctl,
213 	.d_name =	"veriexec",
214 };
215 
216 static void
217 veriexec_drvinit(void *unused __unused)
218 {
219 
220 	make_dev(&veriexec_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "veriexec");
221 }
222 
223 SYSINIT(veriexec, SI_SUB_PSEUDO, SI_ORDER_ANY, veriexec_drvinit, NULL);
224 MODULE_DEPEND(veriexec, mac_veriexec, 1, 1, 1);
225