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