1 /*
2 * $FreeBSD$
3 *
4 * Copyright (c) 2011-2013, 2015, 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 #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/priv.h>
48 #include <sys/proc.h>
49 #include <sys/queue.h>
50 #include <sys/vnode.h>
51
52 #include <security/mac_veriexec/mac_veriexec.h>
53 #include <security/mac_veriexec/mac_veriexec_internal.h>
54
55 #include "veriexec_ioctl.h"
56
57 /*
58 * We need a mutex while updating lists etc.
59 */
60 extern struct mtx ve_mutex;
61
62 /*
63 * Handle the ioctl for the device
64 */
65 static int
66 verifiedexecioctl(struct cdev *dev __unused, u_long cmd, caddr_t data,
67 int flags, struct thread *td)
68 {
69 struct nameidata nid;
70 struct vattr vattr;
71 struct verified_exec_label_params *lparams;
72 struct verified_exec_params *params;
73 int error = 0;
74
75 /*
76 * These commands are considered safe requests for anyone who has
77 * permission to access to device node.
78 */
79 switch (cmd) {
80 case VERIEXEC_GETSTATE:
81 {
82 int *ip = (int *)data;
83
84 if (ip)
85 *ip = mac_veriexec_get_state();
86 else
87 error = EINVAL;
88
89 return (error);
90 }
91 break;
92 default:
93 break;
94 }
95
96 /*
97 * Anything beyond this point is considered dangerous, so we need to
98 * only allow processes that have kmem write privs to do them.
99 *
100 * MAC/veriexec will grant kmem write privs to "trusted" processes.
101 */
102 error = priv_check(td, PRIV_KMEM_WRITE);
103 if (error)
104 return (error);
105
106 lparams = (struct verified_exec_label_params *)data;
107 if (cmd == VERIEXEC_LABEL_LOAD)
108 params = &lparams->params;
109 else
110 params = (struct verified_exec_params *)data;
111
112 switch (cmd) {
113 case VERIEXEC_ACTIVE:
114 mtx_lock(&ve_mutex);
115 if (mac_veriexec_in_state(VERIEXEC_STATE_LOADED))
116 mac_veriexec_set_state(VERIEXEC_STATE_ACTIVE);
117 else
118 error = EINVAL;
119 mtx_unlock(&ve_mutex);
120 break;
121 case VERIEXEC_DEBUG_ON:
122 mtx_lock(&ve_mutex);
123 {
124 int *ip = (int *)data;
125
126 mac_veriexec_debug++;
127 if (ip) {
128 if (*ip > 0)
129 mac_veriexec_debug = *ip;
130 *ip = mac_veriexec_debug;
131 }
132 }
133 mtx_unlock(&ve_mutex);
134 break;
135 case VERIEXEC_DEBUG_OFF:
136 mac_veriexec_debug = 0;
137 break;
138 case VERIEXEC_ENFORCE:
139 mtx_lock(&ve_mutex);
140 if (mac_veriexec_in_state(VERIEXEC_STATE_LOADED))
141 mac_veriexec_set_state(VERIEXEC_STATE_ACTIVE |
142 VERIEXEC_STATE_ENFORCE);
143 else
144 error = EINVAL;
145 mtx_unlock(&ve_mutex);
146 break;
147 case VERIEXEC_GETVERSION:
148 {
149 int *ip = (int *)data;
150
151 if (ip)
152 *ip = MAC_VERIEXEC_VERSION;
153 else
154 error = EINVAL;
155 }
156 break;
157 case VERIEXEC_LOCK:
158 mtx_lock(&ve_mutex);
159 mac_veriexec_set_state(VERIEXEC_STATE_LOCKED);
160 mtx_unlock(&ve_mutex);
161 break;
162 case VERIEXEC_LOAD:
163 if (prison0.pr_securelevel > 0)
164 return (EPERM); /* no updates when secure */
165
166 /* FALLTHROUGH */
167 case VERIEXEC_LABEL_LOAD:
168 case VERIEXEC_SIGNED_LOAD:
169 /*
170 * If we use a loader that will only use a
171 * digitally signed hash list - which it verifies.
172 * We can load fingerprints provided veriexec is not locked.
173 */
174 if (prison0.pr_securelevel > 0 &&
175 !mac_veriexec_in_state(VERIEXEC_STATE_LOADED)) {
176 /*
177 * If securelevel has been raised and we
178 * do not have any fingerprints loaded,
179 * it would dangerous to do so now.
180 */
181 return (EPERM);
182 }
183 if (mac_veriexec_in_state(VERIEXEC_STATE_LOCKED))
184 error = EPERM;
185 else {
186 size_t labellen = 0;
187 int flags = FREAD;
188 int override = (cmd != VERIEXEC_LOAD);
189
190 /*
191 * Get the attributes for the file name passed
192 * stash the file's device id and inode number
193 * along with it's fingerprint in a list for
194 * exec to use later.
195 */
196 /*
197 * FreeBSD seems to copy the args to kernel space
198 */
199 NDINIT(&nid, LOOKUP, FOLLOW, UIO_SYSSPACE,
200 params->file, td);
201 if ((error = vn_open(&nid, &flags, 0, NULL)) != 0)
202 return (error);
203
204 error = VOP_GETATTR(nid.ni_vp, &vattr, td->td_ucred);
205 if (error != 0) {
206 mac_veriexec_set_fingerprint_status(nid.ni_vp,
207 FINGERPRINT_INVALID);
208 VOP_UNLOCK(nid.ni_vp);
209 (void) vn_close(nid.ni_vp, FREAD, td->td_ucred,
210 td);
211 return (error);
212 }
213 if (override) {
214 /*
215 * If the file is on a "verified" filesystem
216 * someone may be playing games.
217 */
218 if ((nid.ni_vp->v_mount->mnt_flag &
219 MNT_VERIFIED) != 0)
220 override = 0;
221 }
222
223 /*
224 * invalidate the node fingerprint status
225 * which will have been set in the vn_open
226 * and would always be FINGERPRINT_NOTFOUND
227 */
228 mac_veriexec_set_fingerprint_status(nid.ni_vp,
229 FINGERPRINT_INVALID);
230 VOP_UNLOCK(nid.ni_vp);
231 (void) vn_close(nid.ni_vp, FREAD, td->td_ucred, td);
232 if (params->flags & VERIEXEC_LABEL)
233 labellen = strnlen(lparams->label,
234 sizeof(lparams->label) - 1) + 1;
235
236 mtx_lock(&ve_mutex);
237 error = mac_veriexec_metadata_add_file(
238 ((params->flags & VERIEXEC_FILE) != 0),
239 vattr.va_fsid, vattr.va_fileid, vattr.va_gen,
240 params->fingerprint,
241 (params->flags & VERIEXEC_LABEL) ?
242 lparams->label : NULL, labellen,
243 params->flags, params->fp_type, override);
244
245 mac_veriexec_set_state(VERIEXEC_STATE_LOADED);
246 mtx_unlock(&ve_mutex);
247 }
248 break;
249 default:
250 error = ENODEV;
251 }
252 return (error);
253 }
254
255 struct cdevsw veriexec_cdevsw = {
256 .d_version = D_VERSION,
257 .d_ioctl = verifiedexecioctl,
258 .d_name = "veriexec",
259 };
260
261 static void
262 veriexec_drvinit(void *unused __unused)
263 {
264
265 make_dev(&veriexec_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "veriexec");
266 }
267
268 SYSINIT(veriexec, SI_SUB_PSEUDO, SI_ORDER_ANY, veriexec_drvinit, NULL);
269 MODULE_DEPEND(veriexec, mac_veriexec, 1, 1, 1);
Cache object: b377e78d01ffcc4e28bed2c27b7a54b5
|