Sat Jan 8 20:29:13 2011 UTC ()
fix sysctl again.


(christos)
diff -r1.123 -r1.124 src/sys/kern/kern_verifiedexec.c

cvs diff -r1.123 -r1.124 src/sys/kern/Attic/kern_verifiedexec.c (switch to unified diff)

--- src/sys/kern/Attic/kern_verifiedexec.c 2011/01/02 20:50:55 1.123
+++ src/sys/kern/Attic/kern_verifiedexec.c 2011/01/08 20:29:13 1.124
@@ -1,1166 +1,1166 @@ @@ -1,1166 +1,1166 @@
1/* $NetBSD: kern_verifiedexec.c,v 1.123 2011/01/02 20:50:55 christos Exp $ */ 1/* $NetBSD: kern_verifiedexec.c,v 1.124 2011/01/08 20:29:13 christos Exp $ */
2 2
3/*- 3/*-
4 * Copyright (c) 2005, 2006 Elad Efrat <elad@NetBSD.org> 4 * Copyright (c) 2005, 2006 Elad Efrat <elad@NetBSD.org>
5 * Copyright (c) 2005, 2006 Brett Lymn <blymn@NetBSD.org> 5 * Copyright (c) 2005, 2006 Brett Lymn <blymn@NetBSD.org>
6 * All rights reserved. 6 * All rights reserved.
7 * 7 *
8 * Redistribution and use in source and binary forms, with or without 8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions 9 * modification, are permitted provided that the following conditions
10 * are met: 10 * are met:
11 * 1. Redistributions of source code must retain the above copyright 11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer. 12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright 13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the 14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution. 15 * documentation and/or other materials provided with the distribution.
16 * 3. The name of the authors may not be used to endorse or promote products 16 * 3. The name of the authors may not be used to endorse or promote products
17 * derived from this software without specific prior written permission. 17 * derived from this software without specific prior written permission.
18 * 18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */ 29 */
30 30
31#include <sys/cdefs.h> 31#include <sys/cdefs.h>
32__KERNEL_RCSID(0, "$NetBSD: kern_verifiedexec.c,v 1.123 2011/01/02 20:50:55 christos Exp $"); 32__KERNEL_RCSID(0, "$NetBSD: kern_verifiedexec.c,v 1.124 2011/01/08 20:29:13 christos Exp $");
33 33
34#include "opt_veriexec.h" 34#include "opt_veriexec.h"
35 35
36#include <sys/param.h> 36#include <sys/param.h>
37#include <sys/mount.h> 37#include <sys/mount.h>
38#include <sys/kmem.h> 38#include <sys/kmem.h>
39#include <sys/vnode.h> 39#include <sys/vnode.h>
40#include <sys/namei.h> 40#include <sys/namei.h>
41#include <sys/exec.h> 41#include <sys/exec.h>
42#include <sys/once.h> 42#include <sys/once.h>
43#include <sys/proc.h> 43#include <sys/proc.h>
44#include <sys/rwlock.h> 44#include <sys/rwlock.h>
45#include <sys/syslog.h> 45#include <sys/syslog.h>
46#include <sys/sysctl.h> 46#include <sys/sysctl.h>
47#include <sys/inttypes.h> 47#include <sys/inttypes.h>
48#include <sys/verified_exec.h> 48#include <sys/verified_exec.h>
49#if defined(__FreeBSD__) 49#if defined(__FreeBSD__)
50# include <sys/systm.h> 50# include <sys/systm.h>
51# include <sys/imgact.h> 51# include <sys/imgact.h>
52# include <crypto/sha1.h> 52# include <crypto/sha1.h>
53# include <crypto/sha2/sha2.h> 53# include <crypto/sha2/sha2.h>
54# include <crypto/ripemd160/rmd160.h> 54# include <crypto/ripemd160/rmd160.h>
55#else 55#else
56# include <sys/sha1.h> 56# include <sys/sha1.h>
57# include <sys/sha2.h> 57# include <sys/sha2.h>
58# include <sys/rmd160.h> 58# include <sys/rmd160.h>
59#endif 59#endif
60#include <sys/md5.h> 60#include <sys/md5.h>
61#include <uvm/uvm_extern.h> 61#include <uvm/uvm_extern.h>
62#include <sys/fileassoc.h> 62#include <sys/fileassoc.h>
63#include <sys/kauth.h> 63#include <sys/kauth.h>
64#include <sys/conf.h> 64#include <sys/conf.h>
65#include <miscfs/specfs/specdev.h> 65#include <miscfs/specfs/specdev.h>
66#include <prop/proplib.h> 66#include <prop/proplib.h>
67#include <sys/fcntl.h> 67#include <sys/fcntl.h>
68 68
69/* Readable values for veriexec_file_report(). */ 69/* Readable values for veriexec_file_report(). */
70#define REPORT_ALWAYS 0x01 /* Always print */ 70#define REPORT_ALWAYS 0x01 /* Always print */
71#define REPORT_VERBOSE 0x02 /* Print when verbose >= 1 */ 71#define REPORT_VERBOSE 0x02 /* Print when verbose >= 1 */
72#define REPORT_DEBUG 0x04 /* Print when verbose >= 2 (debug) */ 72#define REPORT_DEBUG 0x04 /* Print when verbose >= 2 (debug) */
73#define REPORT_PANIC 0x08 /* Call panic() */ 73#define REPORT_PANIC 0x08 /* Call panic() */
74#define REPORT_ALARM 0x10 /* Alarm - also print pid/uid/.. */ 74#define REPORT_ALARM 0x10 /* Alarm - also print pid/uid/.. */
75#define REPORT_LOGMASK (REPORT_ALWAYS|REPORT_VERBOSE|REPORT_DEBUG) 75#define REPORT_LOGMASK (REPORT_ALWAYS|REPORT_VERBOSE|REPORT_DEBUG)
76 76
77/* state of locking for veriexec_file_verify */ 77/* state of locking for veriexec_file_verify */
78#define VERIEXEC_UNLOCKED 0x00 /* Nothing locked, callee does it */ 78#define VERIEXEC_UNLOCKED 0x00 /* Nothing locked, callee does it */
79#define VERIEXEC_LOCKED 0x01 /* Global op lock held */ 79#define VERIEXEC_LOCKED 0x01 /* Global op lock held */
80 80
81 81
82#define VERIEXEC_RW_UPGRADE(lock) while((rw_tryupgrade(lock)) == 0){}; 82#define VERIEXEC_RW_UPGRADE(lock) while((rw_tryupgrade(lock)) == 0){};
83 83
84struct veriexec_fpops { 84struct veriexec_fpops {
85 const char *type; 85 const char *type;
86 size_t hash_len; 86 size_t hash_len;
87 size_t context_size; 87 size_t context_size;
88 veriexec_fpop_init_t init; 88 veriexec_fpop_init_t init;
89 veriexec_fpop_update_t update; 89 veriexec_fpop_update_t update;
90 veriexec_fpop_final_t final; 90 veriexec_fpop_final_t final;
91 LIST_ENTRY(veriexec_fpops) entries; 91 LIST_ENTRY(veriexec_fpops) entries;
92}; 92};
93 93
94/* Veriexec per-file entry data. */ 94/* Veriexec per-file entry data. */
95struct veriexec_file_entry { 95struct veriexec_file_entry {
96 krwlock_t lock; /* r/w lock */ 96 krwlock_t lock; /* r/w lock */
97 u_char *filename; /* File name. */ 97 u_char *filename; /* File name. */
98 u_char type; /* Entry type. */ 98 u_char type; /* Entry type. */
99 u_char status; /* Evaluation status. */ 99 u_char status; /* Evaluation status. */
100 u_char page_fp_status; /* Per-page FP status. */ 100 u_char page_fp_status; /* Per-page FP status. */
101 u_char *fp; /* Fingerprint. */ 101 u_char *fp; /* Fingerprint. */
102 void *page_fp; /* Per-page fingerprints */ 102 void *page_fp; /* Per-page fingerprints */
103 size_t npages; /* Number of pages. */ 103 size_t npages; /* Number of pages. */
104 size_t last_page_size; /* To support < PAGE_SIZE */ 104 size_t last_page_size; /* To support < PAGE_SIZE */
105 struct veriexec_fpops *ops; /* Fingerprint ops vector*/ 105 struct veriexec_fpops *ops; /* Fingerprint ops vector*/
106 size_t filename_len; /* Length of filename. */ 106 size_t filename_len; /* Length of filename. */
107}; 107};
108 108
109/* Veriexec per-table data. */ 109/* Veriexec per-table data. */
110struct veriexec_table_entry { 110struct veriexec_table_entry {
111 uint64_t vte_count; /* Number of Veriexec entries. */ 111 uint64_t vte_count; /* Number of Veriexec entries. */
112 const struct sysctlnode *vte_node; 112 const struct sysctlnode *vte_node;
113}; 113};
114 114
115static int veriexec_verbose; 115static int veriexec_verbose;
116int veriexec_strict; 116int veriexec_strict;
117static int veriexec_bypass = 1; 117static int veriexec_bypass = 1;
118 118
119static char *veriexec_fp_names = NULL; 119static char *veriexec_fp_names = NULL;
120static size_t veriexec_name_max = 0; 120static size_t veriexec_name_max = 0;
121 121
122static const struct sysctlnode *veriexec_count_node; 122static const struct sysctlnode *veriexec_count_node;
123 123
124static fileassoc_t veriexec_hook; 124static fileassoc_t veriexec_hook;
125static specificdata_key_t veriexec_mountspecific_key; 125static specificdata_key_t veriexec_mountspecific_key;
126 126
127static LIST_HEAD(, veriexec_fpops) veriexec_fpops_list = 127static LIST_HEAD(, veriexec_fpops) veriexec_fpops_list =
128 LIST_HEAD_INITIALIZER(veriexec_fpops_list); 128 LIST_HEAD_INITIALIZER(veriexec_fpops_list);
129 129
130static int veriexec_raw_cb(kauth_cred_t, kauth_action_t, void *, 130static int veriexec_raw_cb(kauth_cred_t, kauth_action_t, void *,
131 void *, void *, void *, void *); 131 void *, void *, void *, void *);
132static struct veriexec_fpops *veriexec_fpops_lookup(const char *); 132static struct veriexec_fpops *veriexec_fpops_lookup(const char *);
133static void veriexec_file_free(struct veriexec_file_entry *); 133static void veriexec_file_free(struct veriexec_file_entry *);
134 134
135static unsigned int veriexec_tablecount = 0; 135static unsigned int veriexec_tablecount = 0;
136 136
137/* 137/*
138 * Veriexec operations global lock - most ops hold this as a read 138 * Veriexec operations global lock - most ops hold this as a read
139 * lock, it is upgraded to a write lock when destroying veriexec file 139 * lock, it is upgraded to a write lock when destroying veriexec file
140 * table entries. 140 * table entries.
141 */ 141 */
142static krwlock_t veriexec_op_lock; 142static krwlock_t veriexec_op_lock;
143 143
144/* 144/*
145 * Sysctl helper routine for Veriexec. 145 * Sysctl helper routine for Veriexec.
146 */ 146 */
147static int 147static int
148sysctl_kern_veriexec_algorithms(SYSCTLFN_ARGS) 148sysctl_kern_veriexec_algorithms(SYSCTLFN_ARGS)
149{ 149{
150 size_t len; 150 size_t len;
151 int error; 151 int error;
152 const char *p; 152 const char *p;
153 153
154 if (newp != NULL) 154 if (newp != NULL)
155 return EPERM; 155 return EPERM;
156 156
157 if (namelen != 0) 157 if (namelen != 0)
158 return EINVAL; 158 return EINVAL;
159 159
160 p = veriexec_fp_names == NULL ? "" : veriexec_fp_names; 160 p = veriexec_fp_names == NULL ? "" : veriexec_fp_names;
161 161
162 len = strlen(p) + 1; 162 len = strlen(p) + 1;
163 163
164 if (*oldlenp < len) 164 if (*oldlenp < len)
165 return ENOMEM; 165 return ENOMEM;
166 166
167 if ((error = copyout(p, oldp, len)) != 0) 167 if (oldp && (error = copyout(p, oldp, len)) != 0)
168 return error; 168 return error;
169 169
170 *oldlenp = len; 170 *oldlenp = len;
171 return 0; 171 return 0;
172} 172}
173 173
174static int 174static int
175sysctl_kern_veriexec_strict(SYSCTLFN_ARGS) 175sysctl_kern_veriexec_strict(SYSCTLFN_ARGS)
176{ 176{
177 struct sysctlnode node; 177 struct sysctlnode node;
178 int error, newval; 178 int error, newval;
179 179
180 node = *rnode; 180 node = *rnode;
181 node.sysctl_data = &newval; 181 node.sysctl_data = &newval;
182 182
183 newval = veriexec_strict; 183 newval = veriexec_strict;
184 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 184 error = sysctl_lookup(SYSCTLFN_CALL(&node));
185 if (error || newp == NULL) 185 if (error || newp == NULL)
186 return error; 186 return error;
187 187
188 if (newval < veriexec_strict) 188 if (newval < veriexec_strict)
189 return EPERM; 189 return EPERM;
190 190
191 veriexec_strict = newval; 191 veriexec_strict = newval;
192 192
193 return 0; 193 return 0;
194} 194}
195 195
196SYSCTL_SETUP(sysctl_kern_veriexec_setup, "sysctl kern.veriexec setup") 196SYSCTL_SETUP(sysctl_kern_veriexec_setup, "sysctl kern.veriexec setup")
197{ 197{
198 const struct sysctlnode *rnode = NULL; 198 const struct sysctlnode *rnode = NULL;
199 199
200 sysctl_createv(clog, 0, NULL, &rnode, 200 sysctl_createv(clog, 0, NULL, &rnode,
201 CTLFLAG_PERMANENT, 201 CTLFLAG_PERMANENT,
202 CTLTYPE_NODE, "kern", NULL, 202 CTLTYPE_NODE, "kern", NULL,
203 NULL, 0, NULL, 0, 203 NULL, 0, NULL, 0,
204 CTL_KERN, CTL_EOL); 204 CTL_KERN, CTL_EOL);
205 205
206 sysctl_createv(clog, 0, &rnode, &rnode, 206 sysctl_createv(clog, 0, &rnode, &rnode,
207 CTLFLAG_PERMANENT, 207 CTLFLAG_PERMANENT,
208 CTLTYPE_NODE, "veriexec", 208 CTLTYPE_NODE, "veriexec",
209 SYSCTL_DESCR("Veriexec"), 209 SYSCTL_DESCR("Veriexec"),
210 NULL, 0, NULL, 0, 210 NULL, 0, NULL, 0,
211 CTL_CREATE, CTL_EOL); 211 CTL_CREATE, CTL_EOL);
212 212
213 sysctl_createv(clog, 0, &rnode, NULL, 213 sysctl_createv(clog, 0, &rnode, NULL,
214 CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 214 CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
215 CTLTYPE_INT, "verbose", 215 CTLTYPE_INT, "verbose",
216 SYSCTL_DESCR("Veriexec verbose level"), 216 SYSCTL_DESCR("Veriexec verbose level"),
217 NULL, 0, &veriexec_verbose, 0, 217 NULL, 0, &veriexec_verbose, 0,
218 CTL_CREATE, CTL_EOL); 218 CTL_CREATE, CTL_EOL);
219 sysctl_createv(clog, 0, &rnode, NULL, 219 sysctl_createv(clog, 0, &rnode, NULL,
220 CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 220 CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
221 CTLTYPE_INT, "strict", 221 CTLTYPE_INT, "strict",
222 SYSCTL_DESCR("Veriexec strict level"), 222 SYSCTL_DESCR("Veriexec strict level"),
223 sysctl_kern_veriexec_strict, 0, NULL, 0, 223 sysctl_kern_veriexec_strict, 0, NULL, 0,
224 CTL_CREATE, CTL_EOL); 224 CTL_CREATE, CTL_EOL);
225 sysctl_createv(clog, 0, &rnode, NULL, 225 sysctl_createv(clog, 0, &rnode, NULL,
226 CTLFLAG_PERMANENT, 226 CTLFLAG_PERMANENT,
227 CTLTYPE_STRING, "algorithms", 227 CTLTYPE_STRING, "algorithms",
228 SYSCTL_DESCR("Veriexec supported hashing " 228 SYSCTL_DESCR("Veriexec supported hashing "
229 "algorithms"), 229 "algorithms"),
230 sysctl_kern_veriexec_algorithms, 0, NULL, 0, 230 sysctl_kern_veriexec_algorithms, 0, NULL, 0,
231 CTL_CREATE, CTL_EOL); 231 CTL_CREATE, CTL_EOL);
232 sysctl_createv(clog, 0, &rnode, &veriexec_count_node, 232 sysctl_createv(clog, 0, &rnode, &veriexec_count_node,
233 CTLFLAG_PERMANENT, 233 CTLFLAG_PERMANENT,
234 CTLTYPE_NODE, "count", 234 CTLTYPE_NODE, "count",
235 SYSCTL_DESCR("Number of fingerprints on mount(s)"), 235 SYSCTL_DESCR("Number of fingerprints on mount(s)"),
236 NULL, 0, NULL, 0, 236 NULL, 0, NULL, 0,
237 CTL_CREATE, CTL_EOL); 237 CTL_CREATE, CTL_EOL);
238} 238}
239 239
240/* 240/*
241 * Add ops to the fignerprint ops vector list. 241 * Add ops to the fignerprint ops vector list.
242 */ 242 */
243int 243int
244veriexec_fpops_add(const char *fp_type, size_t hash_len, size_t ctx_size, 244veriexec_fpops_add(const char *fp_type, size_t hash_len, size_t ctx_size,
245 veriexec_fpop_init_t init, veriexec_fpop_update_t update, 245 veriexec_fpop_init_t init, veriexec_fpop_update_t update,
246 veriexec_fpop_final_t final) 246 veriexec_fpop_final_t final)
247{ 247{
248 struct veriexec_fpops *ops; 248 struct veriexec_fpops *ops;
249 249
250 /* Sanity check all parameters. */ 250 /* Sanity check all parameters. */
251 if ((fp_type == NULL) || (hash_len == 0) || (ctx_size == 0) || 251 if ((fp_type == NULL) || (hash_len == 0) || (ctx_size == 0) ||
252 (init == NULL) || (update == NULL) || (final == NULL)) 252 (init == NULL) || (update == NULL) || (final == NULL))
253 return (EFAULT); 253 return (EFAULT);
254 254
255 if (veriexec_fpops_lookup(fp_type) != NULL) 255 if (veriexec_fpops_lookup(fp_type) != NULL)
256 return (EEXIST); 256 return (EEXIST);
257 257
258 ops = kmem_alloc(sizeof(*ops), KM_SLEEP); 258 ops = kmem_alloc(sizeof(*ops), KM_SLEEP);
259 259
260 ops->type = fp_type; 260 ops->type = fp_type;
261 ops->hash_len = hash_len; 261 ops->hash_len = hash_len;
262 ops->context_size = ctx_size; 262 ops->context_size = ctx_size;
263 ops->init = init; 263 ops->init = init;
264 ops->update = update; 264 ops->update = update;
265 ops->final = final; 265 ops->final = final;
266 266
267 LIST_INSERT_HEAD(&veriexec_fpops_list, ops, entries); 267 LIST_INSERT_HEAD(&veriexec_fpops_list, ops, entries);
268 268
269 /* 269 /*
270 * If we don't have space for any names, allocate enough for six 270 * If we don't have space for any names, allocate enough for six
271 * which should be sufficient. (it's also enough for all algorithms 271 * which should be sufficient. (it's also enough for all algorithms
272 * we can support at the moment) 272 * we can support at the moment)
273 */ 273 */
274 if (veriexec_fp_names == NULL) { 274 if (veriexec_fp_names == NULL) {
275 veriexec_name_max = 64; 275 veriexec_name_max = 64;
276 veriexec_fp_names = kmem_zalloc(veriexec_name_max, KM_SLEEP); 276 veriexec_fp_names = kmem_zalloc(veriexec_name_max, KM_SLEEP);
277 } 277 }
278 278
279 /* 279 /*
280 * If we're running out of space for storing supported algorithms, 280 * If we're running out of space for storing supported algorithms,
281 * extend the buffer with space for four names. 281 * extend the buffer with space for four names.
282 */ 282 */
283 while (veriexec_name_max - (strlen(veriexec_fp_names) + 1) < 283 while (veriexec_name_max - (strlen(veriexec_fp_names) + 1) <
284 strlen(fp_type)) { 284 strlen(fp_type)) {
285 char *newp; 285 char *newp;
286 unsigned int new_max; 286 unsigned int new_max;
287 287
288 /* Add space for four algorithm names. */ 288 /* Add space for four algorithm names. */
289 new_max = veriexec_name_max + 64; 289 new_max = veriexec_name_max + 64;
290 newp = kmem_zalloc(new_max, KM_SLEEP); 290 newp = kmem_zalloc(new_max, KM_SLEEP);
291 strlcpy(newp, veriexec_fp_names, new_max); 291 strlcpy(newp, veriexec_fp_names, new_max);
292 kmem_free(veriexec_fp_names, veriexec_name_max); 292 kmem_free(veriexec_fp_names, veriexec_name_max);
293 veriexec_fp_names = newp; 293 veriexec_fp_names = newp;
294 veriexec_name_max = new_max; 294 veriexec_name_max = new_max;
295 } 295 }
296 296
297 if (*veriexec_fp_names != '\0') 297 if (*veriexec_fp_names != '\0')
298 strlcat(veriexec_fp_names, " ", veriexec_name_max); 298 strlcat(veriexec_fp_names, " ", veriexec_name_max);
299 299
300 strlcat(veriexec_fp_names, fp_type, veriexec_name_max); 300 strlcat(veriexec_fp_names, fp_type, veriexec_name_max);
301 301
302 return (0); 302 return (0);
303} 303}
304 304
305static void 305static void
306veriexec_mountspecific_dtor(void *v) 306veriexec_mountspecific_dtor(void *v)
307{ 307{
308 struct veriexec_table_entry *vte = v; 308 struct veriexec_table_entry *vte = v;
309 309
310 if (vte == NULL) { 310 if (vte == NULL) {
311 return; 311 return;
312 } 312 }
313 sysctl_free(__UNCONST(vte->vte_node)); 313 sysctl_free(__UNCONST(vte->vte_node));
314 veriexec_tablecount--; 314 veriexec_tablecount--;
315 kmem_free(vte, sizeof(*vte)); 315 kmem_free(vte, sizeof(*vte));
316} 316}
317 317
318/* 318/*
319 * Initialise Veriexec. 319 * Initialise Veriexec.
320 */ 320 */
321void 321void
322veriexec_init(void) 322veriexec_init(void)
323{ 323{
324 int error; 324 int error;
325 325
326 /* Register a fileassoc for Veriexec. */ 326 /* Register a fileassoc for Veriexec. */
327 error = fileassoc_register("veriexec", 327 error = fileassoc_register("veriexec",
328 (fileassoc_cleanup_cb_t)veriexec_file_free, &veriexec_hook); 328 (fileassoc_cleanup_cb_t)veriexec_file_free, &veriexec_hook);
329 if (error) 329 if (error)
330 panic("Veriexec: Can't register fileassoc: error=%d", error); 330 panic("Veriexec: Can't register fileassoc: error=%d", error);
331 331
332 /* Register listener to handle raw disk access. */ 332 /* Register listener to handle raw disk access. */
333 if (kauth_listen_scope(KAUTH_SCOPE_DEVICE, veriexec_raw_cb, NULL) == 333 if (kauth_listen_scope(KAUTH_SCOPE_DEVICE, veriexec_raw_cb, NULL) ==
334 NULL) 334 NULL)
335 panic("Veriexec: Can't listen on device scope"); 335 panic("Veriexec: Can't listen on device scope");
336 336
337 error = mount_specific_key_create(&veriexec_mountspecific_key, 337 error = mount_specific_key_create(&veriexec_mountspecific_key,
338 veriexec_mountspecific_dtor); 338 veriexec_mountspecific_dtor);
339 if (error) 339 if (error)
340 panic("Veriexec: Can't create mountspecific key"); 340 panic("Veriexec: Can't create mountspecific key");
341 341
342 rw_init(&veriexec_op_lock); 342 rw_init(&veriexec_op_lock);
343 343
344#define FPOPS_ADD(a, b, c, d, e, f) \ 344#define FPOPS_ADD(a, b, c, d, e, f) \
345 veriexec_fpops_add(a, b, c, (veriexec_fpop_init_t)d, \ 345 veriexec_fpops_add(a, b, c, (veriexec_fpop_init_t)d, \
346 (veriexec_fpop_update_t)e, (veriexec_fpop_final_t)f) 346 (veriexec_fpop_update_t)e, (veriexec_fpop_final_t)f)
347 347
348#ifdef VERIFIED_EXEC_FP_RMD160 348#ifdef VERIFIED_EXEC_FP_RMD160
349 FPOPS_ADD("RMD160", RMD160_DIGEST_LENGTH, sizeof(RMD160_CTX), 349 FPOPS_ADD("RMD160", RMD160_DIGEST_LENGTH, sizeof(RMD160_CTX),
350 RMD160Init, RMD160Update, RMD160Final); 350 RMD160Init, RMD160Update, RMD160Final);
351#endif /* VERIFIED_EXEC_FP_RMD160 */ 351#endif /* VERIFIED_EXEC_FP_RMD160 */
352 352
353#ifdef VERIFIED_EXEC_FP_SHA256 353#ifdef VERIFIED_EXEC_FP_SHA256
354 FPOPS_ADD("SHA256", SHA256_DIGEST_LENGTH, sizeof(SHA256_CTX), 354 FPOPS_ADD("SHA256", SHA256_DIGEST_LENGTH, sizeof(SHA256_CTX),
355 SHA256_Init, SHA256_Update, SHA256_Final); 355 SHA256_Init, SHA256_Update, SHA256_Final);
356#endif /* VERIFIED_EXEC_FP_SHA256 */ 356#endif /* VERIFIED_EXEC_FP_SHA256 */
357 357
358#ifdef VERIFIED_EXEC_FP_SHA384 358#ifdef VERIFIED_EXEC_FP_SHA384
359 FPOPS_ADD("SHA384", SHA384_DIGEST_LENGTH, sizeof(SHA384_CTX), 359 FPOPS_ADD("SHA384", SHA384_DIGEST_LENGTH, sizeof(SHA384_CTX),
360 SHA384_Init, SHA384_Update, SHA384_Final); 360 SHA384_Init, SHA384_Update, SHA384_Final);
361#endif /* VERIFIED_EXEC_FP_SHA384 */ 361#endif /* VERIFIED_EXEC_FP_SHA384 */
362 362
363#ifdef VERIFIED_EXEC_FP_SHA512 363#ifdef VERIFIED_EXEC_FP_SHA512
364 FPOPS_ADD("SHA512", SHA512_DIGEST_LENGTH, sizeof(SHA512_CTX), 364 FPOPS_ADD("SHA512", SHA512_DIGEST_LENGTH, sizeof(SHA512_CTX),
365 SHA512_Init, SHA512_Update, SHA512_Final); 365 SHA512_Init, SHA512_Update, SHA512_Final);
366#endif /* VERIFIED_EXEC_FP_SHA512 */ 366#endif /* VERIFIED_EXEC_FP_SHA512 */
367 367
368#ifdef VERIFIED_EXEC_FP_SHA1 368#ifdef VERIFIED_EXEC_FP_SHA1
369 FPOPS_ADD("SHA1", SHA1_DIGEST_LENGTH, sizeof(SHA1_CTX), 369 FPOPS_ADD("SHA1", SHA1_DIGEST_LENGTH, sizeof(SHA1_CTX),
370 SHA1Init, SHA1Update, SHA1Final); 370 SHA1Init, SHA1Update, SHA1Final);
371#endif /* VERIFIED_EXEC_FP_SHA1 */ 371#endif /* VERIFIED_EXEC_FP_SHA1 */
372 372
373#ifdef VERIFIED_EXEC_FP_MD5 373#ifdef VERIFIED_EXEC_FP_MD5
374 FPOPS_ADD("MD5", MD5_DIGEST_LENGTH, sizeof(MD5_CTX), 374 FPOPS_ADD("MD5", MD5_DIGEST_LENGTH, sizeof(MD5_CTX),
375 MD5Init, MD5Update, MD5Final); 375 MD5Init, MD5Update, MD5Final);
376#endif /* VERIFIED_EXEC_FP_MD5 */ 376#endif /* VERIFIED_EXEC_FP_MD5 */
377 377
378#undef FPOPS_ADD 378#undef FPOPS_ADD
379} 379}
380 380
381static struct veriexec_fpops * 381static struct veriexec_fpops *
382veriexec_fpops_lookup(const char *name) 382veriexec_fpops_lookup(const char *name)
383{ 383{
384 struct veriexec_fpops *ops; 384 struct veriexec_fpops *ops;
385 385
386 if (name == NULL) 386 if (name == NULL)
387 return (NULL); 387 return (NULL);
388 388
389 LIST_FOREACH(ops, &veriexec_fpops_list, entries) { 389 LIST_FOREACH(ops, &veriexec_fpops_list, entries) {
390 if (strcasecmp(name, ops->type) == 0) 390 if (strcasecmp(name, ops->type) == 0)
391 return (ops); 391 return (ops);
392 } 392 }
393 393
394 return (NULL); 394 return (NULL);
395} 395}
396 396
397/* 397/*
398 * Calculate fingerprint. Information on hash length and routines used is 398 * Calculate fingerprint. Information on hash length and routines used is
399 * extracted from veriexec_hash_list according to the hash type. 399 * extracted from veriexec_hash_list according to the hash type.
400 * 400 *
401 * NOTE: vfe is assumed to be locked for writing on entry. 401 * NOTE: vfe is assumed to be locked for writing on entry.
402 */ 402 */
403static int 403static int
404veriexec_fp_calc(struct lwp *l, struct vnode *vp, int lock_state, 404veriexec_fp_calc(struct lwp *l, struct vnode *vp, int lock_state,
405 struct veriexec_file_entry *vfe, u_char *fp) 405 struct veriexec_file_entry *vfe, u_char *fp)
406{ 406{
407 struct vattr va; 407 struct vattr va;
408 void *ctx, *page_ctx; 408 void *ctx, *page_ctx;
409 u_char *buf, *page_fp; 409 u_char *buf, *page_fp;
410 off_t offset, len; 410 off_t offset, len;
411 size_t resid, npages; 411 size_t resid, npages;
412 int error, do_perpage, pagen; 412 int error, do_perpage, pagen;
413 413
414 error = VOP_GETATTR(vp, &va, l->l_cred); 414 error = VOP_GETATTR(vp, &va, l->l_cred);
415 if (error) 415 if (error)
416 return (error); 416 return (error);
417 417
418#ifdef notyet /* XXX - for now */ 418#ifdef notyet /* XXX - for now */
419 if ((vfe->type & VERIEXEC_UNTRUSTED) && 419 if ((vfe->type & VERIEXEC_UNTRUSTED) &&
420 (vfe->page_fp_status == PAGE_FP_NONE)) 420 (vfe->page_fp_status == PAGE_FP_NONE))
421 do_perpage = 1; 421 do_perpage = 1;
422 else 422 else
423#endif /* notyet */ 423#endif /* notyet */
424 do_perpage = 0; 424 do_perpage = 0;
425 425
426 ctx = kmem_alloc(vfe->ops->context_size, KM_SLEEP); 426 ctx = kmem_alloc(vfe->ops->context_size, KM_SLEEP);
427 buf = kmem_alloc(PAGE_SIZE, KM_SLEEP); 427 buf = kmem_alloc(PAGE_SIZE, KM_SLEEP);
428 428
429 page_ctx = NULL; 429 page_ctx = NULL;
430 page_fp = NULL; 430 page_fp = NULL;
431 npages = 0; 431 npages = 0;
432 if (do_perpage) { 432 if (do_perpage) {
433 npages = (va.va_size >> PAGE_SHIFT) + 1; 433 npages = (va.va_size >> PAGE_SHIFT) + 1;
434 page_fp = kmem_alloc(vfe->ops->hash_len * npages, KM_SLEEP); 434 page_fp = kmem_alloc(vfe->ops->hash_len * npages, KM_SLEEP);
435 vfe->page_fp = page_fp; 435 vfe->page_fp = page_fp;
436 page_ctx = kmem_alloc(vfe->ops->context_size, KM_SLEEP); 436 page_ctx = kmem_alloc(vfe->ops->context_size, KM_SLEEP);
437 } 437 }
438 438
439 (vfe->ops->init)(ctx); 439 (vfe->ops->init)(ctx);
440 440
441 len = 0; 441 len = 0;
442 error = 0; 442 error = 0;
443 pagen = 0; 443 pagen = 0;
444 for (offset = 0; offset < va.va_size; offset += PAGE_SIZE) { 444 for (offset = 0; offset < va.va_size; offset += PAGE_SIZE) {
445 len = ((va.va_size - offset) < PAGE_SIZE) ? 445 len = ((va.va_size - offset) < PAGE_SIZE) ?
446 (va.va_size - offset) : PAGE_SIZE; 446 (va.va_size - offset) : PAGE_SIZE;
447 447
448 error = vn_rdwr(UIO_READ, vp, buf, len, offset, 448 error = vn_rdwr(UIO_READ, vp, buf, len, offset,
449 UIO_SYSSPACE, 449 UIO_SYSSPACE,
450 ((lock_state == VERIEXEC_LOCKED)? 450 ((lock_state == VERIEXEC_LOCKED)?
451 IO_NODELOCKED : 0), 451 IO_NODELOCKED : 0),
452 l->l_cred, &resid, NULL); 452 l->l_cred, &resid, NULL);
453 453
454 if (error) { 454 if (error) {
455 if (do_perpage) { 455 if (do_perpage) {
456 kmem_free(vfe->page_fp, 456 kmem_free(vfe->page_fp,
457 vfe->ops->hash_len * npages); 457 vfe->ops->hash_len * npages);
458 vfe->page_fp = NULL; 458 vfe->page_fp = NULL;
459 } 459 }
460 460
461 goto bad; 461 goto bad;
462 } 462 }
463 463
464 (vfe->ops->update)(ctx, buf, (unsigned int) len); 464 (vfe->ops->update)(ctx, buf, (unsigned int) len);
465 465
466 if (do_perpage) { 466 if (do_perpage) {
467 (vfe->ops->init)(page_ctx); 467 (vfe->ops->init)(page_ctx);
468 (vfe->ops->update)(page_ctx, buf, (unsigned int)len); 468 (vfe->ops->update)(page_ctx, buf, (unsigned int)len);
469 (vfe->ops->final)(page_fp, page_ctx); 469 (vfe->ops->final)(page_fp, page_ctx);
470 470
471 if (veriexec_verbose >= 2) { 471 if (veriexec_verbose >= 2) {
472 int i; 472 int i;
473 473
474 printf("hash for page %d: ", pagen); 474 printf("hash for page %d: ", pagen);
475 for (i = 0; i < vfe->ops->hash_len; i++) 475 for (i = 0; i < vfe->ops->hash_len; i++)
476 printf("%02x", page_fp[i]); 476 printf("%02x", page_fp[i]);
477 printf("\n"); 477 printf("\n");
478 } 478 }
479 479
480 page_fp += vfe->ops->hash_len; 480 page_fp += vfe->ops->hash_len;
481 pagen++; 481 pagen++;
482 } 482 }
483 483
484 if (len != PAGE_SIZE) 484 if (len != PAGE_SIZE)
485 break; 485 break;
486 } 486 }
487 487
488 (vfe->ops->final)(fp, ctx); 488 (vfe->ops->final)(fp, ctx);
489 489
490 if (do_perpage) { 490 if (do_perpage) {
491 vfe->last_page_size = len; 491 vfe->last_page_size = len;
492 vfe->page_fp_status = PAGE_FP_READY; 492 vfe->page_fp_status = PAGE_FP_READY;
493 vfe->npages = npages; 493 vfe->npages = npages;
494 } 494 }
495 495
496bad: 496bad:
497 if (do_perpage) 497 if (do_perpage)
498 kmem_free(page_ctx, vfe->ops->context_size); 498 kmem_free(page_ctx, vfe->ops->context_size);
499 499
500 kmem_free(ctx, vfe->ops->context_size); 500 kmem_free(ctx, vfe->ops->context_size);
501 kmem_free(buf, PAGE_SIZE); 501 kmem_free(buf, PAGE_SIZE);
502 502
503 return (error); 503 return (error);
504} 504}
505 505
506/* Compare two fingerprints of the same type. */ 506/* Compare two fingerprints of the same type. */
507static int 507static int
508veriexec_fp_cmp(struct veriexec_fpops *ops, u_char *fp1, u_char *fp2) 508veriexec_fp_cmp(struct veriexec_fpops *ops, u_char *fp1, u_char *fp2)
509{ 509{
510 if (veriexec_verbose >= 2) { 510 if (veriexec_verbose >= 2) {
511 int i; 511 int i;
512 512
513 printf("comparing hashes...\n"); 513 printf("comparing hashes...\n");
514 printf("fp1: "); 514 printf("fp1: ");
515 for (i = 0; i < ops->hash_len; i++) { 515 for (i = 0; i < ops->hash_len; i++) {
516 printf("%02x", fp1[i]); 516 printf("%02x", fp1[i]);
517 } 517 }
518 printf("\nfp2: "); 518 printf("\nfp2: ");
519 for (i = 0; i < ops->hash_len; i++) { 519 for (i = 0; i < ops->hash_len; i++) {
520 printf("%02x", fp2[i]); 520 printf("%02x", fp2[i]);
521 } 521 }
522 printf("\n"); 522 printf("\n");
523 } 523 }
524 524
525 return (memcmp(fp1, fp2, ops->hash_len)); 525 return (memcmp(fp1, fp2, ops->hash_len));
526} 526}
527 527
528static struct veriexec_table_entry * 528static struct veriexec_table_entry *
529veriexec_table_lookup(struct mount *mp) 529veriexec_table_lookup(struct mount *mp)
530{ 530{
531 /* XXX: From raidframe init */ 531 /* XXX: From raidframe init */
532 if (mp == NULL) 532 if (mp == NULL)
533 return NULL; 533 return NULL;
534 534
535 return mount_getspecific(mp, veriexec_mountspecific_key); 535 return mount_getspecific(mp, veriexec_mountspecific_key);
536} 536}
537 537
538static struct veriexec_file_entry * 538static struct veriexec_file_entry *
539veriexec_get(struct vnode *vp) 539veriexec_get(struct vnode *vp)
540{ 540{
541 return (fileassoc_lookup(vp, veriexec_hook)); 541 return (fileassoc_lookup(vp, veriexec_hook));
542} 542}
543 543
544bool 544bool
545veriexec_lookup(struct vnode *vp) 545veriexec_lookup(struct vnode *vp)
546{ 546{
547 return (veriexec_get(vp) == NULL ? false : true); 547 return (veriexec_get(vp) == NULL ? false : true);
548} 548}
549 549
550/* 550/*
551 * Routine for maintaining mostly consistent message formats in Veriexec. 551 * Routine for maintaining mostly consistent message formats in Veriexec.
552 */ 552 */
553static void 553static void
554veriexec_file_report(struct veriexec_file_entry *vfe, const u_char *msg, 554veriexec_file_report(struct veriexec_file_entry *vfe, const u_char *msg,
555 const u_char *filename, struct lwp *l, int f) 555 const u_char *filename, struct lwp *l, int f)
556{ 556{
557 if (msg == NULL) 557 if (msg == NULL)
558 return; 558 return;
559 559
560 if (vfe != NULL && vfe->filename != NULL) 560 if (vfe != NULL && vfe->filename != NULL)
561 filename = vfe->filename; 561 filename = vfe->filename;
562 562
563 if (filename == NULL) 563 if (filename == NULL)
564 return; 564 return;
565 565
566 if (((f & REPORT_LOGMASK) >> 1) <= veriexec_verbose) { 566 if (((f & REPORT_LOGMASK) >> 1) <= veriexec_verbose) {
567 if (!(f & REPORT_ALARM) || (l == NULL)) 567 if (!(f & REPORT_ALARM) || (l == NULL))
568 log(LOG_NOTICE, "Veriexec: %s [%s]\n", msg, 568 log(LOG_NOTICE, "Veriexec: %s [%s]\n", msg,
569 filename); 569 filename);
570 else 570 else
571 log(LOG_ALERT, "Veriexec: %s [%s, prog=%s pid=%u, " 571 log(LOG_ALERT, "Veriexec: %s [%s, prog=%s pid=%u, "
572 "uid=%u, gid=%u]\n", msg, filename, 572 "uid=%u, gid=%u]\n", msg, filename,
573 l->l_proc->p_comm, l->l_proc->p_pid, 573 l->l_proc->p_comm, l->l_proc->p_pid,
574 kauth_cred_getuid(l->l_cred), 574 kauth_cred_getuid(l->l_cred),
575 kauth_cred_getgid(l->l_cred)); 575 kauth_cred_getgid(l->l_cred));
576 } 576 }
577 577
578 if (f & REPORT_PANIC) 578 if (f & REPORT_PANIC)
579 panic("Veriexec: Unrecoverable error."); 579 panic("Veriexec: Unrecoverable error.");
580} 580}
581 581
582/* 582/*
583 * Verify the fingerprint of the given file. If we're called directly from 583 * Verify the fingerprint of the given file. If we're called directly from
584 * sys_execve(), 'flag' will be VERIEXEC_DIRECT. If we're called from 584 * sys_execve(), 'flag' will be VERIEXEC_DIRECT. If we're called from
585 * exec_script(), 'flag' will be VERIEXEC_INDIRECT. If we are called from 585 * exec_script(), 'flag' will be VERIEXEC_INDIRECT. If we are called from
586 * vn_open(), 'flag' will be VERIEXEC_FILE. 586 * vn_open(), 'flag' will be VERIEXEC_FILE.
587 * 587 *
588 * NOTE: The veriexec file entry pointer (vfep) will be returned LOCKED 588 * NOTE: The veriexec file entry pointer (vfep) will be returned LOCKED
589 * on no error. 589 * on no error.
590 */ 590 */
591static int 591static int
592veriexec_file_verify(struct lwp *l, struct vnode *vp, const u_char *name, 592veriexec_file_verify(struct lwp *l, struct vnode *vp, const u_char *name,
593 int flag, int lockstate, struct veriexec_file_entry **vfep) 593 int flag, int lockstate, struct veriexec_file_entry **vfep)
594{ 594{
595 struct veriexec_file_entry *vfe; 595 struct veriexec_file_entry *vfe;
596 int error; 596 int error;
597 597
598#define VFE_NEEDS_EVAL(vfe) ((vfe->status == FINGERPRINT_NOTEVAL) || \ 598#define VFE_NEEDS_EVAL(vfe) ((vfe->status == FINGERPRINT_NOTEVAL) || \
599 (vfe->type & VERIEXEC_UNTRUSTED)) 599 (vfe->type & VERIEXEC_UNTRUSTED))
600 600
601 if (vfep != NULL) 601 if (vfep != NULL)
602 *vfep = NULL; 602 *vfep = NULL;
603 603
604 if (vp->v_type != VREG) 604 if (vp->v_type != VREG)
605 return (0); 605 return (0);
606 606
607 if (lockstate == VERIEXEC_UNLOCKED) 607 if (lockstate == VERIEXEC_UNLOCKED)
608 rw_enter(&veriexec_op_lock, RW_READER); 608 rw_enter(&veriexec_op_lock, RW_READER);
609 609
610 /* Lookup veriexec table entry, save pointer if requested. */ 610 /* Lookup veriexec table entry, save pointer if requested. */
611 vfe = veriexec_get(vp); 611 vfe = veriexec_get(vp);
612 if (vfep != NULL) 612 if (vfep != NULL)
613 *vfep = vfe; 613 *vfep = vfe;
614 if (vfe == NULL) 614 if (vfe == NULL)
615 goto out; 615 goto out;
616 616
617 error = 0; 617 error = 0;
618 618
619 /* 619 /*
620 * Grab the lock for the entry, if we need to do an evaluation 620 * Grab the lock for the entry, if we need to do an evaluation
621 * then the lock is a write lock, after we have the write 621 * then the lock is a write lock, after we have the write
622 * lock, check if we really need it - some other thread may 622 * lock, check if we really need it - some other thread may
623 * have already done the work for us. 623 * have already done the work for us.
624 */ 624 */
625 if (VFE_NEEDS_EVAL(vfe)) { 625 if (VFE_NEEDS_EVAL(vfe)) {
626 rw_enter(&vfe->lock, RW_WRITER); 626 rw_enter(&vfe->lock, RW_WRITER);
627 if (!VFE_NEEDS_EVAL(vfe)) 627 if (!VFE_NEEDS_EVAL(vfe))
628 rw_downgrade(&vfe->lock); 628 rw_downgrade(&vfe->lock);
629 } else 629 } else
630 rw_enter(&vfe->lock, RW_READER); 630 rw_enter(&vfe->lock, RW_READER);
631 631
632 /* Evaluate fingerprint if needed. */ 632 /* Evaluate fingerprint if needed. */
633 if (VFE_NEEDS_EVAL(vfe)) { 633 if (VFE_NEEDS_EVAL(vfe)) {
634 u_char *digest; 634 u_char *digest;
635 635
636 /* Calculate fingerprint for on-disk file. */ 636 /* Calculate fingerprint for on-disk file. */
637 digest = kmem_zalloc(vfe->ops->hash_len, KM_SLEEP); 637 digest = kmem_zalloc(vfe->ops->hash_len, KM_SLEEP);
638 638
639 error = veriexec_fp_calc(l, vp, lockstate, vfe, digest); 639 error = veriexec_fp_calc(l, vp, lockstate, vfe, digest);
640 if (error) { 640 if (error) {
641 veriexec_file_report(vfe, "Fingerprint calculation error.", 641 veriexec_file_report(vfe, "Fingerprint calculation error.",
642 name, NULL, REPORT_ALWAYS); 642 name, NULL, REPORT_ALWAYS);
643 kmem_free(digest, vfe->ops->hash_len); 643 kmem_free(digest, vfe->ops->hash_len);
644 rw_exit(&vfe->lock); 644 rw_exit(&vfe->lock);
645 if (lockstate == VERIEXEC_UNLOCKED) 645 if (lockstate == VERIEXEC_UNLOCKED)
646 rw_exit(&veriexec_op_lock); 646 rw_exit(&veriexec_op_lock);
647 return (error); 647 return (error);
648 } 648 }
649 649
650 /* Compare fingerprint with loaded data. */ 650 /* Compare fingerprint with loaded data. */
651 if (veriexec_fp_cmp(vfe->ops, vfe->fp, digest) == 0) 651 if (veriexec_fp_cmp(vfe->ops, vfe->fp, digest) == 0)
652 vfe->status = FINGERPRINT_VALID; 652 vfe->status = FINGERPRINT_VALID;
653 else 653 else
654 vfe->status = FINGERPRINT_NOMATCH; 654 vfe->status = FINGERPRINT_NOMATCH;
655 655
656 kmem_free(digest, vfe->ops->hash_len); 656 kmem_free(digest, vfe->ops->hash_len);
657 rw_downgrade(&vfe->lock); 657 rw_downgrade(&vfe->lock);
658 } 658 }
659 659
660 if (!(vfe->type & flag)) { 660 if (!(vfe->type & flag)) {
661 veriexec_file_report(vfe, "Incorrect access type.", name, l, 661 veriexec_file_report(vfe, "Incorrect access type.", name, l,
662 REPORT_ALWAYS|REPORT_ALARM); 662 REPORT_ALWAYS|REPORT_ALARM);
663 663
664 /* IPS mode: Enforce access type. */ 664 /* IPS mode: Enforce access type. */
665 if (veriexec_strict >= VERIEXEC_IPS) { 665 if (veriexec_strict >= VERIEXEC_IPS) {
666 rw_exit(&vfe->lock); 666 rw_exit(&vfe->lock);
667 if (lockstate == VERIEXEC_UNLOCKED) 667 if (lockstate == VERIEXEC_UNLOCKED)
668 rw_exit(&veriexec_op_lock); 668 rw_exit(&veriexec_op_lock);
669 return (EPERM); 669 return (EPERM);
670 } 670 }
671 } 671 }
672 672
673 out: 673 out:
674 /* No entry in the veriexec tables. */ 674 /* No entry in the veriexec tables. */
675 if (vfe == NULL) { 675 if (vfe == NULL) {
676 veriexec_file_report(NULL, "No entry.", name, 676 veriexec_file_report(NULL, "No entry.", name,
677 l, REPORT_VERBOSE); 677 l, REPORT_VERBOSE);
678 678
679 if (lockstate == VERIEXEC_UNLOCKED) 679 if (lockstate == VERIEXEC_UNLOCKED)
680 rw_exit(&veriexec_op_lock); 680 rw_exit(&veriexec_op_lock);
681 /* 681 /*
682 * Lockdown mode: Deny access to non-monitored files. 682 * Lockdown mode: Deny access to non-monitored files.
683 * IPS mode: Deny execution of non-monitored files. 683 * IPS mode: Deny execution of non-monitored files.
684 */ 684 */
685 if ((veriexec_strict >= VERIEXEC_LOCKDOWN) || 685 if ((veriexec_strict >= VERIEXEC_LOCKDOWN) ||
686 ((veriexec_strict >= VERIEXEC_IPS) && 686 ((veriexec_strict >= VERIEXEC_IPS) &&
687 (flag != VERIEXEC_FILE))) 687 (flag != VERIEXEC_FILE)))
688 return (EPERM); 688 return (EPERM);
689 689
690 return (0); 690 return (0);
691 } 691 }
692 692
693 switch (vfe->status) { 693 switch (vfe->status) {
694 case FINGERPRINT_NOTEVAL: 694 case FINGERPRINT_NOTEVAL:
695 /* Should not happen. */ 695 /* Should not happen. */
696 rw_exit(&vfe->lock); 696 rw_exit(&vfe->lock);
697 if (lockstate == VERIEXEC_UNLOCKED) 697 if (lockstate == VERIEXEC_UNLOCKED)
698 rw_exit(&veriexec_op_lock); 698 rw_exit(&veriexec_op_lock);
699 veriexec_file_report(vfe, "Not-evaluated status " 699 veriexec_file_report(vfe, "Not-evaluated status "
700 "post evaluation; inconsistency detected.", name, 700 "post evaluation; inconsistency detected.", name,
701 NULL, REPORT_ALWAYS|REPORT_PANIC); 701 NULL, REPORT_ALWAYS|REPORT_PANIC);
702 702
703 /*NOTREACHED*/ 703 /*NOTREACHED*/
704 704
705 case FINGERPRINT_VALID: 705 case FINGERPRINT_VALID:
706 /* Valid fingerprint. */ 706 /* Valid fingerprint. */
707 veriexec_file_report(vfe, "Match.", name, NULL, 707 veriexec_file_report(vfe, "Match.", name, NULL,
708 REPORT_VERBOSE); 708 REPORT_VERBOSE);
709 709
710 break; 710 break;
711 711
712 case FINGERPRINT_NOMATCH: 712 case FINGERPRINT_NOMATCH:
713 /* Fingerprint mismatch. */ 713 /* Fingerprint mismatch. */
714 veriexec_file_report(vfe, "Mismatch.", name, 714 veriexec_file_report(vfe, "Mismatch.", name,
715 NULL, REPORT_ALWAYS|REPORT_ALARM); 715 NULL, REPORT_ALWAYS|REPORT_ALARM);
716 716
717 /* IDS mode: Deny access on fingerprint mismatch. */ 717 /* IDS mode: Deny access on fingerprint mismatch. */
718 if (veriexec_strict >= VERIEXEC_IDS) { 718 if (veriexec_strict >= VERIEXEC_IDS) {
719 rw_exit(&vfe->lock); 719 rw_exit(&vfe->lock);
720 error = EPERM; 720 error = EPERM;
721 } 721 }
722 722
723 break; 723 break;
724 724
725 default: 725 default:
726 /* Should never happen. */ 726 /* Should never happen. */
727 rw_exit(&vfe->lock); 727 rw_exit(&vfe->lock);
728 if (lockstate == VERIEXEC_UNLOCKED) 728 if (lockstate == VERIEXEC_UNLOCKED)
729 rw_exit(&veriexec_op_lock); 729 rw_exit(&veriexec_op_lock);
730 veriexec_file_report(vfe, "Invalid status " 730 veriexec_file_report(vfe, "Invalid status "
731 "post evaluation.", name, NULL, REPORT_ALWAYS|REPORT_PANIC); 731 "post evaluation.", name, NULL, REPORT_ALWAYS|REPORT_PANIC);
732 } 732 }
733 733
734 if (lockstate == VERIEXEC_UNLOCKED) 734 if (lockstate == VERIEXEC_UNLOCKED)
735 rw_exit(&veriexec_op_lock); 735 rw_exit(&veriexec_op_lock);
736 return (error); 736 return (error);
737} 737}
738 738
739int 739int
740veriexec_verify(struct lwp *l, struct vnode *vp, const u_char *name, int flag, 740veriexec_verify(struct lwp *l, struct vnode *vp, const u_char *name, int flag,
741 bool *found) 741 bool *found)
742{ 742{
743 struct veriexec_file_entry *vfe; 743 struct veriexec_file_entry *vfe;
744 int r; 744 int r;
745 745
746 if (veriexec_bypass && (veriexec_strict == VERIEXEC_LEARNING)) 746 if (veriexec_bypass && (veriexec_strict == VERIEXEC_LEARNING))
747 return 0; 747 return 0;
748 748
749 r = veriexec_file_verify(l, vp, name, flag, VERIEXEC_UNLOCKED, &vfe); 749 r = veriexec_file_verify(l, vp, name, flag, VERIEXEC_UNLOCKED, &vfe);
750 750
751 if ((r == 0) && (vfe != NULL)) 751 if ((r == 0) && (vfe != NULL))
752 rw_exit(&vfe->lock); 752 rw_exit(&vfe->lock);
753 753
754 if (found != NULL) 754 if (found != NULL)
755 *found = (vfe != NULL) ? true : false; 755 *found = (vfe != NULL) ? true : false;
756 756
757 return (r); 757 return (r);
758} 758}
759 759
760#ifdef notyet 760#ifdef notyet
761/* 761/*
762 * Evaluate per-page fingerprints. 762 * Evaluate per-page fingerprints.
763 */ 763 */
764int 764int
765veriexec_page_verify(struct veriexec_file_entry *vfe, struct vm_page *pg, 765veriexec_page_verify(struct veriexec_file_entry *vfe, struct vm_page *pg,
766 size_t idx, struct lwp *l) 766 size_t idx, struct lwp *l)
767{ 767{
768 void *ctx; 768 void *ctx;
769 u_char *fp; 769 u_char *fp;
770 u_char *page_fp; 770 u_char *page_fp;
771 int error; 771 int error;
772 vaddr_t kva; 772 vaddr_t kva;
773 773
774 if (vfe->page_fp_status == PAGE_FP_NONE) 774 if (vfe->page_fp_status == PAGE_FP_NONE)
775 return (0); 775 return (0);
776 776
777 if (vfe->page_fp_status == PAGE_FP_FAIL) 777 if (vfe->page_fp_status == PAGE_FP_FAIL)
778 return (EPERM); 778 return (EPERM);
779 779
780 if (idx >= vfe->npages) 780 if (idx >= vfe->npages)
781 return (0); 781 return (0);
782 782
783 ctx = kmem_alloc(vfe->ops->context_size, KM_SLEEP); 783 ctx = kmem_alloc(vfe->ops->context_size, KM_SLEEP);
784 fp = kmem_alloc(vfe->ops->hash_len, KM_SLEEP); 784 fp = kmem_alloc(vfe->ops->hash_len, KM_SLEEP);
785 kva = uvm_km_alloc(kernel_map, PAGE_SIZE, 0, UVM_KMF_VAONLY | UVM_KMF_WAITVA); 785 kva = uvm_km_alloc(kernel_map, PAGE_SIZE, 0, UVM_KMF_VAONLY | UVM_KMF_WAITVA);
786 pmap_kenter_pa(kva, VM_PAGE_TO_PHYS(pg), VM_PROT_READ, 0); 786 pmap_kenter_pa(kva, VM_PAGE_TO_PHYS(pg), VM_PROT_READ, 0);
787 pmap_update(pmap_kernel()); 787 pmap_update(pmap_kernel());
788 788
789 page_fp = (u_char *) vfe->page_fp + (vfe->ops->hash_len * idx); 789 page_fp = (u_char *) vfe->page_fp + (vfe->ops->hash_len * idx);
790 (vfe->ops->init)(ctx); 790 (vfe->ops->init)(ctx);
791 (vfe->ops->update)(ctx, (void *) kva, 791 (vfe->ops->update)(ctx, (void *) kva,
792 ((vfe->npages - 1) == idx) ? vfe->last_page_size 792 ((vfe->npages - 1) == idx) ? vfe->last_page_size
793 : PAGE_SIZE); 793 : PAGE_SIZE);
794 (vfe->ops->final)(fp, ctx); 794 (vfe->ops->final)(fp, ctx);
795 795
796 pmap_kremove(kva, PAGE_SIZE); 796 pmap_kremove(kva, PAGE_SIZE);
797 pmap_update(pmap_kernel()); 797 pmap_update(pmap_kernel());
798 uvm_km_free(kernel_map, kva, PAGE_SIZE, UVM_KMF_VAONLY); 798 uvm_km_free(kernel_map, kva, PAGE_SIZE, UVM_KMF_VAONLY);
799 799
800 error = veriexec_fp_cmp(vfe->ops, page_fp, fp); 800 error = veriexec_fp_cmp(vfe->ops, page_fp, fp);
801 if (error) { 801 if (error) {
802 const char *msg; 802 const char *msg;
803 803
804 if (veriexec_strict > VERIEXEC_LEARNING) { 804 if (veriexec_strict > VERIEXEC_LEARNING) {
805 msg = "Pages modified: Killing process."; 805 msg = "Pages modified: Killing process.";
806 } else { 806 } else {
807 msg = "Pages modified."; 807 msg = "Pages modified.";
808 error = 0; 808 error = 0;
809 } 809 }
810 810
811 veriexec_file_report(msg, "[page_in]", l, 811 veriexec_file_report(msg, "[page_in]", l,
812 REPORT_ALWAYS|REPORT_ALARM); 812 REPORT_ALWAYS|REPORT_ALARM);
813 813
814 if (error) { 814 if (error) {
815 ksiginfo_t ksi; 815 ksiginfo_t ksi;
816 816
817 KSI_INIT(&ksi); 817 KSI_INIT(&ksi);
818 ksi.ksi_signo = SIGKILL; 818 ksi.ksi_signo = SIGKILL;
819 ksi.ksi_code = SI_NOINFO; 819 ksi.ksi_code = SI_NOINFO;
820 ksi.ksi_pid = l->l_proc->p_pid; 820 ksi.ksi_pid = l->l_proc->p_pid;
821 ksi.ksi_uid = 0; 821 ksi.ksi_uid = 0;
822 822
823 kpsignal(l->l_proc, &ksi, NULL); 823 kpsignal(l->l_proc, &ksi, NULL);
824 } 824 }
825 } 825 }
826 826
827 kmem_free(ctx, vfe->ops->context_size); 827 kmem_free(ctx, vfe->ops->context_size);
828 kmem_free(fp, vfe->ops->hash_len); 828 kmem_free(fp, vfe->ops->hash_len);
829 829
830 return (error); 830 return (error);
831} 831}
832#endif /* notyet */ 832#endif /* notyet */
833 833
834/* 834/*
835 * Veriexec remove policy code. 835 * Veriexec remove policy code.
836 */ 836 */
837int 837int
838veriexec_removechk(struct lwp *l, struct vnode *vp, const char *pathbuf) 838veriexec_removechk(struct lwp *l, struct vnode *vp, const char *pathbuf)
839{ 839{
840 struct veriexec_file_entry *vfe; 840 struct veriexec_file_entry *vfe;
841 int error; 841 int error;
842 842
843 if (veriexec_bypass && (veriexec_strict == VERIEXEC_LEARNING)) 843 if (veriexec_bypass && (veriexec_strict == VERIEXEC_LEARNING))
844 return 0; 844 return 0;
845 845
846 rw_enter(&veriexec_op_lock, RW_READER); 846 rw_enter(&veriexec_op_lock, RW_READER);
847 847
848 vfe = veriexec_get(vp); 848 vfe = veriexec_get(vp);
849 rw_exit(&veriexec_op_lock); 849 rw_exit(&veriexec_op_lock);
850 850
851 if (vfe == NULL) { 851 if (vfe == NULL) {
852 /* Lockdown mode: Deny access to non-monitored files. */ 852 /* Lockdown mode: Deny access to non-monitored files. */
853 if (veriexec_strict >= VERIEXEC_LOCKDOWN) 853 if (veriexec_strict >= VERIEXEC_LOCKDOWN)
854 return (EPERM); 854 return (EPERM);
855 855
856 return (0); 856 return (0);
857 } 857 }
858 858
859 veriexec_file_report(vfe, "Remove request.", pathbuf, l, 859 veriexec_file_report(vfe, "Remove request.", pathbuf, l,
860 REPORT_ALWAYS|REPORT_ALARM); 860 REPORT_ALWAYS|REPORT_ALARM);
861 861
862 /* IDS mode: Deny removal of monitored files. */ 862 /* IDS mode: Deny removal of monitored files. */
863 if (veriexec_strict >= VERIEXEC_IDS) 863 if (veriexec_strict >= VERIEXEC_IDS)
864 error = EPERM; 864 error = EPERM;
865 else 865 else
866 error = veriexec_file_delete(l, vp); 866 error = veriexec_file_delete(l, vp);
867 867
868 868
869 return error; 869 return error;
870} 870}
871 871
872/* 872/*
873 * Veriexec rename policy. 873 * Veriexec rename policy.
874 * 874 *
875 * XXX: Once there's a way to hook after a successful rename, it would be 875 * XXX: Once there's a way to hook after a successful rename, it would be
876 * XXX: nice to update vfe->filename to the new name if it's not NULL and 876 * XXX: nice to update vfe->filename to the new name if it's not NULL and
877 * XXX: the new name is absolute (ie., starts with a slash). 877 * XXX: the new name is absolute (ie., starts with a slash).
878 */ 878 */
879int 879int
880veriexec_renamechk(struct lwp *l, struct vnode *fromvp, const char *fromname, 880veriexec_renamechk(struct lwp *l, struct vnode *fromvp, const char *fromname,
881 struct vnode *tovp, const char *toname) 881 struct vnode *tovp, const char *toname)
882{ 882{
883 struct veriexec_file_entry *vfe, *tvfe; 883 struct veriexec_file_entry *vfe, *tvfe;
884 884
885 if (veriexec_bypass && (veriexec_strict == VERIEXEC_LEARNING)) 885 if (veriexec_bypass && (veriexec_strict == VERIEXEC_LEARNING))
886 return 0; 886 return 0;
887 887
888 rw_enter(&veriexec_op_lock, RW_READER); 888 rw_enter(&veriexec_op_lock, RW_READER);
889 889
890 if (veriexec_strict >= VERIEXEC_LOCKDOWN) { 890 if (veriexec_strict >= VERIEXEC_LOCKDOWN) {
891 log(LOG_ALERT, "Veriexec: Preventing rename of `%s' to " 891 log(LOG_ALERT, "Veriexec: Preventing rename of `%s' to "
892 "`%s', uid=%u, pid=%u: Lockdown mode.\n", fromname, toname, 892 "`%s', uid=%u, pid=%u: Lockdown mode.\n", fromname, toname,
893 kauth_cred_geteuid(l->l_cred), l->l_proc->p_pid); 893 kauth_cred_geteuid(l->l_cred), l->l_proc->p_pid);
894 894
895 rw_exit(&veriexec_op_lock); 895 rw_exit(&veriexec_op_lock);
896 return (EPERM); 896 return (EPERM);
897 } 897 }
898 898
899 vfe = veriexec_get(fromvp); 899 vfe = veriexec_get(fromvp);
900 tvfe = NULL; 900 tvfe = NULL;
901 if (tovp != NULL) 901 if (tovp != NULL)
902 tvfe = veriexec_get(tovp); 902 tvfe = veriexec_get(tovp);
903 903
904 if ((vfe != NULL) || (tvfe != NULL)) { 904 if ((vfe != NULL) || (tvfe != NULL)) {
905 if (veriexec_strict >= VERIEXEC_IPS) { 905 if (veriexec_strict >= VERIEXEC_IPS) {
906 log(LOG_ALERT, "Veriexec: Preventing rename of `%s' " 906 log(LOG_ALERT, "Veriexec: Preventing rename of `%s' "
907 "to `%s', uid=%u, pid=%u: IPS mode, %s " 907 "to `%s', uid=%u, pid=%u: IPS mode, %s "
908 "monitored.\n", fromname, toname, 908 "monitored.\n", fromname, toname,
909 kauth_cred_geteuid(l->l_cred), 909 kauth_cred_geteuid(l->l_cred),
910 l->l_proc->p_pid, (vfe != NULL && tvfe != NULL) ? 910 l->l_proc->p_pid, (vfe != NULL && tvfe != NULL) ?
911 "files" : "file"); 911 "files" : "file");
912 912
913 rw_exit(&veriexec_op_lock); 913 rw_exit(&veriexec_op_lock);
914 return (EPERM); 914 return (EPERM);
915 } 915 }
916 916
917 /* 917 /*
918 * Monitored file is renamed; filename no longer relevant. 918 * Monitored file is renamed; filename no longer relevant.
919 * 919 *
920 * XXX: We could keep the buffer, and when (and if) updating the 920 * XXX: We could keep the buffer, and when (and if) updating the
921 * XXX: filename post-rename, re-allocate it only if it's not 921 * XXX: filename post-rename, re-allocate it only if it's not
922 * XXX: big enough for the new filename. 922 * XXX: big enough for the new filename.
923 */ 923 */
924 if (vfe != NULL) { 924 if (vfe != NULL) {
925 /* XXXX get write lock on vfe here? */ 925 /* XXXX get write lock on vfe here? */
926 926
927 VERIEXEC_RW_UPGRADE(&veriexec_op_lock); 927 VERIEXEC_RW_UPGRADE(&veriexec_op_lock);
928 /* once we have the op lock in write mode 928 /* once we have the op lock in write mode
929 * there should be no locks on any file 929 * there should be no locks on any file
930 * entries so we can destroy the object. 930 * entries so we can destroy the object.
931 */ 931 */
932 932
933 if (vfe->filename_len > 0) 933 if (vfe->filename_len > 0)
934 kmem_free(vfe->filename, vfe->filename_len); 934 kmem_free(vfe->filename, vfe->filename_len);
935 935
936 vfe->filename = NULL; 936 vfe->filename = NULL;
937 vfe->filename_len = 0; 937 vfe->filename_len = 0;
938 938
939 rw_downgrade(&veriexec_op_lock); 939 rw_downgrade(&veriexec_op_lock);
940 } 940 }
941 941
942 log(LOG_NOTICE, "Veriexec: %s file `%s' renamed to " 942 log(LOG_NOTICE, "Veriexec: %s file `%s' renamed to "
943 "%s file `%s', uid=%u, pid=%u.\n", (vfe != NULL) ? 943 "%s file `%s', uid=%u, pid=%u.\n", (vfe != NULL) ?
944 "Monitored" : "Non-monitored", fromname, (tvfe != NULL) ? 944 "Monitored" : "Non-monitored", fromname, (tvfe != NULL) ?
945 "monitored" : "non-monitored", toname, 945 "monitored" : "non-monitored", toname,
946 kauth_cred_geteuid(l->l_cred), l->l_proc->p_pid); 946 kauth_cred_geteuid(l->l_cred), l->l_proc->p_pid);
947 947
948 rw_exit(&veriexec_op_lock); 948 rw_exit(&veriexec_op_lock);
949 949
950 /* 950 /*
951 * Monitored file is overwritten. Remove the entry. 951 * Monitored file is overwritten. Remove the entry.
952 */ 952 */
953 if (tvfe != NULL) 953 if (tvfe != NULL)
954 (void)veriexec_file_delete(l, tovp); 954 (void)veriexec_file_delete(l, tovp);
955 955
956 } else 956 } else
957 rw_exit(&veriexec_op_lock); 957 rw_exit(&veriexec_op_lock);
958 958
959 return (0); 959 return (0);
960} 960}
961 961
962static void 962static void
963veriexec_file_free(struct veriexec_file_entry *vfe) 963veriexec_file_free(struct veriexec_file_entry *vfe)
964{ 964{
965 if (vfe != NULL) { 965 if (vfe != NULL) {
966 if (vfe->fp != NULL) 966 if (vfe->fp != NULL)
967 kmem_free(vfe->fp, vfe->ops->hash_len); 967 kmem_free(vfe->fp, vfe->ops->hash_len);
968 if (vfe->page_fp != NULL) 968 if (vfe->page_fp != NULL)
969 kmem_free(vfe->page_fp, vfe->ops->hash_len); 969 kmem_free(vfe->page_fp, vfe->ops->hash_len);
970 if (vfe->filename != NULL) 970 if (vfe->filename != NULL)
971 kmem_free(vfe->filename, vfe->filename_len); 971 kmem_free(vfe->filename, vfe->filename_len);
972 rw_destroy(&vfe->lock); 972 rw_destroy(&vfe->lock);
973 kmem_free(vfe, sizeof(*vfe)); 973 kmem_free(vfe, sizeof(*vfe));
974 } 974 }
975} 975}
976 976
977static void 977static void
978veriexec_file_purge(struct veriexec_file_entry *vfe, int have_lock) 978veriexec_file_purge(struct veriexec_file_entry *vfe, int have_lock)
979{ 979{
980 if (vfe == NULL) 980 if (vfe == NULL)
981 return; 981 return;
982 982
983 if (have_lock == VERIEXEC_UNLOCKED) 983 if (have_lock == VERIEXEC_UNLOCKED)
984 rw_enter(&vfe->lock, RW_WRITER); 984 rw_enter(&vfe->lock, RW_WRITER);
985 else 985 else
986 VERIEXEC_RW_UPGRADE(&vfe->lock); 986 VERIEXEC_RW_UPGRADE(&vfe->lock);
987 987
988 vfe->status = FINGERPRINT_NOTEVAL; 988 vfe->status = FINGERPRINT_NOTEVAL;
989 if (have_lock == VERIEXEC_UNLOCKED) 989 if (have_lock == VERIEXEC_UNLOCKED)
990 rw_exit(&vfe->lock); 990 rw_exit(&vfe->lock);
991 else 991 else
992 rw_downgrade(&vfe->lock); 992 rw_downgrade(&vfe->lock);
993} 993}
994 994
995static void 995static void
996veriexec_file_purge_cb(struct veriexec_file_entry *vfe, void *cookie) 996veriexec_file_purge_cb(struct veriexec_file_entry *vfe, void *cookie)
997{ 997{
998 veriexec_file_purge(vfe, VERIEXEC_UNLOCKED); 998 veriexec_file_purge(vfe, VERIEXEC_UNLOCKED);
999} 999}
1000 1000
1001/* 1001/*
1002 * Invalidate a Veriexec file entry. 1002 * Invalidate a Veriexec file entry.
1003 * XXX: This should be updated when per-page fingerprints are added. 1003 * XXX: This should be updated when per-page fingerprints are added.
1004 */ 1004 */
1005void 1005void
1006veriexec_purge(struct vnode *vp) 1006veriexec_purge(struct vnode *vp)
1007{ 1007{
1008 1008
1009 rw_enter(&veriexec_op_lock, RW_READER); 1009 rw_enter(&veriexec_op_lock, RW_READER);
1010 veriexec_file_purge(veriexec_get(vp), VERIEXEC_UNLOCKED); 1010 veriexec_file_purge(veriexec_get(vp), VERIEXEC_UNLOCKED);
1011 rw_exit(&veriexec_op_lock); 1011 rw_exit(&veriexec_op_lock);
1012} 1012}
1013 1013
1014/* 1014/*
1015 * Enforce raw disk access policy. 1015 * Enforce raw disk access policy.
1016 * 1016 *
1017 * IDS mode: Invalidate fingerprints on a mount if it's opened for writing. 1017 * IDS mode: Invalidate fingerprints on a mount if it's opened for writing.
1018 * IPS mode: Don't allow raw writing to disks we monitor. 1018 * IPS mode: Don't allow raw writing to disks we monitor.
1019 * Lockdown mode: Don't allow raw writing to all disks. 1019 * Lockdown mode: Don't allow raw writing to all disks.
1020 * 1020 *
1021 * XXX: This is bogus. There's an obvious race condition between the time 1021 * XXX: This is bogus. There's an obvious race condition between the time
1022 * XXX: the disk is open for writing, in which an attacker can access a 1022 * XXX: the disk is open for writing, in which an attacker can access a
1023 * XXX: monitored file to get its signature cached again, and when the raw 1023 * XXX: monitored file to get its signature cached again, and when the raw
1024 * XXX: file is overwritten on disk. 1024 * XXX: file is overwritten on disk.
1025 * XXX: 1025 * XXX:
1026 * XXX: To solve this, we need something like the following: 1026 * XXX: To solve this, we need something like the following:
1027 * XXX: open raw disk: 1027 * XXX: open raw disk:
1028 * XXX: - raise refcount, 1028 * XXX: - raise refcount,
1029 * XXX: - invalidate fingerprints, 1029 * XXX: - invalidate fingerprints,
1030 * XXX: - mark all entries for that disk with "no cache" flag 1030 * XXX: - mark all entries for that disk with "no cache" flag
1031 * XXX: 1031 * XXX:
1032 * XXX: veriexec_verify: 1032 * XXX: veriexec_verify:
1033 * XXX: - if "no cache", don't cache evaluation result 1033 * XXX: - if "no cache", don't cache evaluation result
1034 * XXX: 1034 * XXX:
1035 * XXX: close raw disk: 1035 * XXX: close raw disk:
1036 * XXX: - lower refcount, 1036 * XXX: - lower refcount,
1037 * XXX: - if refcount == 0, remove "no cache" flag from all entries 1037 * XXX: - if refcount == 0, remove "no cache" flag from all entries
1038 */ 1038 */
1039static int 1039static int
1040veriexec_raw_cb(kauth_cred_t cred, kauth_action_t action, void *cookie, 1040veriexec_raw_cb(kauth_cred_t cred, kauth_action_t action, void *cookie,
1041 void *arg0, void *arg1, void *arg2, void *arg3) 1041 void *arg0, void *arg1, void *arg2, void *arg3)
1042{ 1042{
1043 int result; 1043 int result;
1044 enum kauth_device_req req; 1044 enum kauth_device_req req;
1045 struct veriexec_table_entry *vte; 1045 struct veriexec_table_entry *vte;
1046 1046
1047 result = KAUTH_RESULT_DENY; 1047 result = KAUTH_RESULT_DENY;
1048 req = (enum kauth_device_req)arg0; 1048 req = (enum kauth_device_req)arg0;
1049 1049
1050 switch (action) { 1050 switch (action) {
1051 case KAUTH_DEVICE_RAWIO_SPEC: { 1051 case KAUTH_DEVICE_RAWIO_SPEC: {
1052 struct vnode *vp, *bvp; 1052 struct vnode *vp, *bvp;
1053 int error; 1053 int error;
1054 1054
1055 if (req == KAUTH_REQ_DEVICE_RAWIO_SPEC_READ) { 1055 if (req == KAUTH_REQ_DEVICE_RAWIO_SPEC_READ) {
1056 result = KAUTH_RESULT_DEFER; 1056 result = KAUTH_RESULT_DEFER;
1057 break; 1057 break;
1058 } 1058 }
1059 1059
1060 vp = arg1; 1060 vp = arg1;
1061 KASSERT(vp != NULL); 1061 KASSERT(vp != NULL);
1062 1062
1063 /* Handle /dev/mem and /dev/kmem. */ 1063 /* Handle /dev/mem and /dev/kmem. */
1064 if (iskmemvp(vp)) { 1064 if (iskmemvp(vp)) {
1065 if (veriexec_strict < VERIEXEC_IPS) 1065 if (veriexec_strict < VERIEXEC_IPS)
1066 result = KAUTH_RESULT_DEFER; 1066 result = KAUTH_RESULT_DEFER;
1067 1067
1068 break; 1068 break;
1069 } 1069 }
1070 1070
1071 error = rawdev_mounted(vp, &bvp); 1071 error = rawdev_mounted(vp, &bvp);
1072 if (error == EINVAL) { 1072 if (error == EINVAL) {
1073 result = KAUTH_RESULT_DEFER; 1073 result = KAUTH_RESULT_DEFER;
1074 break; 1074 break;
1075 } 1075 }
1076 1076
1077 /* 1077 /*
1078 * XXX: See vfs_mountedon() comment in rawdev_mounted(). 1078 * XXX: See vfs_mountedon() comment in rawdev_mounted().
1079 */ 1079 */
1080 vte = veriexec_table_lookup(bvp->v_mount); 1080 vte = veriexec_table_lookup(bvp->v_mount);
1081 if (vte == NULL) { 1081 if (vte == NULL) {
1082 result = KAUTH_RESULT_DEFER; 1082 result = KAUTH_RESULT_DEFER;
1083 break; 1083 break;
1084 } 1084 }
1085 1085
1086 switch (veriexec_strict) { 1086 switch (veriexec_strict) {
1087 case VERIEXEC_LEARNING: 1087 case VERIEXEC_LEARNING:
1088 case VERIEXEC_IDS: 1088 case VERIEXEC_IDS:
1089 result = KAUTH_RESULT_DEFER; 1089 result = KAUTH_RESULT_DEFER;
1090 1090
1091 rw_enter(&veriexec_op_lock, RW_WRITER); 1091 rw_enter(&veriexec_op_lock, RW_WRITER);
1092 fileassoc_table_run(bvp->v_mount, veriexec_hook, 1092 fileassoc_table_run(bvp->v_mount, veriexec_hook,
1093 (fileassoc_cb_t)veriexec_file_purge_cb, NULL); 1093 (fileassoc_cb_t)veriexec_file_purge_cb, NULL);
1094 rw_exit(&veriexec_op_lock); 1094 rw_exit(&veriexec_op_lock);
1095 1095
1096 break; 1096 break;
1097 case VERIEXEC_IPS: 1097 case VERIEXEC_IPS:
1098 result = KAUTH_RESULT_DENY; 1098 result = KAUTH_RESULT_DENY;
1099 break; 1099 break;
1100 case VERIEXEC_LOCKDOWN: 1100 case VERIEXEC_LOCKDOWN:
1101 result = KAUTH_RESULT_DENY; 1101 result = KAUTH_RESULT_DENY;
1102 break; 1102 break;
1103 } 1103 }
1104 1104
1105 break; 1105 break;
1106 } 1106 }
1107 1107
1108 case KAUTH_DEVICE_RAWIO_PASSTHRU: 1108 case KAUTH_DEVICE_RAWIO_PASSTHRU:
1109 /* XXX What can we do here? */ 1109 /* XXX What can we do here? */
1110 if (veriexec_strict < VERIEXEC_IPS) 1110 if (veriexec_strict < VERIEXEC_IPS)
1111 result = KAUTH_RESULT_DEFER; 1111 result = KAUTH_RESULT_DEFER;
1112 1112
1113 break; 1113 break;
1114 1114
1115 default: 1115 default:
1116 result = KAUTH_RESULT_DEFER; 1116 result = KAUTH_RESULT_DEFER;
1117 break; 1117 break;
1118 } 1118 }
1119 1119
1120 return (result); 1120 return (result);
1121} 1121}
1122 1122
1123/* 1123/*
1124 * Create a new Veriexec table. 1124 * Create a new Veriexec table.
1125 */ 1125 */
1126static struct veriexec_table_entry * 1126static struct veriexec_table_entry *
1127veriexec_table_add(struct lwp *l, struct mount *mp) 1127veriexec_table_add(struct lwp *l, struct mount *mp)
1128{ 1128{
1129 struct veriexec_table_entry *vte; 1129 struct veriexec_table_entry *vte;
1130 u_char buf[16]; 1130 u_char buf[16];
1131 1131
1132 vte = kmem_zalloc(sizeof(*vte), KM_SLEEP); 1132 vte = kmem_zalloc(sizeof(*vte), KM_SLEEP);
1133 mount_setspecific(mp, veriexec_mountspecific_key, vte); 1133 mount_setspecific(mp, veriexec_mountspecific_key, vte);
1134 1134
1135 snprintf(buf, sizeof(buf), "table%u", veriexec_tablecount++); 1135 snprintf(buf, sizeof(buf), "table%u", veriexec_tablecount++);
1136 sysctl_createv(NULL, 0, &veriexec_count_node, &vte->vte_node, 1136 sysctl_createv(NULL, 0, &veriexec_count_node, &vte->vte_node,
1137 0, CTLTYPE_NODE, buf, NULL, NULL, 0, NULL, 1137 0, CTLTYPE_NODE, buf, NULL, NULL, 0, NULL,
1138 0, CTL_CREATE, CTL_EOL); 1138 0, CTL_CREATE, CTL_EOL);
1139 1139
1140 sysctl_createv(NULL, 0, &vte->vte_node, NULL, 1140 sysctl_createv(NULL, 0, &vte->vte_node, NULL,
1141 CTLFLAG_READONLY, CTLTYPE_STRING, "mntpt", 1141 CTLFLAG_READONLY, CTLTYPE_STRING, "mntpt",
1142 NULL, NULL, 0, mp->mnt_stat.f_mntonname, 1142 NULL, NULL, 0, mp->mnt_stat.f_mntonname,
1143 0, CTL_CREATE, CTL_EOL); 1143 0, CTL_CREATE, CTL_EOL);
1144 sysctl_createv(NULL, 0, &vte->vte_node, NULL, 1144 sysctl_createv(NULL, 0, &vte->vte_node, NULL,
1145 CTLFLAG_READONLY, CTLTYPE_STRING, "fstype", 1145 CTLFLAG_READONLY, CTLTYPE_STRING, "fstype",
1146 NULL, NULL, 0, mp->mnt_stat.f_fstypename, 1146 NULL, NULL, 0, mp->mnt_stat.f_fstypename,
1147 0, CTL_CREATE, CTL_EOL); 1147 0, CTL_CREATE, CTL_EOL);
1148 sysctl_createv(NULL, 0, &vte->vte_node, NULL, 1148 sysctl_createv(NULL, 0, &vte->vte_node, NULL,
1149 CTLFLAG_READONLY, CTLTYPE_QUAD, "nentries", 1149 CTLFLAG_READONLY, CTLTYPE_QUAD, "nentries",
1150 NULL, NULL, 0, &vte->vte_count, 0, CTL_CREATE, CTL_EOL); 1150 NULL, NULL, 0, &vte->vte_count, 0, CTL_CREATE, CTL_EOL);
1151 1151
1152 return (vte); 1152 return (vte);
1153} 1153}
1154 1154
1155/* 1155/*
1156 * Add a file to be monitored by Veriexec. 1156 * Add a file to be monitored by Veriexec.
1157 * 1157 *
1158 * Expected elements in dict: file, fp, fp-type, entry-type. 1158 * Expected elements in dict: file, fp, fp-type, entry-type.
1159 */ 1159 */
1160int 1160int
1161veriexec_file_add(struct lwp *l, prop_dictionary_t dict) 1161veriexec_file_add(struct lwp *l, prop_dictionary_t dict)
1162{ 1162{
1163 struct veriexec_table_entry *vte; 1163 struct veriexec_table_entry *vte;
1164 struct veriexec_file_entry *vfe = NULL, *hh; 1164 struct veriexec_file_entry *vfe = NULL, *hh;
1165 struct vnode *vp; 1165 struct vnode *vp;
1166 const char *file, *fp_type; 1166 const char *file, *fp_type;