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