1 1.27 riastrad /* $NetBSD: kern_veriexec.c,v 1.27 2023/04/09 09:18:09 riastradh Exp $ */ 2 1.1 maxv 3 1.1 maxv /*- 4 1.1 maxv * Copyright (c) 2005, 2006 Elad Efrat <elad (at) NetBSD.org> 5 1.1 maxv * Copyright (c) 2005, 2006 Brett Lymn <blymn (at) NetBSD.org> 6 1.1 maxv * All rights reserved. 7 1.1 maxv * 8 1.1 maxv * Redistribution and use in source and binary forms, with or without 9 1.1 maxv * modification, are permitted provided that the following conditions 10 1.1 maxv * are met: 11 1.1 maxv * 1. Redistributions of source code must retain the above copyright 12 1.1 maxv * notice, this list of conditions and the following disclaimer. 13 1.1 maxv * 2. Redistributions in binary form must reproduce the above copyright 14 1.1 maxv * notice, this list of conditions and the following disclaimer in the 15 1.1 maxv * documentation and/or other materials provided with the distribution. 16 1.1 maxv * 3. The name of the authors may not be used to endorse or promote products 17 1.1 maxv * derived from this software without specific prior written permission. 18 1.1 maxv * 19 1.1 maxv * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 20 1.1 maxv * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21 1.1 maxv * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22 1.1 maxv * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, 23 1.1 maxv * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 24 1.1 maxv * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 1.1 maxv * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 1.1 maxv * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 1.1 maxv * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 1.1 maxv * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 1.1 maxv */ 30 1.1 maxv 31 1.1 maxv #include <sys/cdefs.h> 32 1.27 riastrad __KERNEL_RCSID(0, "$NetBSD: kern_veriexec.c,v 1.27 2023/04/09 09:18:09 riastradh Exp $"); 33 1.1 maxv 34 1.1 maxv #include "opt_veriexec.h" 35 1.1 maxv 36 1.1 maxv #include <sys/param.h> 37 1.1 maxv #include <sys/mount.h> 38 1.1 maxv #include <sys/kmem.h> 39 1.1 maxv #include <sys/vnode.h> 40 1.1 maxv #include <sys/namei.h> 41 1.1 maxv #include <sys/once.h> 42 1.1 maxv #include <sys/proc.h> 43 1.1 maxv #include <sys/rwlock.h> 44 1.1 maxv #include <sys/syslog.h> 45 1.1 maxv #include <sys/sysctl.h> 46 1.1 maxv #include <sys/inttypes.h> 47 1.1 maxv #include <sys/verified_exec.h> 48 1.7 maxv #include <sys/sha1.h> 49 1.7 maxv #include <sys/sha2.h> 50 1.7 maxv #include <sys/rmd160.h> 51 1.1 maxv #include <sys/md5.h> 52 1.1 maxv #include <sys/fileassoc.h> 53 1.1 maxv #include <sys/kauth.h> 54 1.1 maxv #include <sys/conf.h> 55 1.1 maxv #include <miscfs/specfs/specdev.h> 56 1.1 maxv #include <prop/proplib.h> 57 1.1 maxv #include <sys/fcntl.h> 58 1.1 maxv 59 1.1 maxv /* Readable values for veriexec_file_report(). */ 60 1.1 maxv #define REPORT_ALWAYS 0x01 /* Always print */ 61 1.1 maxv #define REPORT_VERBOSE 0x02 /* Print when verbose >= 1 */ 62 1.1 maxv #define REPORT_DEBUG 0x04 /* Print when verbose >= 2 (debug) */ 63 1.1 maxv #define REPORT_PANIC 0x08 /* Call panic() */ 64 1.1 maxv #define REPORT_ALARM 0x10 /* Alarm - also print pid/uid/.. */ 65 1.1 maxv #define REPORT_LOGMASK (REPORT_ALWAYS|REPORT_VERBOSE|REPORT_DEBUG) 66 1.1 maxv 67 1.1 maxv /* state of locking for veriexec_file_verify */ 68 1.1 maxv #define VERIEXEC_UNLOCKED 0x00 /* Nothing locked, callee does it */ 69 1.1 maxv #define VERIEXEC_LOCKED 0x01 /* Global op lock held */ 70 1.1 maxv 71 1.3 maxv /* state of file locking for veriexec_file_verify */ 72 1.3 maxv #define VERIEXEC_FILE_UNLOCKED 0x02 /* Nothing locked, callee does it */ 73 1.3 maxv #define VERIEXEC_FILE_LOCKED 0x04 /* File locked */ 74 1.1 maxv 75 1.1 maxv #define VERIEXEC_RW_UPGRADE(lock) while((rw_tryupgrade(lock)) == 0){}; 76 1.1 maxv 77 1.1 maxv struct veriexec_fpops { 78 1.1 maxv const char *type; 79 1.1 maxv size_t hash_len; 80 1.1 maxv size_t context_size; 81 1.1 maxv veriexec_fpop_init_t init; 82 1.1 maxv veriexec_fpop_update_t update; 83 1.1 maxv veriexec_fpop_final_t final; 84 1.1 maxv LIST_ENTRY(veriexec_fpops) entries; 85 1.1 maxv }; 86 1.1 maxv 87 1.1 maxv /* Veriexec per-file entry data. */ 88 1.1 maxv struct veriexec_file_entry { 89 1.1 maxv krwlock_t lock; /* r/w lock */ 90 1.1 maxv u_char *filename; /* File name. */ 91 1.1 maxv u_char type; /* Entry type. */ 92 1.1 maxv u_char status; /* Evaluation status. */ 93 1.1 maxv u_char *fp; /* Fingerprint. */ 94 1.1 maxv struct veriexec_fpops *ops; /* Fingerprint ops vector*/ 95 1.1 maxv size_t filename_len; /* Length of filename. */ 96 1.1 maxv }; 97 1.1 maxv 98 1.1 maxv /* Veriexec per-table data. */ 99 1.1 maxv struct veriexec_table_entry { 100 1.1 maxv uint64_t vte_count; /* Number of Veriexec entries. */ 101 1.1 maxv const struct sysctlnode *vte_node; 102 1.1 maxv }; 103 1.1 maxv 104 1.1 maxv static int veriexec_verbose; 105 1.1 maxv static int veriexec_strict; 106 1.1 maxv static int veriexec_bypass = 1; 107 1.1 maxv 108 1.1 maxv static char *veriexec_fp_names = NULL; 109 1.1 maxv static size_t veriexec_name_max = 0; 110 1.1 maxv 111 1.1 maxv static const struct sysctlnode *veriexec_count_node; 112 1.1 maxv 113 1.1 maxv static fileassoc_t veriexec_hook; 114 1.1 maxv static specificdata_key_t veriexec_mountspecific_key; 115 1.1 maxv 116 1.1 maxv static LIST_HEAD(, veriexec_fpops) veriexec_fpops_list = 117 1.1 maxv LIST_HEAD_INITIALIZER(veriexec_fpops_list); 118 1.1 maxv 119 1.1 maxv static int veriexec_raw_cb(kauth_cred_t, kauth_action_t, void *, 120 1.1 maxv void *, void *, void *, void *); 121 1.1 maxv static struct veriexec_fpops *veriexec_fpops_lookup(const char *); 122 1.1 maxv static void veriexec_file_free(struct veriexec_file_entry *); 123 1.1 maxv 124 1.1 maxv static unsigned int veriexec_tablecount = 0; 125 1.1 maxv 126 1.1 maxv /* 127 1.1 maxv * Veriexec operations global lock - most ops hold this as a read 128 1.1 maxv * lock, it is upgraded to a write lock when destroying veriexec file 129 1.1 maxv * table entries. 130 1.1 maxv */ 131 1.1 maxv static krwlock_t veriexec_op_lock; 132 1.1 maxv 133 1.1 maxv /* 134 1.1 maxv * Sysctl helper routine for Veriexec. 135 1.1 maxv */ 136 1.1 maxv static int 137 1.1 maxv sysctl_kern_veriexec_algorithms(SYSCTLFN_ARGS) 138 1.1 maxv { 139 1.1 maxv size_t len; 140 1.1 maxv int error; 141 1.1 maxv const char *p; 142 1.1 maxv 143 1.1 maxv if (newp != NULL) 144 1.1 maxv return EPERM; 145 1.1 maxv 146 1.1 maxv if (namelen != 0) 147 1.1 maxv return EINVAL; 148 1.1 maxv 149 1.1 maxv p = veriexec_fp_names == NULL ? "" : veriexec_fp_names; 150 1.1 maxv 151 1.1 maxv len = strlen(p) + 1; 152 1.1 maxv 153 1.1 maxv if (*oldlenp < len && oldp) 154 1.1 maxv return ENOMEM; 155 1.1 maxv 156 1.1 maxv if (oldp && (error = copyout(p, oldp, len)) != 0) 157 1.1 maxv return error; 158 1.1 maxv 159 1.1 maxv *oldlenp = len; 160 1.1 maxv return 0; 161 1.1 maxv } 162 1.1 maxv 163 1.1 maxv static int 164 1.1 maxv sysctl_kern_veriexec_strict(SYSCTLFN_ARGS) 165 1.1 maxv { 166 1.1 maxv struct sysctlnode node; 167 1.1 maxv int error, newval; 168 1.1 maxv 169 1.1 maxv node = *rnode; 170 1.1 maxv node.sysctl_data = &newval; 171 1.1 maxv 172 1.1 maxv newval = veriexec_strict; 173 1.1 maxv error = sysctl_lookup(SYSCTLFN_CALL(&node)); 174 1.1 maxv if (error || newp == NULL) 175 1.1 maxv return error; 176 1.1 maxv 177 1.1 maxv if (newval < veriexec_strict) 178 1.1 maxv return EPERM; 179 1.1 maxv 180 1.1 maxv veriexec_strict = newval; 181 1.1 maxv 182 1.1 maxv return 0; 183 1.1 maxv } 184 1.1 maxv 185 1.1 maxv SYSCTL_SETUP(sysctl_kern_veriexec_setup, "sysctl kern.veriexec setup") 186 1.1 maxv { 187 1.1 maxv const struct sysctlnode *rnode = NULL; 188 1.1 maxv 189 1.1 maxv sysctl_createv(clog, 0, NULL, &rnode, 190 1.1 maxv CTLFLAG_PERMANENT, 191 1.1 maxv CTLTYPE_NODE, "veriexec", 192 1.1 maxv SYSCTL_DESCR("Veriexec"), 193 1.1 maxv NULL, 0, NULL, 0, 194 1.1 maxv CTL_KERN, CTL_CREATE, CTL_EOL); 195 1.1 maxv 196 1.1 maxv sysctl_createv(clog, 0, &rnode, NULL, 197 1.1 maxv CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 198 1.1 maxv CTLTYPE_INT, "verbose", 199 1.1 maxv SYSCTL_DESCR("Veriexec verbose level"), 200 1.1 maxv NULL, 0, &veriexec_verbose, 0, 201 1.1 maxv CTL_CREATE, CTL_EOL); 202 1.1 maxv sysctl_createv(clog, 0, &rnode, NULL, 203 1.1 maxv CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 204 1.1 maxv CTLTYPE_INT, "strict", 205 1.1 maxv SYSCTL_DESCR("Veriexec strict level"), 206 1.1 maxv sysctl_kern_veriexec_strict, 0, NULL, 0, 207 1.1 maxv CTL_CREATE, CTL_EOL); 208 1.1 maxv sysctl_createv(clog, 0, &rnode, NULL, 209 1.1 maxv CTLFLAG_PERMANENT, 210 1.1 maxv CTLTYPE_STRING, "algorithms", 211 1.1 maxv SYSCTL_DESCR("Veriexec supported hashing " 212 1.1 maxv "algorithms"), 213 1.1 maxv sysctl_kern_veriexec_algorithms, 0, NULL, 0, 214 1.1 maxv CTL_CREATE, CTL_EOL); 215 1.1 maxv sysctl_createv(clog, 0, &rnode, &veriexec_count_node, 216 1.1 maxv CTLFLAG_PERMANENT, 217 1.1 maxv CTLTYPE_NODE, "count", 218 1.1 maxv SYSCTL_DESCR("Number of fingerprints on mount(s)"), 219 1.1 maxv NULL, 0, NULL, 0, 220 1.1 maxv CTL_CREATE, CTL_EOL); 221 1.1 maxv } 222 1.1 maxv 223 1.1 maxv /* 224 1.10 maxv * Add ops to the fingerprint ops vector list. 225 1.1 maxv */ 226 1.1 maxv int 227 1.1 maxv veriexec_fpops_add(const char *fp_type, size_t hash_len, size_t ctx_size, 228 1.1 maxv veriexec_fpop_init_t init, veriexec_fpop_update_t update, 229 1.1 maxv veriexec_fpop_final_t final) 230 1.1 maxv { 231 1.1 maxv struct veriexec_fpops *ops; 232 1.1 maxv 233 1.27 riastrad KASSERT(init != NULL); 234 1.27 riastrad KASSERT(update != NULL); 235 1.27 riastrad KASSERT(final != NULL); 236 1.27 riastrad KASSERT(hash_len != 0); 237 1.27 riastrad KASSERT(ctx_size != 0); 238 1.10 maxv KASSERT(fp_type != NULL); 239 1.1 maxv 240 1.1 maxv if (veriexec_fpops_lookup(fp_type) != NULL) 241 1.1 maxv return (EEXIST); 242 1.1 maxv 243 1.1 maxv ops = kmem_alloc(sizeof(*ops), KM_SLEEP); 244 1.1 maxv ops->type = fp_type; 245 1.1 maxv ops->hash_len = hash_len; 246 1.1 maxv ops->context_size = ctx_size; 247 1.1 maxv ops->init = init; 248 1.1 maxv ops->update = update; 249 1.1 maxv ops->final = final; 250 1.1 maxv 251 1.1 maxv LIST_INSERT_HEAD(&veriexec_fpops_list, ops, entries); 252 1.1 maxv 253 1.1 maxv /* 254 1.1 maxv * If we don't have space for any names, allocate enough for six 255 1.1 maxv * which should be sufficient. (it's also enough for all algorithms 256 1.1 maxv * we can support at the moment) 257 1.1 maxv */ 258 1.1 maxv if (veriexec_fp_names == NULL) { 259 1.1 maxv veriexec_name_max = 64; 260 1.1 maxv veriexec_fp_names = kmem_zalloc(veriexec_name_max, KM_SLEEP); 261 1.1 maxv } 262 1.1 maxv 263 1.1 maxv /* 264 1.1 maxv * If we're running out of space for storing supported algorithms, 265 1.1 maxv * extend the buffer with space for four names. 266 1.1 maxv */ 267 1.1 maxv while (veriexec_name_max - (strlen(veriexec_fp_names) + 1) < 268 1.1 maxv strlen(fp_type)) { 269 1.1 maxv char *newp; 270 1.1 maxv unsigned int new_max; 271 1.1 maxv 272 1.1 maxv /* Add space for four algorithm names. */ 273 1.1 maxv new_max = veriexec_name_max + 64; 274 1.1 maxv newp = kmem_zalloc(new_max, KM_SLEEP); 275 1.1 maxv strlcpy(newp, veriexec_fp_names, new_max); 276 1.1 maxv kmem_free(veriexec_fp_names, veriexec_name_max); 277 1.1 maxv veriexec_fp_names = newp; 278 1.1 maxv veriexec_name_max = new_max; 279 1.1 maxv } 280 1.1 maxv 281 1.1 maxv if (*veriexec_fp_names != '\0') 282 1.1 maxv strlcat(veriexec_fp_names, " ", veriexec_name_max); 283 1.1 maxv 284 1.1 maxv strlcat(veriexec_fp_names, fp_type, veriexec_name_max); 285 1.1 maxv 286 1.1 maxv return (0); 287 1.1 maxv } 288 1.1 maxv 289 1.1 maxv static void 290 1.1 maxv veriexec_mountspecific_dtor(void *v) 291 1.1 maxv { 292 1.1 maxv struct veriexec_table_entry *vte = v; 293 1.1 maxv 294 1.1 maxv if (vte == NULL) { 295 1.1 maxv return; 296 1.1 maxv } 297 1.1 maxv sysctl_free(__UNCONST(vte->vte_node)); 298 1.1 maxv veriexec_tablecount--; 299 1.1 maxv kmem_free(vte, sizeof(*vte)); 300 1.1 maxv } 301 1.1 maxv 302 1.1 maxv static int 303 1.1 maxv veriexec_listener_cb(kauth_cred_t cred, kauth_action_t action, void *cookie, 304 1.1 maxv void *arg0, void *arg1, void *arg2, void *arg3) 305 1.1 maxv { 306 1.1 maxv int result; 307 1.1 maxv enum kauth_system_req req; 308 1.1 maxv 309 1.1 maxv if (action != KAUTH_SYSTEM_VERIEXEC) 310 1.1 maxv return KAUTH_RESULT_DEFER; 311 1.1 maxv 312 1.1 maxv result = KAUTH_RESULT_DEFER; 313 1.23 joerg req = (enum kauth_system_req)(uintptr_t)arg0; 314 1.1 maxv 315 1.1 maxv if (req == KAUTH_REQ_SYSTEM_VERIEXEC_MODIFY && 316 1.1 maxv veriexec_strict > VERIEXEC_LEARNING) { 317 1.1 maxv log(LOG_WARNING, "Veriexec: Strict mode, modifying " 318 1.1 maxv "tables not permitted.\n"); 319 1.1 maxv 320 1.1 maxv result = KAUTH_RESULT_DENY; 321 1.1 maxv } 322 1.1 maxv 323 1.1 maxv return result; 324 1.1 maxv } 325 1.1 maxv 326 1.1 maxv /* 327 1.1 maxv * Initialise Veriexec. 328 1.1 maxv */ 329 1.1 maxv void 330 1.1 maxv veriexec_init(void) 331 1.1 maxv { 332 1.1 maxv int error; 333 1.1 maxv 334 1.1 maxv /* Register a fileassoc for Veriexec. */ 335 1.1 maxv error = fileassoc_register("veriexec", 336 1.1 maxv (fileassoc_cleanup_cb_t)veriexec_file_free, &veriexec_hook); 337 1.1 maxv if (error) 338 1.1 maxv panic("Veriexec: Can't register fileassoc: error=%d", error); 339 1.1 maxv 340 1.1 maxv /* Register listener to handle raw disk access. */ 341 1.1 maxv if (kauth_listen_scope(KAUTH_SCOPE_DEVICE, veriexec_raw_cb, NULL) == 342 1.1 maxv NULL) 343 1.1 maxv panic("Veriexec: Can't listen on device scope"); 344 1.1 maxv 345 1.1 maxv error = mount_specific_key_create(&veriexec_mountspecific_key, 346 1.1 maxv veriexec_mountspecific_dtor); 347 1.1 maxv if (error) 348 1.1 maxv panic("Veriexec: Can't create mountspecific key"); 349 1.1 maxv 350 1.1 maxv if (kauth_listen_scope(KAUTH_SCOPE_SYSTEM, veriexec_listener_cb, 351 1.1 maxv NULL) == NULL) 352 1.1 maxv panic("Veriexec: Can't listen on system scope"); 353 1.1 maxv 354 1.1 maxv rw_init(&veriexec_op_lock); 355 1.1 maxv 356 1.22 christos #define FPOPS_ADD(a, b, c, d, e, f) \ 357 1.22 christos veriexec_fpops_add(a, b, c, \ 358 1.22 christos __FPTRCAST(veriexec_fpop_init_t, d), \ 359 1.22 christos __FPTRCAST(veriexec_fpop_update_t, e), \ 360 1.22 christos __FPTRCAST(veriexec_fpop_final_t, f)) 361 1.1 maxv 362 1.1 maxv #ifdef VERIFIED_EXEC_FP_SHA256 363 1.1 maxv FPOPS_ADD("SHA256", SHA256_DIGEST_LENGTH, sizeof(SHA256_CTX), 364 1.1 maxv SHA256_Init, SHA256_Update, SHA256_Final); 365 1.1 maxv #endif /* VERIFIED_EXEC_FP_SHA256 */ 366 1.1 maxv 367 1.1 maxv #ifdef VERIFIED_EXEC_FP_SHA384 368 1.1 maxv FPOPS_ADD("SHA384", SHA384_DIGEST_LENGTH, sizeof(SHA384_CTX), 369 1.1 maxv SHA384_Init, SHA384_Update, SHA384_Final); 370 1.1 maxv #endif /* VERIFIED_EXEC_FP_SHA384 */ 371 1.1 maxv 372 1.1 maxv #ifdef VERIFIED_EXEC_FP_SHA512 373 1.1 maxv FPOPS_ADD("SHA512", SHA512_DIGEST_LENGTH, sizeof(SHA512_CTX), 374 1.1 maxv SHA512_Init, SHA512_Update, SHA512_Final); 375 1.1 maxv #endif /* VERIFIED_EXEC_FP_SHA512 */ 376 1.1 maxv 377 1.1 maxv #undef FPOPS_ADD 378 1.1 maxv } 379 1.1 maxv 380 1.1 maxv static struct veriexec_fpops * 381 1.1 maxv veriexec_fpops_lookup(const char *name) 382 1.1 maxv { 383 1.1 maxv struct veriexec_fpops *ops; 384 1.1 maxv 385 1.1 maxv if (name == NULL) 386 1.1 maxv return (NULL); 387 1.1 maxv 388 1.1 maxv LIST_FOREACH(ops, &veriexec_fpops_list, entries) { 389 1.1 maxv if (strcasecmp(name, ops->type) == 0) 390 1.1 maxv return (ops); 391 1.1 maxv } 392 1.1 maxv 393 1.1 maxv return (NULL); 394 1.1 maxv } 395 1.1 maxv 396 1.1 maxv /* 397 1.1 maxv * Calculate fingerprint. Information on hash length and routines used is 398 1.1 maxv * extracted from veriexec_hash_list according to the hash type. 399 1.1 maxv * 400 1.1 maxv * NOTE: vfe is assumed to be locked for writing on entry. 401 1.1 maxv */ 402 1.1 maxv static int 403 1.3 maxv veriexec_fp_calc(struct lwp *l, struct vnode *vp, int file_lock_state, 404 1.1 maxv struct veriexec_file_entry *vfe, u_char *fp) 405 1.1 maxv { 406 1.1 maxv struct vattr va; 407 1.10 maxv void *ctx; 408 1.10 maxv u_char *buf; 409 1.1 maxv off_t offset, len; 410 1.10 maxv size_t resid; 411 1.10 maxv int error; 412 1.1 maxv 413 1.8 riastrad KASSERT(file_lock_state != VERIEXEC_LOCKED); 414 1.8 riastrad KASSERT(file_lock_state != VERIEXEC_UNLOCKED); 415 1.3 maxv 416 1.3 maxv if (file_lock_state == VERIEXEC_FILE_UNLOCKED) 417 1.1 maxv vn_lock(vp, LK_SHARED | LK_RETRY); 418 1.1 maxv error = VOP_GETATTR(vp, &va, l->l_cred); 419 1.3 maxv if (file_lock_state == VERIEXEC_FILE_UNLOCKED) 420 1.1 maxv VOP_UNLOCK(vp); 421 1.1 maxv if (error) 422 1.1 maxv return (error); 423 1.1 maxv 424 1.1 maxv ctx = kmem_alloc(vfe->ops->context_size, KM_SLEEP); 425 1.1 maxv buf = kmem_alloc(PAGE_SIZE, KM_SLEEP); 426 1.1 maxv 427 1.1 maxv (vfe->ops->init)(ctx); 428 1.1 maxv 429 1.1 maxv len = 0; 430 1.1 maxv error = 0; 431 1.1 maxv for (offset = 0; offset < va.va_size; offset += PAGE_SIZE) { 432 1.1 maxv len = ((va.va_size - offset) < PAGE_SIZE) ? 433 1.1 maxv (va.va_size - offset) : PAGE_SIZE; 434 1.1 maxv 435 1.1 maxv error = vn_rdwr(UIO_READ, vp, buf, len, offset, 436 1.1 maxv UIO_SYSSPACE, 437 1.3 maxv ((file_lock_state == VERIEXEC_FILE_LOCKED)? 438 1.1 maxv IO_NODELOCKED : 0), 439 1.1 maxv l->l_cred, &resid, NULL); 440 1.1 maxv 441 1.1 maxv if (error) { 442 1.1 maxv goto bad; 443 1.1 maxv } 444 1.1 maxv 445 1.1 maxv (vfe->ops->update)(ctx, buf, (unsigned int) len); 446 1.1 maxv 447 1.1 maxv if (len != PAGE_SIZE) 448 1.1 maxv break; 449 1.1 maxv } 450 1.1 maxv 451 1.1 maxv (vfe->ops->final)(fp, ctx); 452 1.1 maxv 453 1.1 maxv bad: 454 1.1 maxv kmem_free(ctx, vfe->ops->context_size); 455 1.1 maxv kmem_free(buf, PAGE_SIZE); 456 1.1 maxv 457 1.1 maxv return (error); 458 1.1 maxv } 459 1.1 maxv 460 1.1 maxv /* Compare two fingerprints of the same type. */ 461 1.1 maxv static int 462 1.1 maxv veriexec_fp_cmp(struct veriexec_fpops *ops, u_char *fp1, u_char *fp2) 463 1.1 maxv { 464 1.1 maxv if (veriexec_verbose >= 2) { 465 1.1 maxv int i; 466 1.1 maxv 467 1.1 maxv printf("comparing hashes...\n"); 468 1.1 maxv printf("fp1: "); 469 1.1 maxv for (i = 0; i < ops->hash_len; i++) { 470 1.1 maxv printf("%02x", fp1[i]); 471 1.1 maxv } 472 1.1 maxv printf("\nfp2: "); 473 1.1 maxv for (i = 0; i < ops->hash_len; i++) { 474 1.1 maxv printf("%02x", fp2[i]); 475 1.1 maxv } 476 1.1 maxv printf("\n"); 477 1.1 maxv } 478 1.1 maxv 479 1.1 maxv return (memcmp(fp1, fp2, ops->hash_len)); 480 1.1 maxv } 481 1.1 maxv 482 1.4 maxv static int 483 1.4 maxv veriexec_fp_status(struct lwp *l, struct vnode *vp, int file_lock_state, 484 1.4 maxv struct veriexec_file_entry *vfe, u_char *status) 485 1.4 maxv { 486 1.4 maxv size_t hash_len = vfe->ops->hash_len; 487 1.4 maxv u_char *digest; 488 1.9 maxv int error; 489 1.4 maxv 490 1.4 maxv digest = kmem_zalloc(hash_len, KM_SLEEP); 491 1.4 maxv 492 1.4 maxv error = veriexec_fp_calc(l, vp, file_lock_state, vfe, digest); 493 1.4 maxv if (error) 494 1.4 maxv goto out; 495 1.4 maxv 496 1.4 maxv /* Compare fingerprint with loaded data. */ 497 1.4 maxv if (veriexec_fp_cmp(vfe->ops, vfe->fp, digest) == 0) 498 1.4 maxv *status = FINGERPRINT_VALID; 499 1.4 maxv else 500 1.4 maxv *status = FINGERPRINT_NOMATCH; 501 1.4 maxv 502 1.4 maxv out: 503 1.4 maxv kmem_free(digest, hash_len); 504 1.4 maxv return error; 505 1.4 maxv } 506 1.4 maxv 507 1.4 maxv 508 1.1 maxv static struct veriexec_table_entry * 509 1.1 maxv veriexec_table_lookup(struct mount *mp) 510 1.1 maxv { 511 1.1 maxv /* XXX: From raidframe init */ 512 1.1 maxv if (mp == NULL) 513 1.1 maxv return NULL; 514 1.1 maxv 515 1.1 maxv return mount_getspecific(mp, veriexec_mountspecific_key); 516 1.1 maxv } 517 1.1 maxv 518 1.1 maxv static struct veriexec_file_entry * 519 1.1 maxv veriexec_get(struct vnode *vp) 520 1.1 maxv { 521 1.1 maxv return (fileassoc_lookup(vp, veriexec_hook)); 522 1.1 maxv } 523 1.1 maxv 524 1.1 maxv bool 525 1.1 maxv veriexec_lookup(struct vnode *vp) 526 1.1 maxv { 527 1.1 maxv return (veriexec_get(vp) == NULL ? false : true); 528 1.1 maxv } 529 1.1 maxv 530 1.1 maxv /* 531 1.1 maxv * Routine for maintaining mostly consistent message formats in Veriexec. 532 1.1 maxv */ 533 1.1 maxv static void 534 1.1 maxv veriexec_file_report(struct veriexec_file_entry *vfe, const u_char *msg, 535 1.1 maxv const u_char *filename, struct lwp *l, int f) 536 1.1 maxv { 537 1.1 maxv if (vfe != NULL && vfe->filename != NULL) 538 1.1 maxv filename = vfe->filename; 539 1.1 maxv if (filename == NULL) 540 1.1 maxv return; 541 1.1 maxv 542 1.1 maxv if (((f & REPORT_LOGMASK) >> 1) <= veriexec_verbose) { 543 1.1 maxv if (!(f & REPORT_ALARM) || (l == NULL)) 544 1.1 maxv log(LOG_NOTICE, "Veriexec: %s [%s]\n", msg, 545 1.1 maxv filename); 546 1.1 maxv else 547 1.1 maxv log(LOG_ALERT, "Veriexec: %s [%s, prog=%s pid=%u, " 548 1.1 maxv "uid=%u, gid=%u]\n", msg, filename, 549 1.1 maxv l->l_proc->p_comm, l->l_proc->p_pid, 550 1.1 maxv kauth_cred_getuid(l->l_cred), 551 1.1 maxv kauth_cred_getgid(l->l_cred)); 552 1.1 maxv } 553 1.1 maxv 554 1.1 maxv if (f & REPORT_PANIC) 555 1.1 maxv panic("Veriexec: Unrecoverable error."); 556 1.1 maxv } 557 1.1 maxv 558 1.1 maxv /* 559 1.1 maxv * Verify the fingerprint of the given file. If we're called directly from 560 1.1 maxv * sys_execve(), 'flag' will be VERIEXEC_DIRECT. If we're called from 561 1.1 maxv * exec_script(), 'flag' will be VERIEXEC_INDIRECT. If we are called from 562 1.1 maxv * vn_open(), 'flag' will be VERIEXEC_FILE. 563 1.1 maxv * 564 1.3 maxv * 'veriexec_op_lock' must be locked (and remains locked). 565 1.3 maxv * 566 1.1 maxv * NOTE: The veriexec file entry pointer (vfep) will be returned LOCKED 567 1.1 maxv * on no error. 568 1.1 maxv */ 569 1.1 maxv static int 570 1.1 maxv veriexec_file_verify(struct lwp *l, struct vnode *vp, const u_char *name, 571 1.3 maxv int flag, int file_lock_state, struct veriexec_file_entry **vfep) 572 1.1 maxv { 573 1.1 maxv struct veriexec_file_entry *vfe; 574 1.4 maxv int error = 0; 575 1.1 maxv 576 1.3 maxv KASSERT(rw_lock_held(&veriexec_op_lock)); 577 1.8 riastrad KASSERT(file_lock_state != VERIEXEC_LOCKED); 578 1.8 riastrad KASSERT(file_lock_state != VERIEXEC_UNLOCKED); 579 1.3 maxv 580 1.1 maxv #define VFE_NEEDS_EVAL(vfe) ((vfe->status == FINGERPRINT_NOTEVAL) || \ 581 1.1 maxv (vfe->type & VERIEXEC_UNTRUSTED)) 582 1.1 maxv 583 1.1 maxv if (vfep != NULL) 584 1.1 maxv *vfep = NULL; 585 1.1 maxv 586 1.1 maxv if (vp->v_type != VREG) 587 1.1 maxv return (0); 588 1.1 maxv 589 1.1 maxv /* Lookup veriexec table entry, save pointer if requested. */ 590 1.1 maxv vfe = veriexec_get(vp); 591 1.1 maxv if (vfep != NULL) 592 1.1 maxv *vfep = vfe; 593 1.1 maxv 594 1.4 maxv /* No entry in the veriexec tables. */ 595 1.4 maxv if (vfe == NULL) { 596 1.4 maxv veriexec_file_report(NULL, "No entry.", name, 597 1.4 maxv l, REPORT_VERBOSE); 598 1.4 maxv 599 1.4 maxv /* 600 1.4 maxv * Lockdown mode: Deny access to non-monitored files. 601 1.4 maxv * IPS mode: Deny execution of non-monitored files. 602 1.4 maxv */ 603 1.4 maxv if ((veriexec_strict >= VERIEXEC_LOCKDOWN) || 604 1.4 maxv ((veriexec_strict >= VERIEXEC_IPS) && 605 1.4 maxv (flag != VERIEXEC_FILE))) 606 1.4 maxv return (EPERM); 607 1.4 maxv 608 1.4 maxv return (0); 609 1.4 maxv } 610 1.1 maxv 611 1.1 maxv /* 612 1.1 maxv * Grab the lock for the entry, if we need to do an evaluation 613 1.1 maxv * then the lock is a write lock, after we have the write 614 1.1 maxv * lock, check if we really need it - some other thread may 615 1.1 maxv * have already done the work for us. 616 1.1 maxv */ 617 1.1 maxv if (VFE_NEEDS_EVAL(vfe)) { 618 1.1 maxv rw_enter(&vfe->lock, RW_WRITER); 619 1.1 maxv if (!VFE_NEEDS_EVAL(vfe)) 620 1.1 maxv rw_downgrade(&vfe->lock); 621 1.1 maxv } else 622 1.1 maxv rw_enter(&vfe->lock, RW_READER); 623 1.1 maxv 624 1.1 maxv /* Evaluate fingerprint if needed. */ 625 1.1 maxv if (VFE_NEEDS_EVAL(vfe)) { 626 1.4 maxv u_char status; 627 1.1 maxv 628 1.4 maxv error = veriexec_fp_status(l, vp, file_lock_state, vfe, &status); 629 1.1 maxv if (error) { 630 1.1 maxv veriexec_file_report(vfe, "Fingerprint calculation error.", 631 1.1 maxv name, NULL, REPORT_ALWAYS); 632 1.1 maxv rw_exit(&vfe->lock); 633 1.1 maxv return (error); 634 1.1 maxv } 635 1.4 maxv vfe->status = status; 636 1.1 maxv rw_downgrade(&vfe->lock); 637 1.1 maxv } 638 1.1 maxv 639 1.1 maxv if (!(vfe->type & flag)) { 640 1.1 maxv veriexec_file_report(vfe, "Incorrect access type.", name, l, 641 1.1 maxv REPORT_ALWAYS|REPORT_ALARM); 642 1.1 maxv 643 1.1 maxv /* IPS mode: Enforce access type. */ 644 1.1 maxv if (veriexec_strict >= VERIEXEC_IPS) { 645 1.1 maxv rw_exit(&vfe->lock); 646 1.1 maxv return (EPERM); 647 1.1 maxv } 648 1.1 maxv } 649 1.1 maxv 650 1.2 maxv switch (vfe->status) { 651 1.1 maxv case FINGERPRINT_NOTEVAL: 652 1.1 maxv /* Should not happen. */ 653 1.1 maxv rw_exit(&vfe->lock); 654 1.1 maxv veriexec_file_report(vfe, "Not-evaluated status " 655 1.1 maxv "post evaluation; inconsistency detected.", name, 656 1.1 maxv NULL, REPORT_ALWAYS|REPORT_PANIC); 657 1.19 mrg __builtin_unreachable(); 658 1.2 maxv /* NOTREACHED */ 659 1.1 maxv 660 1.1 maxv case FINGERPRINT_VALID: 661 1.1 maxv /* Valid fingerprint. */ 662 1.1 maxv veriexec_file_report(vfe, "Match.", name, NULL, 663 1.1 maxv REPORT_VERBOSE); 664 1.1 maxv 665 1.1 maxv break; 666 1.1 maxv 667 1.1 maxv case FINGERPRINT_NOMATCH: 668 1.1 maxv /* Fingerprint mismatch. */ 669 1.1 maxv veriexec_file_report(vfe, "Mismatch.", name, 670 1.1 maxv NULL, REPORT_ALWAYS|REPORT_ALARM); 671 1.1 maxv 672 1.1 maxv /* IDS mode: Deny access on fingerprint mismatch. */ 673 1.1 maxv if (veriexec_strict >= VERIEXEC_IDS) { 674 1.1 maxv rw_exit(&vfe->lock); 675 1.1 maxv error = EPERM; 676 1.1 maxv } 677 1.1 maxv 678 1.1 maxv break; 679 1.1 maxv 680 1.1 maxv default: 681 1.1 maxv /* Should never happen. */ 682 1.1 maxv rw_exit(&vfe->lock); 683 1.1 maxv veriexec_file_report(vfe, "Invalid status " 684 1.1 maxv "post evaluation.", name, NULL, REPORT_ALWAYS|REPORT_PANIC); 685 1.2 maxv /* NOTREACHED */ 686 1.2 maxv } 687 1.1 maxv 688 1.1 maxv return (error); 689 1.1 maxv } 690 1.1 maxv 691 1.1 maxv int 692 1.1 maxv veriexec_verify(struct lwp *l, struct vnode *vp, const u_char *name, int flag, 693 1.1 maxv bool *found) 694 1.1 maxv { 695 1.1 maxv struct veriexec_file_entry *vfe; 696 1.1 maxv int r; 697 1.1 maxv 698 1.1 maxv if (veriexec_bypass && (veriexec_strict == VERIEXEC_LEARNING)) 699 1.1 maxv return 0; 700 1.1 maxv 701 1.3 maxv rw_enter(&veriexec_op_lock, RW_READER); 702 1.3 maxv r = veriexec_file_verify(l, vp, name, flag, VERIEXEC_FILE_UNLOCKED, 703 1.3 maxv &vfe); 704 1.3 maxv rw_exit(&veriexec_op_lock); 705 1.1 maxv 706 1.1 maxv if ((r == 0) && (vfe != NULL)) 707 1.1 maxv rw_exit(&vfe->lock); 708 1.1 maxv 709 1.1 maxv if (found != NULL) 710 1.1 maxv *found = (vfe != NULL) ? true : false; 711 1.1 maxv 712 1.1 maxv return (r); 713 1.1 maxv } 714 1.1 maxv 715 1.1 maxv /* 716 1.1 maxv * Veriexec remove policy code. 717 1.1 maxv */ 718 1.1 maxv int 719 1.1 maxv veriexec_removechk(struct lwp *l, struct vnode *vp, const char *pathbuf) 720 1.1 maxv { 721 1.1 maxv struct veriexec_file_entry *vfe; 722 1.1 maxv int error; 723 1.1 maxv 724 1.1 maxv if (veriexec_bypass && (veriexec_strict == VERIEXEC_LEARNING)) 725 1.1 maxv return 0; 726 1.1 maxv 727 1.1 maxv rw_enter(&veriexec_op_lock, RW_READER); 728 1.1 maxv vfe = veriexec_get(vp); 729 1.1 maxv rw_exit(&veriexec_op_lock); 730 1.1 maxv 731 1.1 maxv if (vfe == NULL) { 732 1.1 maxv /* Lockdown mode: Deny access to non-monitored files. */ 733 1.1 maxv if (veriexec_strict >= VERIEXEC_LOCKDOWN) 734 1.1 maxv return (EPERM); 735 1.1 maxv 736 1.1 maxv return (0); 737 1.1 maxv } 738 1.1 maxv 739 1.1 maxv veriexec_file_report(vfe, "Remove request.", pathbuf, l, 740 1.1 maxv REPORT_ALWAYS|REPORT_ALARM); 741 1.1 maxv 742 1.1 maxv /* IDS mode: Deny removal of monitored files. */ 743 1.1 maxv if (veriexec_strict >= VERIEXEC_IDS) 744 1.1 maxv error = EPERM; 745 1.1 maxv else 746 1.1 maxv error = veriexec_file_delete(l, vp); 747 1.1 maxv 748 1.1 maxv return error; 749 1.1 maxv } 750 1.1 maxv 751 1.1 maxv /* 752 1.1 maxv * Veriexec rename policy. 753 1.1 maxv * 754 1.1 maxv * XXX: Once there's a way to hook after a successful rename, it would be 755 1.1 maxv * XXX: nice to update vfe->filename to the new name if it's not NULL and 756 1.1 maxv * XXX: the new name is absolute (ie., starts with a slash). 757 1.1 maxv */ 758 1.1 maxv int 759 1.1 maxv veriexec_renamechk(struct lwp *l, struct vnode *fromvp, const char *fromname, 760 1.1 maxv struct vnode *tovp, const char *toname) 761 1.1 maxv { 762 1.5 maxv struct veriexec_file_entry *fvfe = NULL, *tvfe = NULL; 763 1.1 maxv 764 1.1 maxv if (veriexec_bypass && (veriexec_strict == VERIEXEC_LEARNING)) 765 1.1 maxv return 0; 766 1.1 maxv 767 1.1 maxv rw_enter(&veriexec_op_lock, RW_READER); 768 1.1 maxv 769 1.1 maxv if (veriexec_strict >= VERIEXEC_LOCKDOWN) { 770 1.1 maxv log(LOG_ALERT, "Veriexec: Preventing rename of `%s' to " 771 1.1 maxv "`%s', uid=%u, pid=%u: Lockdown mode.\n", fromname, toname, 772 1.1 maxv kauth_cred_geteuid(l->l_cred), l->l_proc->p_pid); 773 1.1 maxv rw_exit(&veriexec_op_lock); 774 1.1 maxv return (EPERM); 775 1.1 maxv } 776 1.1 maxv 777 1.5 maxv fvfe = veriexec_get(fromvp); 778 1.1 maxv if (tovp != NULL) 779 1.1 maxv tvfe = veriexec_get(tovp); 780 1.1 maxv 781 1.5 maxv if ((fvfe == NULL) && (tvfe == NULL)) { 782 1.5 maxv /* None of them is monitored */ 783 1.5 maxv rw_exit(&veriexec_op_lock); 784 1.5 maxv return 0; 785 1.5 maxv } 786 1.1 maxv 787 1.5 maxv if (veriexec_strict >= VERIEXEC_IPS) { 788 1.5 maxv log(LOG_ALERT, "Veriexec: Preventing rename of `%s' " 789 1.5 maxv "to `%s', uid=%u, pid=%u: IPS mode, %s " 790 1.5 maxv "monitored.\n", fromname, toname, 791 1.5 maxv kauth_cred_geteuid(l->l_cred), 792 1.5 maxv l->l_proc->p_pid, (fvfe != NULL && tvfe != NULL) ? 793 1.5 maxv "files" : "file"); 794 1.5 maxv rw_exit(&veriexec_op_lock); 795 1.5 maxv return (EPERM); 796 1.5 maxv } 797 1.1 maxv 798 1.5 maxv if (fvfe != NULL) { 799 1.1 maxv /* 800 1.1 maxv * Monitored file is renamed; filename no longer relevant. 801 1.5 maxv */ 802 1.5 maxv 803 1.5 maxv /* 804 1.1 maxv * XXX: We could keep the buffer, and when (and if) updating the 805 1.1 maxv * XXX: filename post-rename, re-allocate it only if it's not 806 1.1 maxv * XXX: big enough for the new filename. 807 1.1 maxv */ 808 1.1 maxv 809 1.5 maxv /* XXX: Get write lock on fvfe here? */ 810 1.1 maxv 811 1.5 maxv VERIEXEC_RW_UPGRADE(&veriexec_op_lock); 812 1.5 maxv /* once we have the op lock in write mode 813 1.5 maxv * there should be no locks on any file 814 1.5 maxv * entries so we can destroy the object. 815 1.5 maxv */ 816 1.5 maxv 817 1.5 maxv if (fvfe->filename_len > 0) 818 1.5 maxv kmem_free(fvfe->filename, fvfe->filename_len); 819 1.1 maxv 820 1.5 maxv fvfe->filename = NULL; 821 1.5 maxv fvfe->filename_len = 0; 822 1.1 maxv 823 1.5 maxv rw_downgrade(&veriexec_op_lock); 824 1.5 maxv } 825 1.1 maxv 826 1.5 maxv log(LOG_NOTICE, "Veriexec: %s file `%s' renamed to " 827 1.5 maxv "%s file `%s', uid=%u, pid=%u.\n", (fvfe != NULL) ? 828 1.5 maxv "Monitored" : "Non-monitored", fromname, (tvfe != NULL) ? 829 1.5 maxv "monitored" : "non-monitored", toname, 830 1.5 maxv kauth_cred_geteuid(l->l_cred), l->l_proc->p_pid); 831 1.1 maxv 832 1.5 maxv rw_exit(&veriexec_op_lock); 833 1.1 maxv 834 1.5 maxv if (tvfe != NULL) { 835 1.1 maxv /* 836 1.1 maxv * Monitored file is overwritten. Remove the entry. 837 1.1 maxv */ 838 1.5 maxv (void)veriexec_file_delete(l, tovp); 839 1.5 maxv } 840 1.1 maxv 841 1.1 maxv return (0); 842 1.1 maxv } 843 1.1 maxv 844 1.1 maxv static void 845 1.1 maxv veriexec_file_free(struct veriexec_file_entry *vfe) 846 1.1 maxv { 847 1.1 maxv if (vfe != NULL) { 848 1.1 maxv if (vfe->fp != NULL) 849 1.1 maxv kmem_free(vfe->fp, vfe->ops->hash_len); 850 1.1 maxv if (vfe->filename != NULL) 851 1.1 maxv kmem_free(vfe->filename, vfe->filename_len); 852 1.1 maxv rw_destroy(&vfe->lock); 853 1.1 maxv kmem_free(vfe, sizeof(*vfe)); 854 1.1 maxv } 855 1.1 maxv } 856 1.1 maxv 857 1.1 maxv static void 858 1.1 maxv veriexec_file_purge(struct veriexec_file_entry *vfe, int have_lock) 859 1.1 maxv { 860 1.1 maxv if (vfe == NULL) 861 1.1 maxv return; 862 1.1 maxv 863 1.1 maxv if (have_lock == VERIEXEC_UNLOCKED) 864 1.1 maxv rw_enter(&vfe->lock, RW_WRITER); 865 1.1 maxv else 866 1.1 maxv VERIEXEC_RW_UPGRADE(&vfe->lock); 867 1.1 maxv 868 1.1 maxv vfe->status = FINGERPRINT_NOTEVAL; 869 1.1 maxv if (have_lock == VERIEXEC_UNLOCKED) 870 1.1 maxv rw_exit(&vfe->lock); 871 1.1 maxv else 872 1.1 maxv rw_downgrade(&vfe->lock); 873 1.1 maxv } 874 1.1 maxv 875 1.1 maxv static void 876 1.1 maxv veriexec_file_purge_cb(struct veriexec_file_entry *vfe, void *cookie) 877 1.1 maxv { 878 1.1 maxv veriexec_file_purge(vfe, VERIEXEC_UNLOCKED); 879 1.1 maxv } 880 1.1 maxv 881 1.1 maxv /* 882 1.1 maxv * Invalidate a Veriexec file entry. 883 1.1 maxv * XXX: This should be updated when per-page fingerprints are added. 884 1.1 maxv */ 885 1.1 maxv void 886 1.1 maxv veriexec_purge(struct vnode *vp) 887 1.1 maxv { 888 1.1 maxv rw_enter(&veriexec_op_lock, RW_READER); 889 1.1 maxv veriexec_file_purge(veriexec_get(vp), VERIEXEC_UNLOCKED); 890 1.1 maxv rw_exit(&veriexec_op_lock); 891 1.1 maxv } 892 1.1 maxv 893 1.1 maxv /* 894 1.1 maxv * Enforce raw disk access policy. 895 1.1 maxv * 896 1.1 maxv * IDS mode: Invalidate fingerprints on a mount if it's opened for writing. 897 1.1 maxv * IPS mode: Don't allow raw writing to disks we monitor. 898 1.1 maxv * Lockdown mode: Don't allow raw writing to all disks. 899 1.1 maxv * 900 1.1 maxv * XXX: This is bogus. There's an obvious race condition between the time 901 1.1 maxv * XXX: the disk is open for writing, in which an attacker can access a 902 1.1 maxv * XXX: monitored file to get its signature cached again, and when the raw 903 1.1 maxv * XXX: file is overwritten on disk. 904 1.1 maxv * XXX: 905 1.1 maxv * XXX: To solve this, we need something like the following: 906 1.1 maxv * XXX: open raw disk: 907 1.1 maxv * XXX: - raise refcount, 908 1.1 maxv * XXX: - invalidate fingerprints, 909 1.1 maxv * XXX: - mark all entries for that disk with "no cache" flag 910 1.1 maxv * XXX: 911 1.1 maxv * XXX: veriexec_verify: 912 1.1 maxv * XXX: - if "no cache", don't cache evaluation result 913 1.1 maxv * XXX: 914 1.1 maxv * XXX: close raw disk: 915 1.1 maxv * XXX: - lower refcount, 916 1.1 maxv * XXX: - if refcount == 0, remove "no cache" flag from all entries 917 1.1 maxv */ 918 1.1 maxv static int 919 1.1 maxv veriexec_raw_cb(kauth_cred_t cred, kauth_action_t action, void *cookie, 920 1.1 maxv void *arg0, void *arg1, void *arg2, void *arg3) 921 1.1 maxv { 922 1.1 maxv int result; 923 1.1 maxv enum kauth_device_req req; 924 1.1 maxv struct veriexec_table_entry *vte; 925 1.1 maxv 926 1.1 maxv result = KAUTH_RESULT_DENY; 927 1.23 joerg req = (enum kauth_device_req)(uintptr_t)arg0; 928 1.1 maxv 929 1.1 maxv switch (action) { 930 1.1 maxv case KAUTH_DEVICE_RAWIO_SPEC: { 931 1.1 maxv struct vnode *vp, *bvp; 932 1.1 maxv int error; 933 1.1 maxv 934 1.1 maxv if (req == KAUTH_REQ_DEVICE_RAWIO_SPEC_READ) { 935 1.1 maxv result = KAUTH_RESULT_DEFER; 936 1.1 maxv break; 937 1.1 maxv } 938 1.1 maxv 939 1.1 maxv vp = arg1; 940 1.1 maxv KASSERT(vp != NULL); 941 1.1 maxv 942 1.1 maxv /* Handle /dev/mem and /dev/kmem. */ 943 1.1 maxv if (iskmemvp(vp)) { 944 1.1 maxv if (veriexec_strict < VERIEXEC_IPS) 945 1.1 maxv result = KAUTH_RESULT_DEFER; 946 1.1 maxv 947 1.1 maxv break; 948 1.1 maxv } 949 1.1 maxv 950 1.1 maxv error = rawdev_mounted(vp, &bvp); 951 1.1 maxv if (error == EINVAL) { 952 1.1 maxv result = KAUTH_RESULT_DEFER; 953 1.1 maxv break; 954 1.1 maxv } 955 1.1 maxv 956 1.1 maxv /* 957 1.1 maxv * XXX: See vfs_mountedon() comment in rawdev_mounted(). 958 1.1 maxv */ 959 1.1 maxv vte = veriexec_table_lookup(bvp->v_mount); 960 1.1 maxv if (vte == NULL) { 961 1.1 maxv result = KAUTH_RESULT_DEFER; 962 1.1 maxv break; 963 1.1 maxv } 964 1.1 maxv 965 1.1 maxv switch (veriexec_strict) { 966 1.1 maxv case VERIEXEC_LEARNING: 967 1.1 maxv case VERIEXEC_IDS: 968 1.1 maxv result = KAUTH_RESULT_DEFER; 969 1.1 maxv 970 1.1 maxv rw_enter(&veriexec_op_lock, RW_WRITER); 971 1.1 maxv fileassoc_table_run(bvp->v_mount, veriexec_hook, 972 1.1 maxv (fileassoc_cb_t)veriexec_file_purge_cb, NULL); 973 1.1 maxv rw_exit(&veriexec_op_lock); 974 1.1 maxv 975 1.1 maxv break; 976 1.1 maxv case VERIEXEC_IPS: 977 1.1 maxv result = KAUTH_RESULT_DENY; 978 1.1 maxv break; 979 1.1 maxv case VERIEXEC_LOCKDOWN: 980 1.1 maxv result = KAUTH_RESULT_DENY; 981 1.1 maxv break; 982 1.1 maxv } 983 1.1 maxv 984 1.1 maxv break; 985 1.1 maxv } 986 1.1 maxv 987 1.1 maxv case KAUTH_DEVICE_RAWIO_PASSTHRU: 988 1.1 maxv /* XXX What can we do here? */ 989 1.1 maxv if (veriexec_strict < VERIEXEC_IPS) 990 1.1 maxv result = KAUTH_RESULT_DEFER; 991 1.1 maxv 992 1.1 maxv break; 993 1.1 maxv 994 1.1 maxv default: 995 1.1 maxv result = KAUTH_RESULT_DEFER; 996 1.1 maxv break; 997 1.1 maxv } 998 1.1 maxv 999 1.1 maxv return (result); 1000 1.1 maxv } 1001 1.1 maxv 1002 1.1 maxv /* 1003 1.1 maxv * Create a new Veriexec table. 1004 1.1 maxv */ 1005 1.1 maxv static struct veriexec_table_entry * 1006 1.1 maxv veriexec_table_add(struct lwp *l, struct mount *mp) 1007 1.1 maxv { 1008 1.1 maxv struct veriexec_table_entry *vte; 1009 1.1 maxv u_char buf[16]; 1010 1.1 maxv 1011 1.1 maxv vte = kmem_zalloc(sizeof(*vte), KM_SLEEP); 1012 1.1 maxv mount_setspecific(mp, veriexec_mountspecific_key, vte); 1013 1.1 maxv 1014 1.1 maxv snprintf(buf, sizeof(buf), "table%u", veriexec_tablecount++); 1015 1.1 maxv sysctl_createv(NULL, 0, &veriexec_count_node, &vte->vte_node, 1016 1.1 maxv 0, CTLTYPE_NODE, buf, NULL, NULL, 0, NULL, 1017 1.1 maxv 0, CTL_CREATE, CTL_EOL); 1018 1.1 maxv 1019 1.1 maxv sysctl_createv(NULL, 0, &vte->vte_node, NULL, 1020 1.1 maxv CTLFLAG_READONLY, CTLTYPE_STRING, "mntpt", 1021 1.1 maxv NULL, NULL, 0, mp->mnt_stat.f_mntonname, 1022 1.1 maxv 0, CTL_CREATE, CTL_EOL); 1023 1.1 maxv sysctl_createv(NULL, 0, &vte->vte_node, NULL, 1024 1.1 maxv CTLFLAG_READONLY, CTLTYPE_STRING, "fstype", 1025 1.1 maxv NULL, NULL, 0, mp->mnt_stat.f_fstypename, 1026 1.1 maxv 0, CTL_CREATE, CTL_EOL); 1027 1.1 maxv sysctl_createv(NULL, 0, &vte->vte_node, NULL, 1028 1.1 maxv CTLFLAG_READONLY, CTLTYPE_QUAD, "nentries", 1029 1.1 maxv NULL, NULL, 0, &vte->vte_count, 0, CTL_CREATE, CTL_EOL); 1030 1.1 maxv 1031 1.1 maxv return (vte); 1032 1.1 maxv } 1033 1.1 maxv 1034 1.1 maxv /* 1035 1.1 maxv * Add a file to be monitored by Veriexec. 1036 1.1 maxv * 1037 1.20 alnsn * Expected elements in dict: 1038 1.20 alnsn * file, fp, fp-type, entry-type, keep-filename, eval-on-load. 1039 1.1 maxv */ 1040 1.1 maxv int 1041 1.1 maxv veriexec_file_add(struct lwp *l, prop_dictionary_t dict) 1042 1.1 maxv { 1043 1.1 maxv struct veriexec_table_entry *vte; 1044 1.6 maxv struct veriexec_file_entry *vfe = NULL; 1045 1.16 pgoyette struct veriexec_file_entry *ovfe; 1046 1.1 maxv struct vnode *vp; 1047 1.1 maxv const char *file, *fp_type; 1048 1.1 maxv int error; 1049 1.16 pgoyette bool ignore_dup = false; 1050 1.1 maxv 1051 1.26 thorpej if (!prop_dictionary_get_string(dict, "file", &file)) 1052 1.1 maxv return (EINVAL); 1053 1.1 maxv 1054 1.1 maxv error = namei_simple_kernel(file, NSM_FOLLOW_NOEMULROOT, &vp); 1055 1.1 maxv if (error) 1056 1.1 maxv return (error); 1057 1.1 maxv 1058 1.1 maxv /* Add only regular files. */ 1059 1.1 maxv if (vp->v_type != VREG) { 1060 1.1 maxv log(LOG_ERR, "Veriexec: Not adding `%s': Not a regular file.\n", 1061 1.1 maxv file); 1062 1.1 maxv error = EBADF; 1063 1.1 maxv goto out; 1064 1.1 maxv } 1065 1.1 maxv 1066 1.1 maxv vfe = kmem_zalloc(sizeof(*vfe), KM_SLEEP); 1067 1.1 maxv rw_init(&vfe->lock); 1068 1.1 maxv 1069 1.1 maxv /* Lookup fingerprint hashing algorithm. */ 1070 1.25 thorpej fp_type = prop_string_value(prop_dictionary_get(dict, "fp-type")); 1071 1.1 maxv if ((vfe->ops = veriexec_fpops_lookup(fp_type)) == NULL) { 1072 1.1 maxv log(LOG_ERR, "Veriexec: Invalid or unknown fingerprint type " 1073 1.1 maxv "`%s' for file `%s'.\n", fp_type, file); 1074 1.1 maxv error = EOPNOTSUPP; 1075 1.15 pgoyette goto out; 1076 1.1 maxv } 1077 1.1 maxv 1078 1.1 maxv if (prop_data_size(prop_dictionary_get(dict, "fp")) != 1079 1.1 maxv vfe->ops->hash_len) { 1080 1.1 maxv log(LOG_ERR, "Veriexec: Bad fingerprint length for `%s'.\n", 1081 1.1 maxv file); 1082 1.1 maxv error = EINVAL; 1083 1.15 pgoyette goto out; 1084 1.1 maxv } 1085 1.1 maxv 1086 1.1 maxv vfe->fp = kmem_alloc(vfe->ops->hash_len, KM_SLEEP); 1087 1.25 thorpej memcpy(vfe->fp, prop_data_value(prop_dictionary_get(dict, "fp")), 1088 1.1 maxv vfe->ops->hash_len); 1089 1.1 maxv 1090 1.1 maxv rw_enter(&veriexec_op_lock, RW_WRITER); 1091 1.1 maxv 1092 1.1 maxv /* Continue entry initialization. */ 1093 1.1 maxv if (prop_dictionary_get_uint8(dict, "entry-type", &vfe->type) == FALSE) 1094 1.1 maxv vfe->type = 0; 1095 1.1 maxv else { 1096 1.1 maxv uint8_t extra_flags; 1097 1.1 maxv 1098 1.1 maxv extra_flags = vfe->type & ~(VERIEXEC_DIRECT | 1099 1.1 maxv VERIEXEC_INDIRECT | VERIEXEC_FILE | VERIEXEC_UNTRUSTED); 1100 1.1 maxv if (extra_flags) { 1101 1.1 maxv log(LOG_NOTICE, "Veriexec: Contaminated flags `0x%x' " 1102 1.1 maxv "for `%s', skipping.\n", extra_flags, file); 1103 1.1 maxv error = EINVAL; 1104 1.1 maxv goto unlock_out; 1105 1.1 maxv } 1106 1.1 maxv } 1107 1.1 maxv if (!(vfe->type & (VERIEXEC_DIRECT | VERIEXEC_INDIRECT | 1108 1.1 maxv VERIEXEC_FILE))) 1109 1.1 maxv vfe->type |= VERIEXEC_DIRECT; 1110 1.1 maxv 1111 1.1 maxv vfe->status = FINGERPRINT_NOTEVAL; 1112 1.1 maxv if (prop_bool_true(prop_dictionary_get(dict, "keep-filename"))) { 1113 1.18 christos vfe->filename = kmem_strdupsize(file, &vfe->filename_len, 1114 1.18 christos KM_SLEEP); 1115 1.1 maxv } else 1116 1.1 maxv vfe->filename = NULL; 1117 1.1 maxv 1118 1.1 maxv if (prop_bool_true(prop_dictionary_get(dict, "eval-on-load")) || 1119 1.1 maxv (vfe->type & VERIEXEC_UNTRUSTED)) { 1120 1.4 maxv u_char status; 1121 1.1 maxv 1122 1.4 maxv error = veriexec_fp_status(l, vp, VERIEXEC_FILE_UNLOCKED, 1123 1.4 maxv vfe, &status); 1124 1.4 maxv if (error) 1125 1.1 maxv goto unlock_out; 1126 1.4 maxv vfe->status = status; 1127 1.1 maxv } 1128 1.1 maxv 1129 1.16 pgoyette /* 1130 1.16 pgoyette * If we already have an entry for this file, and it matches 1131 1.16 pgoyette * the new entry exactly (except for the filename, which may 1132 1.16 pgoyette * hard-linked!), we just ignore the new entry. If the new 1133 1.16 pgoyette * entry differs, report the error. 1134 1.16 pgoyette */ 1135 1.16 pgoyette if ((ovfe = veriexec_get(vp)) != NULL) { 1136 1.16 pgoyette error = EEXIST; 1137 1.16 pgoyette if (vfe->type == ovfe->type && 1138 1.16 pgoyette vfe->status == ovfe->status && 1139 1.16 pgoyette vfe->ops == ovfe->ops && 1140 1.16 pgoyette memcmp(vfe->fp, ovfe->fp, vfe->ops->hash_len) == 0) 1141 1.16 pgoyette ignore_dup = true; 1142 1.16 pgoyette goto unlock_out; 1143 1.16 pgoyette } 1144 1.16 pgoyette 1145 1.1 maxv vte = veriexec_table_lookup(vp->v_mount); 1146 1.1 maxv if (vte == NULL) 1147 1.1 maxv vte = veriexec_table_add(l, vp->v_mount); 1148 1.1 maxv 1149 1.1 maxv /* XXX if we bail below this, we might want to gc newly created vtes. */ 1150 1.1 maxv 1151 1.1 maxv error = fileassoc_add(vp, veriexec_hook, vfe); 1152 1.1 maxv if (error) 1153 1.1 maxv goto unlock_out; 1154 1.1 maxv 1155 1.1 maxv vte->vte_count++; 1156 1.1 maxv 1157 1.1 maxv veriexec_file_report(NULL, "New entry.", file, NULL, REPORT_DEBUG); 1158 1.1 maxv veriexec_bypass = 0; 1159 1.1 maxv 1160 1.1 maxv unlock_out: 1161 1.1 maxv rw_exit(&veriexec_op_lock); 1162 1.1 maxv 1163 1.1 maxv out: 1164 1.1 maxv vrele(vp); 1165 1.1 maxv if (error) 1166 1.1 maxv veriexec_file_free(vfe); 1167 1.1 maxv 1168 1.16 pgoyette if (ignore_dup && error == EEXIST) 1169 1.16 pgoyette error = 0; 1170 1.16 pgoyette 1171 1.1 maxv return (error); 1172 1.1 maxv } 1173 1.1 maxv 1174 1.1 maxv int 1175 1.5 maxv veriexec_table_delete(struct lwp *l, struct mount *mp) 1176 1.5 maxv { 1177 1.1 maxv struct veriexec_table_entry *vte; 1178 1.1 maxv 1179 1.1 maxv vte = veriexec_table_lookup(mp); 1180 1.1 maxv if (vte == NULL) 1181 1.1 maxv return (ENOENT); 1182 1.1 maxv 1183 1.1 maxv veriexec_mountspecific_dtor(vte); 1184 1.1 maxv mount_setspecific(mp, veriexec_mountspecific_key, NULL); 1185 1.1 maxv 1186 1.1 maxv return (fileassoc_table_clear(mp, veriexec_hook)); 1187 1.1 maxv } 1188 1.1 maxv 1189 1.1 maxv int 1190 1.5 maxv veriexec_file_delete(struct lwp *l, struct vnode *vp) 1191 1.5 maxv { 1192 1.1 maxv struct veriexec_table_entry *vte; 1193 1.1 maxv int error; 1194 1.1 maxv 1195 1.1 maxv vte = veriexec_table_lookup(vp->v_mount); 1196 1.1 maxv if (vte == NULL) 1197 1.1 maxv return (ENOENT); 1198 1.1 maxv 1199 1.1 maxv rw_enter(&veriexec_op_lock, RW_WRITER); 1200 1.1 maxv error = fileassoc_clear(vp, veriexec_hook); 1201 1.1 maxv rw_exit(&veriexec_op_lock); 1202 1.5 maxv if (!error) { 1203 1.5 maxv KASSERT(vte->vte_count > 0); 1204 1.1 maxv vte->vte_count--; 1205 1.5 maxv } 1206 1.1 maxv 1207 1.1 maxv return (error); 1208 1.1 maxv } 1209 1.1 maxv 1210 1.1 maxv /* 1211 1.1 maxv * Convert Veriexec entry data to a dictionary readable by userland tools. 1212 1.1 maxv */ 1213 1.1 maxv static void 1214 1.1 maxv veriexec_file_convert(struct veriexec_file_entry *vfe, prop_dictionary_t rdict) 1215 1.1 maxv { 1216 1.1 maxv if (vfe->filename) 1217 1.1 maxv prop_dictionary_set(rdict, "file", 1218 1.24 thorpej prop_string_create_copy(vfe->filename)); 1219 1.1 maxv prop_dictionary_set_uint8(rdict, "entry-type", vfe->type); 1220 1.1 maxv prop_dictionary_set_uint8(rdict, "status", vfe->status); 1221 1.1 maxv prop_dictionary_set(rdict, "fp-type", 1222 1.24 thorpej prop_string_create_copy(vfe->ops->type)); 1223 1.1 maxv prop_dictionary_set(rdict, "fp", 1224 1.25 thorpej prop_data_create_copy(vfe->fp, vfe->ops->hash_len)); 1225 1.1 maxv } 1226 1.1 maxv 1227 1.1 maxv int 1228 1.1 maxv veriexec_convert(struct vnode *vp, prop_dictionary_t rdict) 1229 1.1 maxv { 1230 1.1 maxv struct veriexec_file_entry *vfe; 1231 1.1 maxv 1232 1.1 maxv rw_enter(&veriexec_op_lock, RW_READER); 1233 1.1 maxv 1234 1.1 maxv vfe = veriexec_get(vp); 1235 1.1 maxv if (vfe == NULL) { 1236 1.1 maxv rw_exit(&veriexec_op_lock); 1237 1.1 maxv return (ENOENT); 1238 1.1 maxv } 1239 1.1 maxv 1240 1.1 maxv rw_enter(&vfe->lock, RW_READER); 1241 1.1 maxv veriexec_file_convert(vfe, rdict); 1242 1.2 maxv rw_exit(&vfe->lock); 1243 1.1 maxv 1244 1.1 maxv rw_exit(&veriexec_op_lock); 1245 1.1 maxv return (0); 1246 1.1 maxv } 1247 1.1 maxv 1248 1.1 maxv int 1249 1.1 maxv veriexec_unmountchk(struct mount *mp) 1250 1.1 maxv { 1251 1.1 maxv int error; 1252 1.1 maxv 1253 1.1 maxv if ((veriexec_bypass && (veriexec_strict == VERIEXEC_LEARNING)) 1254 1.1 maxv || doing_shutdown) 1255 1.1 maxv return (0); 1256 1.1 maxv 1257 1.1 maxv rw_enter(&veriexec_op_lock, RW_READER); 1258 1.1 maxv 1259 1.1 maxv switch (veriexec_strict) { 1260 1.1 maxv case VERIEXEC_LEARNING: 1261 1.1 maxv error = 0; 1262 1.1 maxv break; 1263 1.1 maxv 1264 1.1 maxv case VERIEXEC_IDS: 1265 1.1 maxv if (veriexec_table_lookup(mp) != NULL) { 1266 1.1 maxv log(LOG_INFO, "Veriexec: IDS mode, allowing unmount " 1267 1.1 maxv "of \"%s\".\n", mp->mnt_stat.f_mntonname); 1268 1.1 maxv } 1269 1.1 maxv 1270 1.1 maxv error = 0; 1271 1.1 maxv break; 1272 1.1 maxv 1273 1.1 maxv case VERIEXEC_IPS: { 1274 1.1 maxv struct veriexec_table_entry *vte; 1275 1.1 maxv 1276 1.1 maxv vte = veriexec_table_lookup(mp); 1277 1.1 maxv if ((vte != NULL) && (vte->vte_count > 0)) { 1278 1.1 maxv log(LOG_ALERT, "Veriexec: IPS mode, preventing" 1279 1.1 maxv " unmount of \"%s\" with monitored files.\n", 1280 1.1 maxv mp->mnt_stat.f_mntonname); 1281 1.1 maxv 1282 1.1 maxv error = EPERM; 1283 1.1 maxv } else 1284 1.1 maxv error = 0; 1285 1.1 maxv break; 1286 1.1 maxv } 1287 1.1 maxv 1288 1.1 maxv case VERIEXEC_LOCKDOWN: 1289 1.1 maxv default: 1290 1.1 maxv log(LOG_ALERT, "Veriexec: Lockdown mode, preventing unmount " 1291 1.1 maxv "of \"%s\".\n", mp->mnt_stat.f_mntonname); 1292 1.1 maxv error = EPERM; 1293 1.1 maxv break; 1294 1.1 maxv } 1295 1.1 maxv 1296 1.1 maxv rw_exit(&veriexec_op_lock); 1297 1.1 maxv return (error); 1298 1.1 maxv } 1299 1.1 maxv 1300 1.1 maxv int 1301 1.1 maxv veriexec_openchk(struct lwp *l, struct vnode *vp, const char *path, int fmode) 1302 1.1 maxv { 1303 1.1 maxv struct veriexec_file_entry *vfe = NULL; 1304 1.1 maxv int error = 0; 1305 1.1 maxv 1306 1.1 maxv if (veriexec_bypass && (veriexec_strict == VERIEXEC_LEARNING)) 1307 1.1 maxv return 0; 1308 1.1 maxv 1309 1.1 maxv if (vp == NULL) { 1310 1.1 maxv /* If no creation requested, let this fail normally. */ 1311 1.1 maxv if (!(fmode & O_CREAT)) 1312 1.1 maxv goto out; 1313 1.1 maxv 1314 1.1 maxv /* Lockdown mode: Prevent creation of new files. */ 1315 1.1 maxv if (veriexec_strict >= VERIEXEC_LOCKDOWN) { 1316 1.1 maxv log(LOG_ALERT, "Veriexec: Preventing new file " 1317 1.1 maxv "creation in `%s'.\n", path); 1318 1.1 maxv error = EPERM; 1319 1.1 maxv } 1320 1.1 maxv 1321 1.1 maxv goto out; 1322 1.1 maxv } 1323 1.1 maxv 1324 1.1 maxv rw_enter(&veriexec_op_lock, RW_READER); 1325 1.1 maxv error = veriexec_file_verify(l, vp, path, VERIEXEC_FILE, 1326 1.3 maxv VERIEXEC_FILE_LOCKED, &vfe); 1327 1.1 maxv 1328 1.1 maxv if (error) { 1329 1.1 maxv rw_exit(&veriexec_op_lock); 1330 1.1 maxv goto out; 1331 1.1 maxv } 1332 1.1 maxv 1333 1.1 maxv if ((vfe != NULL) && ((fmode & FWRITE) || (fmode & O_TRUNC))) { 1334 1.1 maxv veriexec_file_report(vfe, "Write access request.", path, l, 1335 1.1 maxv REPORT_ALWAYS | REPORT_ALARM); 1336 1.1 maxv 1337 1.1 maxv /* IPS mode: Deny write access to monitored files. */ 1338 1.1 maxv if (veriexec_strict >= VERIEXEC_IPS) 1339 1.1 maxv error = EPERM; 1340 1.1 maxv else 1341 1.1 maxv veriexec_file_purge(vfe, VERIEXEC_LOCKED); 1342 1.1 maxv } 1343 1.1 maxv 1344 1.1 maxv if (vfe != NULL) 1345 1.1 maxv rw_exit(&vfe->lock); 1346 1.1 maxv 1347 1.1 maxv rw_exit(&veriexec_op_lock); 1348 1.1 maxv out: 1349 1.1 maxv return (error); 1350 1.1 maxv } 1351 1.1 maxv 1352 1.1 maxv static void 1353 1.1 maxv veriexec_file_dump(struct veriexec_file_entry *vfe, prop_array_t entries) 1354 1.1 maxv { 1355 1.1 maxv prop_dictionary_t entry; 1356 1.1 maxv 1357 1.1 maxv /* If we don't have a filename, this is meaningless. */ 1358 1.1 maxv if (vfe->filename == NULL) 1359 1.1 maxv return; 1360 1.1 maxv 1361 1.1 maxv entry = prop_dictionary_create(); 1362 1.1 maxv 1363 1.1 maxv veriexec_file_convert(vfe, entry); 1364 1.1 maxv 1365 1.1 maxv prop_array_add(entries, entry); 1366 1.1 maxv } 1367 1.1 maxv 1368 1.1 maxv int 1369 1.1 maxv veriexec_dump(struct lwp *l, prop_array_t rarray) 1370 1.1 maxv { 1371 1.12 hannken mount_iterator_t *iter; 1372 1.12 hannken struct mount *mp; 1373 1.1 maxv 1374 1.12 hannken mountlist_iterator_init(&iter); 1375 1.12 hannken while ((mp = mountlist_iterator_next(iter)) != NULL) { 1376 1.1 maxv fileassoc_table_run(mp, veriexec_hook, 1377 1.1 maxv (fileassoc_cb_t)veriexec_file_dump, rarray); 1378 1.1 maxv } 1379 1.12 hannken mountlist_iterator_destroy(iter); 1380 1.1 maxv 1381 1.1 maxv return (0); 1382 1.1 maxv } 1383 1.1 maxv 1384 1.1 maxv int 1385 1.1 maxv veriexec_flush(struct lwp *l) 1386 1.1 maxv { 1387 1.12 hannken mount_iterator_t *iter; 1388 1.12 hannken struct mount *mp; 1389 1.1 maxv int error = 0; 1390 1.1 maxv 1391 1.12 hannken mountlist_iterator_init(&iter); 1392 1.12 hannken while ((mp = mountlist_iterator_next(iter)) != NULL) { 1393 1.1 maxv int lerror; 1394 1.1 maxv 1395 1.1 maxv lerror = veriexec_table_delete(l, mp); 1396 1.1 maxv if (lerror && lerror != ENOENT) 1397 1.1 maxv error = lerror; 1398 1.1 maxv } 1399 1.12 hannken mountlist_iterator_destroy(iter); 1400 1.1 maxv 1401 1.1 maxv return (error); 1402 1.1 maxv } 1403