Massive restructuring and cleanup of Veriexec, mainly in preparation

for work on some future functionality.

  - Veriexec data-structures are no longer exposed.

  - Thanks to using proplib for data passing now, the interface
    changes further to accomodate that.

    Introduce four new functions. First, veriexec_file_add(), to add
    a new file to be monitored by Veriexec, to replace both
    veriexec_load() and veriexec_hashadd(). veriexec_table_add(), to
    replace veriexec_newtable(), will be used to optimize hash table
    size (during preload), and finally, veriexec_convert(), to convert
    an internal entry to one userland can read.

  - Introduce veriexec_unmountchk(), to enforce Veriexec unmount
    policy. This cleans up a bit of code in kern/vfs_syscalls.c.

  - Rename veriexec_tblfind() with veriexec_table_lookup(), and make
    it static. More functions that became static: veriexec_fp_cmp(),
    veriexec_fp_calc().

  - veriexec_verify() no longer returns the entry as well, but just
    sets a boolean indicating whether an entry was found or not.

  - veriexec_purge() now takes a struct vnode *.

  - veriexec_add_fp_name() was merged into veriexec_add_fp_ops(), that
    changed its name to veriexec_fpops_add(). veriexec_find_ops() was
    also renamed to veriexec_fpops_lookup().

    Also on the fp-ops front, the three function types used to initialize,
    update, and finalize a hash context were renamed to
    veriexec_fpop_init_t, veriexec_fpop_update_t, and veriexec_fpop_final_t
    respectively.

  - Introduce a new malloc(9) type, M_VERIEXEC, and use it instead of
    M_TEMP, so we can tell exactly how much memory is used by Veriexec.

  - And, most importantly, whitespace and indentation nits.

Built successfuly for amd64, i386, sparc, and sparc64. Tested on amd64.
This commit is contained in:
elad 2006-11-30 01:09:47 +00:00
parent 2abb1c7f9b
commit 0c67c581a5
5 changed files with 465 additions and 479 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: verified_exec.c,v 1.50 2006/11/28 22:22:02 elad Exp $ */
/* $NetBSD: verified_exec.c,v 1.51 2006/11/30 01:09:47 elad Exp $ */
/*-
* Copyright 2005 Elad Efrat <elad@NetBSD.org>
@ -31,17 +31,20 @@
#include <sys/cdefs.h>
#if defined(__NetBSD__)
__KERNEL_RCSID(0, "$NetBSD: verified_exec.c,v 1.50 2006/11/28 22:22:02 elad Exp $");
__KERNEL_RCSID(0, "$NetBSD: verified_exec.c,v 1.51 2006/11/30 01:09:47 elad Exp $");
#else
__RCSID("$Id: verified_exec.c,v 1.50 2006/11/28 22:22:02 elad Exp $\n$NetBSD: verified_exec.c,v 1.50 2006/11/28 22:22:02 elad Exp $");
__RCSID("$Id: verified_exec.c,v 1.51 2006/11/30 01:09:47 elad Exp $\n$NetBSD: verified_exec.c,v 1.51 2006/11/30 01:09:47 elad Exp $");
#endif
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/proc.h>
#include <sys/errno.h>
#include <sys/buf.h>
#include <sys/malloc.h>
#include <sys/conf.h>
#include <sys/vnode.h>
#include <sys/fcntl.h>
#include <sys/namei.h>
#include <sys/verified_exec.h>
#include <sys/kauth.h>
#include <sys/syslog.h>
#ifdef __FreeBSD__
#include <sys/kernel.h>
@ -53,26 +56,8 @@ __RCSID("$Id: verified_exec.c,v 1.50 2006/11/28 22:22:02 elad Exp $\n$NetBSD: ve
#define DEVPORT_DEVICE struct device
#endif
#include <sys/conf.h>
#include <sys/lock.h>
#include <sys/queue.h>
#include <sys/vnode.h>
#include <sys/fcntl.h>
#include <sys/namei.h>
#include <sys/sysctl.h>
#define VERIEXEC_NEED_NODE
#include <sys/verified_exec.h>
#include <sys/kauth.h>
#include <sys/fileassoc.h>
#include <sys/syslog.h>
#include <prop/proplib.h>
/* count of number of times device is open (we really only allow one open) */
static unsigned int veriexec_dev_usage;
static unsigned int veriexec_tablecount = 0;
struct veriexec_softc {
DEVPORT_DEVICE veriexec_dev;
};
@ -108,19 +93,11 @@ const struct cdevsw veriexec_cdevsw = {
#endif
};
/* Autoconfiguration glue */
void veriexecattach(DEVPORT_DEVICE *parent, DEVPORT_DEVICE *self,
void *aux);
int veriexecopen(dev_t dev, int flags, int fmt, struct lwp *l);
int veriexecclose(dev_t dev, int flags, int fmt, struct lwp *l);
int veriexecioctl(dev_t dev, u_long cmd, caddr_t data, int flags,
struct lwp *l);
static int veriexec_newtable(prop_dictionary_t, struct lwp *);
static int veriexec_load(prop_dictionary_t, struct lwp *);
static int veriexec_delete(prop_dictionary_t, struct lwp *);
static int veriexec_query(prop_dictionary_t, prop_dictionary_t, struct lwp *);
/* count of number of times device is open (we really only allow one open) */
static unsigned int veriexec_dev_usage;
void
veriexecattach(DEVPORT_DEVICE *parent, DEVPORT_DEVICE *self,
void *aux)
@ -190,7 +167,7 @@ veriexecioctl(dev_t dev, u_long cmd, caddr_t data, int flags,
if (error)
break;
error = veriexec_newtable(dict, l);
error = veriexec_table_add(l, dict);
prop_object_release(dict);
break;
@ -199,7 +176,7 @@ veriexecioctl(dev_t dev, u_long cmd, caddr_t data, int flags,
if (error)
break;
error = veriexec_load(dict, l);
error = veriexec_file_add(l, dict);
prop_object_release(dict);
break;
@ -208,7 +185,7 @@ veriexecioctl(dev_t dev, u_long cmd, caddr_t data, int flags,
if (error)
break;
error = veriexec_delete(dict, l);
error = veriexec_delete(l, dict);
prop_object_release(dict);
break;
@ -258,186 +235,6 @@ veriexec_drvinit(void *unused)
SYSINIT(veriexec, SI_SUB_PSEUDO, SI_ORDER_ANY, veriexec_drvinit, NULL);
#endif
/*
* Create a new Veriexec table.
*/
static int
veriexec_newtable(prop_dictionary_t dict, struct lwp *l)
{
struct veriexec_table_entry *vte;
struct nameidata nid;
u_char buf[16];
int error;
NDINIT(&nid, LOOKUP, FOLLOW, UIO_SYSSPACE,
prop_string_cstring_nocopy(prop_dictionary_get(dict, "mount")), l);
error = namei(&nid);
if (error)
return (error);
error = fileassoc_table_add(nid.ni_vp->v_mount,
prop_number_integer_value(prop_dictionary_get(dict, "count")));
if (error && (error != EEXIST))
goto out;
vte = malloc(sizeof(*vte), M_TEMP, M_WAITOK | M_ZERO);
error = fileassoc_tabledata_add(nid.ni_vp->v_mount, veriexec_hook, vte);
#ifdef DIAGNOSTIC
if (error)
panic("Fileassoc: Inconsistency after adding table");
#endif /* DIAGNOSTIC */
snprintf(buf, sizeof(buf), "table%u", veriexec_tablecount++);
sysctl_createv(NULL, 0, &veriexec_count_node, &vte->vte_node,
0, CTLTYPE_NODE, buf, NULL, NULL, 0, NULL,
0, CTL_CREATE, CTL_EOL);
sysctl_createv(NULL, 0, &vte->vte_node, NULL,
CTLFLAG_READONLY, CTLTYPE_STRING, "mntpt",
NULL, NULL, 0, nid.ni_vp->v_mount->mnt_stat.f_mntonname,
0, CTL_CREATE, CTL_EOL);
sysctl_createv(NULL, 0, &vte->vte_node, NULL,
CTLFLAG_READONLY, CTLTYPE_STRING, "fstype",
NULL, NULL, 0, nid.ni_vp->v_mount->mnt_stat.f_fstypename,
0, CTL_CREATE, CTL_EOL);
sysctl_createv(NULL, 0, &vte->vte_node, NULL,
CTLFLAG_READONLY, CTLTYPE_QUAD, "nentries",
NULL, NULL, 0, &vte->vte_count, 0, CTL_CREATE, CTL_EOL);
out:
vrele(nid.ni_vp);
return (error);
}
static int
veriexec_load(prop_dictionary_t dict, struct lwp *l)
{
struct veriexec_file_entry *hh, *e;
struct nameidata nid;
const char *file, *fp_type;
int error;
file = prop_string_cstring_nocopy(prop_dictionary_get(dict, "file"));
NDINIT(&nid, LOOKUP, FOLLOW, UIO_SYSSPACE, file, l);
error = namei(&nid);
if (error)
return (error);
/* Add only regular files. */
if (nid.ni_vp->v_type != VREG) {
log(LOG_ERR, "Veriexec: Not adding `%s': Not a regular file.\n",
file);
error = EINVAL;
goto out;
}
e = malloc(sizeof(*e), M_TEMP, M_WAITOK);
fp_type = prop_string_cstring_nocopy(prop_dictionary_get(dict,
"fp-type"));
if ((e->ops = veriexec_find_ops(__UNCONST(fp_type))) == NULL) {
free(e, M_TEMP);
log(LOG_ERR, "Veriexec: Invalid or unknown fingerprint type "
"`%s' for file `%s'.\n", fp_type, file);
error = EINVAL;
goto out;
}
e->fp = prop_data_data(prop_dictionary_get(dict, "fp"));
if (e->fp == NULL) {
free(e, M_TEMP);
goto out;
}
hh = veriexec_lookup(nid.ni_vp);
if (hh != NULL) {
boolean_t fp_mismatch;
if (strcmp(e->ops->type, fp_type) ||
memcmp(hh->fp, e->fp, hh->ops->hash_len))
fp_mismatch = TRUE;
else
fp_mismatch = FALSE;
if ((veriexec_verbose >= 1) || fp_mismatch)
log(LOG_NOTICE, "Veriexec: Duplicate entry for `%s' "
"ignored. (%s fingerprint)\n", file,
fp_mismatch ? "different" : "same");
free(e->fp, M_TEMP);
free(e, M_TEMP);
error = 0;
goto out;
}
e->type = prop_number_integer_value(prop_dictionary_get(dict,
"entry-type"));
e->status = FINGERPRINT_NOTEVAL;
e->page_fp = NULL;
e->page_fp_status = PAGE_FP_NONE;
e->npages = 0;
e->last_page_size = 0;
error = veriexec_hashadd(nid.ni_vp, e);
if (error) {
free(e->fp, M_TEMP);
free(e, M_TEMP);
goto out;
}
veriexec_report("New entry.", file, NULL, REPORT_DEBUG);
out:
vrele(nid.ni_vp);
return (error);
}
static int
veriexec_delete(prop_dictionary_t dict, struct lwp *l)
{
struct veriexec_table_entry *vte;
struct nameidata nid;
int error;
NDINIT(&nid, LOOKUP, FOLLOW, UIO_SYSSPACE,
prop_string_cstring_nocopy(prop_dictionary_get(dict, "file")), l);
error = namei(&nid);
if (error)
return (error);
vte = veriexec_tblfind(nid.ni_vp);
if (vte == NULL) {
error = ENOENT;
goto out;
}
/* XXX this should either receive the filename to remove OR a mount point! */
/* Delete an entire table */
if (nid.ni_vp->v_type == VDIR) {
sysctl_free(__UNCONST(vte->vte_node));
veriexec_tablecount--;
error = fileassoc_table_clear(nid.ni_vp->v_mount, veriexec_hook);
if (error)
goto out;
} else if (nid.ni_vp->v_type == VREG) {
error = fileassoc_clear(nid.ni_vp, veriexec_hook);
if (error)
goto out;
vte->vte_count--;
}
out:
vrele(nid.ni_vp);
return (error);
}
static int
veriexec_query(prop_dictionary_t dict, prop_dictionary_t rdict, struct lwp *l)
{
@ -452,20 +249,12 @@ veriexec_query(prop_dictionary_t dict, prop_dictionary_t rdict, struct lwp *l)
return (error);
vfe = veriexec_lookup(nid.ni_vp);
if (vfe == NULL) {
error = ENOENT;
goto out;
}
prop_dictionary_set_uint8(rdict, "entry-type", vfe->type);
prop_dictionary_set_uint8(rdict, "status", vfe->status);
prop_dictionary_set(rdict, "fp-type",
prop_string_create_cstring(vfe->ops->type));
prop_dictionary_set(rdict, "fp",
prop_data_create_data(vfe->fp, vfe->ops->hash_len));
out:
vrele(nid.ni_vp);
if (vfe != NULL)
veriexec_convert(vfe, rdict);
else
error = ENOENT;
return (error);
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: kern_verifiedexec.c,v 1.74 2006/11/28 22:22:02 elad Exp $ */
/* $NetBSD: kern_verifiedexec.c,v 1.75 2006/11/30 01:09:47 elad Exp $ */
/*-
* Copyright 2005 Elad Efrat <elad@NetBSD.org>
@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: kern_verifiedexec.c,v 1.74 2006/11/28 22:22:02 elad Exp $");
__KERNEL_RCSID(0, "$NetBSD: kern_verifiedexec.c,v 1.75 2006/11/30 01:09:47 elad Exp $");
#include "opt_veriexec.h"
@ -44,7 +44,6 @@ __KERNEL_RCSID(0, "$NetBSD: kern_verifiedexec.c,v 1.74 2006/11/28 22:22:02 elad
#include <sys/syslog.h>
#include <sys/sysctl.h>
#include <sys/inttypes.h>
#define VERIEXEC_NEED_NODE
#include <sys/verified_exec.h>
#if defined(__FreeBSD__)
# include <sys/systm.h>
@ -63,6 +62,37 @@ __KERNEL_RCSID(0, "$NetBSD: kern_verifiedexec.c,v 1.74 2006/11/28 22:22:02 elad
#include <sys/kauth.h>
#include <sys/conf.h>
#include <miscfs/specfs/specdev.h>
#include <prop/proplib.h>
MALLOC_DEFINE(M_VERIEXEC, "Veriexec", "Veriexec data-structures");
struct veriexec_fpops {
const char *type;
size_t hash_len;
size_t context_size;
veriexec_fpop_init_t init;
veriexec_fpop_update_t update;
veriexec_fpop_final_t final;
LIST_ENTRY(veriexec_fpops) entries;
};
/* Veriexec per-file entry data. */
struct veriexec_file_entry {
u_char type; /* Entry type. */
u_char status; /* Evaluation status. */
u_char page_fp_status; /* Per-page FP status. */
u_char *fp; /* Fingerprint. */
void *page_fp; /* Per-page fingerprints */
size_t npages; /* Number of pages. */
size_t last_page_size; /* To support < PAGE_SIZE */
struct veriexec_fpops *ops; /* Fingerprint ops vector*/
};
/* Veriexec per-table data. */
struct veriexec_table_entry {
uint64_t vte_count; /* Number of Veriexec entries. */
const struct sysctlnode *vte_node;
};
int veriexec_verbose;
int veriexec_strict;
@ -74,13 +104,14 @@ const struct sysctlnode *veriexec_count_node;
int veriexec_hook;
/* Veriexecs table of hash types and their associated information. */
LIST_HEAD(veriexec_ops_head, veriexec_fp_ops) veriexec_ops_list;
LIST_HEAD(, veriexec_fpops) veriexec_fpops_list;
static int veriexec_raw_cb(kauth_cred_t, kauth_action_t, void *,
void *, void *, void *, void *);
static int sysctl_kern_veriexec(SYSCTLFN_PROTO);
static unsigned int veriexec_tablecount = 0;
/*
* Sysctl helper routine for Veriexec.
*/
@ -165,16 +196,35 @@ SYSCTL_SETUP(sysctl_security_pax_setup, "sysctl security.pax setup")
}
/*
* Add fingerprint names to the global list.
* Add ops to the fignerprint ops vector list.
*/
static void
veriexec_add_fp_name(const char *name)
int
veriexec_fpops_add(const char *fp_type, size_t hash_len, size_t ctx_size,
veriexec_fpop_init_t init, veriexec_fpop_update_t update,
veriexec_fpop_final_t final)
{
struct veriexec_fpops *ops;
char *newp;
unsigned int new_max;
if (name == NULL)
return;
/* Sanity check all parameters. */
if ((fp_type == NULL) || (hash_len == 0) || (ctx_size == 0) ||
(init == NULL) || (update == NULL) || (final == NULL))
return (EFAULT);
if (veriexec_fpops_lookup(fp_type) != NULL)
return (EEXIST);
ops = malloc(sizeof(*ops), M_VERIEXEC, M_WAITOK);
ops->type = fp_type;
ops->hash_len = hash_len;
ops->context_size = ctx_size;
ops->init = init;
ops->update = update;
ops->final = final;
LIST_INSERT_HEAD(&veriexec_fpops_list, ops, entries);
/*
* If we don't have space for any names, allocate enough for six
@ -183,7 +233,7 @@ veriexec_add_fp_name(const char *name)
*/
if (veriexec_fp_names == NULL) {
veriexec_name_max = 64;
veriexec_fp_names = malloc(veriexec_name_max, M_TEMP,
veriexec_fp_names = malloc(veriexec_name_max, M_VERIEXEC,
M_WAITOK|M_ZERO);
}
@ -192,10 +242,10 @@ veriexec_add_fp_name(const char *name)
* extend the buffer with space for four names.
*/
while (veriexec_name_max - (strlen(veriexec_fp_names) + 1) <
strlen(name)) {
strlen(fp_type)) {
/* Add space for four algorithm names. */
new_max = veriexec_name_max + 64;
newp = realloc(veriexec_fp_names, new_max, M_TEMP,
newp = realloc(veriexec_fp_names, new_max, M_VERIEXEC,
M_WAITOK|M_ZERO);
veriexec_fp_names = newp;
veriexec_name_max = new_max;
@ -204,27 +254,7 @@ veriexec_add_fp_name(const char *name)
if (*veriexec_fp_names != '\0')
strlcat(veriexec_fp_names, " ", veriexec_name_max);
strlcat(veriexec_fp_names, name, veriexec_name_max);
}
/*
* Add ops to the fignerprint ops vector list.
*/
int veriexec_add_fp_ops(struct veriexec_fp_ops *ops)
{
if (ops == NULL)
return (EFAULT);
if ((ops->init == NULL) ||
(ops->update == NULL) ||
(ops->final == NULL))
return (EFAULT);
if (veriexec_find_ops(ops->type) != NULL)
return (EEXIST);
LIST_INSERT_HEAD(&veriexec_ops_list, ops, entries);
veriexec_add_fp_name(ops->type);
strlcat(veriexec_fp_names, fp_type, veriexec_name_max);
return (0);
}
@ -235,8 +265,6 @@ int veriexec_add_fp_ops(struct veriexec_fp_ops *ops)
void
veriexec_init(void)
{
struct veriexec_fp_ops *ops;
/* Register a fileassoc for Veriexec. */
veriexec_hook = fileassoc_register("veriexec", veriexec_clear);
if (veriexec_hook == FILEASSOC_INVAL)
@ -247,68 +275,57 @@ veriexec_init(void)
NULL)
panic("Veriexec: Can't listen on device scope");
LIST_INIT(&veriexec_ops_list);
LIST_INIT(&veriexec_fpops_list);
veriexec_fp_names = NULL;
veriexec_name_max = 0;
#define FPOPS_ADD(a, b, c, d, e, f) \
veriexec_fpops_add(a, b, c, (veriexec_fpop_init_t)d, \
(veriexec_fpop_update_t)e, (veriexec_fpop_final_t)f)
#ifdef VERIFIED_EXEC_FP_RMD160
ops = (struct veriexec_fp_ops *) malloc(sizeof(*ops), M_TEMP, M_WAITOK);
VERIEXEC_OPINIT(ops, "RMD160", RMD160_DIGEST_LENGTH,
sizeof(RMD160_CTX), RMD160Init, RMD160Update,
RMD160Final);
(void) veriexec_add_fp_ops(ops);
FPOPS_ADD("RMD160", RMD160_DIGEST_LENGTH, sizeof(RMD160_CTX),
RMD160Init, RMD160Update, RMD160Final);
#endif /* VERIFIED_EXEC_FP_RMD160 */
#ifdef VERIFIED_EXEC_FP_SHA256
ops = (struct veriexec_fp_ops *) malloc(sizeof(*ops), M_TEMP, M_WAITOK);
VERIEXEC_OPINIT(ops, "SHA256", SHA256_DIGEST_LENGTH,
sizeof(SHA256_CTX), SHA256_Init, SHA256_Update,
SHA256_Final);
(void) veriexec_add_fp_ops(ops);
FPOPS_ADD("SHA256", SHA256_DIGEST_LENGTH, sizeof(SHA256_CTX),
SHA256_Init, SHA256_Update, SHA256_Final);
#endif /* VERIFIED_EXEC_FP_SHA256 */
#ifdef VERIFIED_EXEC_FP_SHA384
ops = (struct veriexec_fp_ops *) malloc(sizeof(*ops), M_TEMP, M_WAITOK);
VERIEXEC_OPINIT(ops, "SHA384", SHA384_DIGEST_LENGTH,
sizeof(SHA384_CTX), SHA384_Init, SHA384_Update,
SHA384_Final);
(void) veriexec_add_fp_ops(ops);
FPOPS_ADD( "SHA384", SHA384_DIGEST_LENGTH, sizeof(SHA384_CTX),
SHA384_Init, SHA384_Update, SHA384_Final);
#endif /* VERIFIED_EXEC_FP_SHA384 */
#ifdef VERIFIED_EXEC_FP_SHA512
ops = (struct veriexec_fp_ops *) malloc(sizeof(*ops), M_TEMP, M_WAITOK);
VERIEXEC_OPINIT(ops, "SHA512", SHA512_DIGEST_LENGTH,
sizeof(SHA512_CTX), SHA512_Init, SHA512_Update,
SHA512_Final);
(void) veriexec_add_fp_ops(ops);
FPOPS_ADD("SHA512", SHA512_DIGEST_LENGTH, sizeof(SHA512_CTX),
SHA512_Init, SHA512_Update, SHA512_Final);
#endif /* VERIFIED_EXEC_FP_SHA512 */
#ifdef VERIFIED_EXEC_FP_SHA1
ops = (struct veriexec_fp_ops *) malloc(sizeof(*ops), M_TEMP, M_WAITOK);
VERIEXEC_OPINIT(ops, "SHA1", SHA1_DIGEST_LENGTH,
sizeof(SHA1_CTX), SHA1Init, SHA1Update,
SHA1Final);
(void) veriexec_add_fp_ops(ops);
FPOPS_ADD("SHA1", SHA1_DIGEST_LENGTH, sizeof(SHA1_CTX),
SHA1Init, SHA1Update, SHA1Final);
#endif /* VERIFIED_EXEC_FP_SHA1 */
#ifdef VERIFIED_EXEC_FP_MD5
ops = (struct veriexec_fp_ops *) malloc(sizeof(*ops), M_TEMP, M_WAITOK);
VERIEXEC_OPINIT(ops, "MD5", MD5_DIGEST_LENGTH, sizeof(MD5_CTX),
MD5Init, MD5Update, MD5Final);
(void) veriexec_add_fp_ops(ops);
FPOPS_ADD("MD5", MD5_DIGEST_LENGTH, sizeof(MD5_CTX),
MD5Init, MD5Update, MD5Final);
#endif /* VERIFIED_EXEC_FP_MD5 */
#undef FPOPS_ADD
}
struct veriexec_fp_ops *
veriexec_find_ops(const char *name)
struct veriexec_fpops *
veriexec_fpops_lookup(const char *name)
{
struct veriexec_fp_ops *ops;
struct veriexec_fpops *ops;
if ((name == NULL) || (strlen(name) == 0))
if (name == NULL)
return (NULL);
LIST_FOREACH(ops, &veriexec_ops_list, entries) {
if (strncasecmp(name, ops->type, sizeof(ops->type) - 1) == 0)
LIST_FOREACH(ops, &veriexec_fpops_list, entries) {
if (strcasecmp(name, ops->type) == 0)
return (ops);
}
@ -319,7 +336,7 @@ veriexec_find_ops(const char *name)
* Calculate fingerprint. Information on hash length and routines used is
* extracted from veriexec_hash_list according to the hash type.
*/
int
static int
veriexec_fp_calc(struct lwp *l, struct vnode *vp,
struct veriexec_file_entry *vfe, u_char *fp)
{
@ -342,8 +359,8 @@ veriexec_fp_calc(struct lwp *l, struct vnode *vp,
#endif
do_perpage = 0;
ctx = (void *) malloc(vfe->ops->context_size, M_TEMP, M_WAITOK);
buf = (u_char *) malloc(PAGE_SIZE, M_TEMP, M_WAITOK);
ctx = (void *) malloc(vfe->ops->context_size, M_VERIEXEC, M_WAITOK);
buf = (u_char *) malloc(PAGE_SIZE, M_VERIEXEC, M_WAITOK);
page_ctx = NULL;
page_fp = NULL;
@ -351,10 +368,10 @@ veriexec_fp_calc(struct lwp *l, struct vnode *vp,
if (do_perpage) {
npages = (va.va_size >> PAGE_SHIFT) + 1;
page_fp = (u_char *) malloc(vfe->ops->hash_len * npages,
M_TEMP, M_WAITOK|M_ZERO);
M_VERIEXEC, M_WAITOK|M_ZERO);
vfe->page_fp = page_fp;
page_ctx = (void *) malloc(vfe->ops->context_size, M_TEMP,
M_WAITOK);
page_ctx = (void *) malloc(vfe->ops->context_size, M_VERIEXEC,
M_WAITOK);
}
(vfe->ops->init)(ctx);
@ -377,7 +394,7 @@ veriexec_fp_calc(struct lwp *l, struct vnode *vp,
if (error) {
if (do_perpage) {
free(vfe->page_fp, M_TEMP);
free(vfe->page_fp, M_VERIEXEC);
vfe->page_fp = NULL;
}
@ -418,16 +435,16 @@ veriexec_fp_calc(struct lwp *l, struct vnode *vp,
bad:
if (do_perpage)
free(page_ctx, M_TEMP);
free(ctx, M_TEMP);
free(buf, M_TEMP);
free(page_ctx, M_VERIEXEC);
free(ctx, M_VERIEXEC);
free(buf, M_VERIEXEC);
return (error);
}
/* Compare two fingerprints of the same type. */
int
veriexec_fp_cmp(struct veriexec_fp_ops *ops, u_char *fp1, u_char *fp2)
static int
veriexec_fp_cmp(struct veriexec_fpops *ops, u_char *fp1, u_char *fp2)
{
if (veriexec_verbose >= 2) {
int i;
@ -447,8 +464,8 @@ veriexec_fp_cmp(struct veriexec_fp_ops *ops, u_char *fp1, u_char *fp2)
return (memcmp(fp1, fp2, ops->hash_len));
}
struct veriexec_table_entry *
veriexec_tblfind(struct vnode *vp)
static struct veriexec_table_entry *
veriexec_table_lookup(struct vnode *vp)
{
return (fileassoc_tabledata_lookup(vp->v_mount, veriexec_hook));
}
@ -459,28 +476,6 @@ veriexec_lookup(struct vnode *vp)
return (fileassoc_lookup(vp, veriexec_hook));
}
/*
* Add an entry to a hash table. If a collision is found, handle it.
* The passed entry is allocated in kernel memory.
*/
int
veriexec_hashadd(struct vnode *vp, struct veriexec_file_entry *vfe)
{
struct veriexec_table_entry *vte;
int error;
error = fileassoc_add(vp, veriexec_hook, vfe);
if (error)
return (error);
vte = veriexec_tblfind(vp);
KASSERT(vte != NULL);
vte->vte_count++;
return (0);
}
/*
* Verify the fingerprint of the given file. If we're called directly from
* sys_execve(), 'flag' will be VERIEXEC_DIRECT. If we're called from
@ -489,7 +484,7 @@ veriexec_hashadd(struct vnode *vp, struct veriexec_file_entry *vfe)
*/
int
veriexec_verify(struct lwp *l, struct vnode *vp, const u_char *name, int flag,
struct veriexec_file_entry **ret)
boolean_t *found)
{
struct veriexec_file_entry *vfe;
u_char *digest;
@ -500,8 +495,12 @@ veriexec_verify(struct lwp *l, struct vnode *vp, const u_char *name, int flag,
/* Lookup veriexec table entry, save pointer if requested. */
vfe = veriexec_lookup(vp);
if (ret != NULL)
*ret = vfe;
if (found != NULL) {
if (vfe != NULL)
*found = TRUE;
else
*found = FALSE;
}
if (vfe == NULL)
goto out;
@ -511,13 +510,13 @@ veriexec_verify(struct lwp *l, struct vnode *vp, const u_char *name, int flag,
if ((vfe->status == FINGERPRINT_NOTEVAL) ||
(vfe->type & VERIEXEC_UNTRUSTED)) {
/* Calculate fingerprint for on-disk file. */
digest = (u_char *) malloc(vfe->ops->hash_len, M_TEMP,
M_WAITOK);
digest = (u_char *) malloc(vfe->ops->hash_len, M_VERIEXEC,
M_WAITOK);
error = veriexec_fp_calc(l, vp, vfe, digest);
if (error) {
veriexec_report("Fingerprint calculation error.",
name, NULL, REPORT_ALWAYS);
free(digest, M_TEMP);
free(digest, M_VERIEXEC);
return (error);
}
@ -528,7 +527,7 @@ veriexec_verify(struct lwp *l, struct vnode *vp, const u_char *name, int flag,
vfe->status = FINGERPRINT_NOMATCH;
}
free(digest, M_TEMP);
free(digest, M_VERIEXEC);
}
if (!(vfe->type & flag)) {
@ -614,8 +613,8 @@ veriexec_page_verify(struct veriexec_file_entry *vfe, struct vm_page *pg,
if (idx >= vfe->npages)
return (0);
ctx = malloc(vfe->ops->context_size, M_TEMP, M_WAITOK);
fp = malloc(vfe->ops->hash_len, M_TEMP, M_WAITOK);
ctx = malloc(vfe->ops->context_size, M_VERIEXEC, M_WAITOK);
fp = malloc(vfe->ops->hash_len, M_VERIEXEC, M_WAITOK);
kva = uvm_km_alloc(kernel_map, PAGE_SIZE, 0, UVM_KMF_VAONLY | UVM_KMF_WAITVA);
pmap_kenter_pa(kva, VM_PAGE_TO_PHYS(pg), VM_PROT_READ);
@ -655,8 +654,8 @@ veriexec_page_verify(struct veriexec_file_entry *vfe, struct vm_page *pg,
}
}
free(ctx, M_TEMP);
free(fp, M_TEMP);
free(ctx, M_VERIEXEC);
free(fp, M_VERIEXEC);
return (error);
}
@ -687,7 +686,7 @@ veriexec_removechk(struct vnode *vp, const char *pathbuf, struct lwp *l)
fileassoc_clear(vp, veriexec_hook);
vte = veriexec_tblfind(vp);
vte = veriexec_table_lookup(vp);
KASSERT(vte != NULL);
vte->vte_count--;
@ -767,16 +766,16 @@ veriexec_clear(void *data, int file_specific)
if (vfe != NULL) {
if (vfe->fp != NULL)
free(vfe->fp, M_TEMP);
free(vfe->fp, M_VERIEXEC);
if (vfe->page_fp != NULL)
free(vfe->page_fp, M_TEMP);
free(vfe, M_TEMP);
free(vfe->page_fp, M_VERIEXEC);
free(vfe, M_VERIEXEC);
}
} else {
struct veriexec_table_entry *vte = data;
if (vte != NULL)
free(vte, M_TEMP);
free(vte, M_VERIEXEC);
}
}
@ -785,8 +784,15 @@ veriexec_clear(void *data, int file_specific)
* XXX: This should be updated when per-page fingerprints are added.
*/
void
veriexec_purge(struct veriexec_file_entry *vfe)
veriexec_purge(struct vnode *vp)
{
struct veriexec_file_entry *vfe;
vfe = veriexec_lookup(vp);
if (vfe == NULL)
return;
vfe->status = FINGERPRINT_NOTEVAL;
}
@ -895,7 +901,7 @@ veriexec_raw_cb(kauth_cred_t cred, kauth_action_t action, void *cookie,
/*
* XXX: See vfs_mountedon() comment in secmodel/bsd44.
*/
vte = veriexec_tblfind(bvp);
vte = veriexec_table_lookup(bvp);
if (vte == NULL) {
result = KAUTH_RESULT_ALLOW;
break;
@ -939,3 +945,260 @@ veriexec_raw_cb(kauth_cred_t cred, kauth_action_t action, void *cookie,
return (result);
}
/*
* Add a file to be monitored by Veriexec.
*
* Expected elements in dict: file, fp, fp-type, entry-type.
*/
int
veriexec_file_add(struct lwp *l, prop_dictionary_t dict)
{
struct veriexec_table_entry *vte;
struct veriexec_file_entry *vfe, *hh;
struct nameidata nid;
const char *file, *fp_type;
int error;
file = prop_string_cstring_nocopy(prop_dictionary_get(dict, "file"));
NDINIT(&nid, LOOKUP, FOLLOW, UIO_SYSSPACE, file, l);
error = namei(&nid);
if (error)
return (error);
/* Add only regular files. */
if (nid.ni_vp->v_type != VREG) {
log(LOG_ERR, "Veriexec: Not adding `%s': Not a regular file.\n",
file);
error = EINVAL;
goto out;
}
vfe = malloc(sizeof(*vfe), M_VERIEXEC, M_WAITOK);
/* Lookup fingerprint hashing algorithm. */
fp_type = prop_string_cstring_nocopy(prop_dictionary_get(dict,
"fp-type"));
if ((vfe->ops = veriexec_fpops_lookup(fp_type)) == NULL) {
free(vfe, M_VERIEXEC);
log(LOG_ERR, "Veriexec: Invalid or unknown fingerprint type "
"`%s' for file `%s'.\n", fp_type, file);
error = EINVAL;
goto out;
}
vfe->fp = prop_data_data(prop_dictionary_get(dict, "fp"));
if (vfe->fp == NULL) {
free(vfe, M_VERIEXEC);
goto out;
}
/*
* See if we already have an entry for this file. If we do, then
* let the user know and silently pretend to succeed.
*/
hh = veriexec_lookup(nid.ni_vp);
if (hh != NULL) {
boolean_t fp_mismatch;
if (strcmp(vfe->ops->type, fp_type) ||
memcmp(hh->fp, vfe->fp, hh->ops->hash_len))
fp_mismatch = TRUE;
else
fp_mismatch = FALSE;
if ((veriexec_verbose >= 1) || fp_mismatch)
log(LOG_NOTICE, "Veriexec: Duplicate entry for `%s' "
"ignored. (%s fingerprint)\n", file,
fp_mismatch ? "different" : "same");
free(vfe->fp, M_VERIEXEC);
free(vfe, M_VERIEXEC);
error = 0;
goto out;
}
/* Continue entry initialization. */
vfe->type = prop_number_integer_value(prop_dictionary_get(dict,
"entry-type"));
vfe->status = FINGERPRINT_NOTEVAL;
vfe->page_fp = NULL;
vfe->page_fp_status = PAGE_FP_NONE;
vfe->npages = 0;
vfe->last_page_size = 0;
error = fileassoc_add(nid.ni_vp, veriexec_hook, vfe);
if (error) {
free(vfe->fp, M_VERIEXEC);
free(vfe, M_VERIEXEC);
goto out;
}
vte = veriexec_table_lookup(nid.ni_vp);
vte->vte_count++;
veriexec_report("New entry.", file, NULL, REPORT_DEBUG);
out:
vrele(nid.ni_vp);
return (error);
}
/*
* Create a new Veriexec table using hints from userland.
*
* Expects dict to have mount and count.
*/
int
veriexec_table_add(struct lwp *l, prop_dictionary_t dict)
{
struct veriexec_table_entry *vte;
struct nameidata nid;
u_char buf[16];
int error;
NDINIT(&nid, LOOKUP, FOLLOW, UIO_SYSSPACE,
prop_string_cstring_nocopy(prop_dictionary_get(dict, "mount")), l);
error = namei(&nid);
if (error)
return (error);
error = fileassoc_table_add(nid.ni_vp->v_mount,
prop_number_integer_value(prop_dictionary_get(dict, "count")));
if (error && (error != EEXIST))
goto out;
vte = malloc(sizeof(*vte), M_VERIEXEC, M_WAITOK | M_ZERO);
error = fileassoc_tabledata_add(nid.ni_vp->v_mount, veriexec_hook, vte);
#ifdef DIAGNOSTIC
if (error)
panic("Fileassoc: Inconsistency after adding table");
#endif /* DIAGNOSTIC */
snprintf(buf, sizeof(buf), "table%u", veriexec_tablecount++);
sysctl_createv(NULL, 0, &veriexec_count_node, &vte->vte_node,
0, CTLTYPE_NODE, buf, NULL, NULL, 0, NULL,
0, CTL_CREATE, CTL_EOL);
sysctl_createv(NULL, 0, &vte->vte_node, NULL,
CTLFLAG_READONLY, CTLTYPE_STRING, "mntpt",
NULL, NULL, 0, nid.ni_vp->v_mount->mnt_stat.f_mntonname,
0, CTL_CREATE, CTL_EOL);
sysctl_createv(NULL, 0, &vte->vte_node, NULL,
CTLFLAG_READONLY, CTLTYPE_STRING, "fstype",
NULL, NULL, 0, nid.ni_vp->v_mount->mnt_stat.f_fstypename,
0, CTL_CREATE, CTL_EOL);
sysctl_createv(NULL, 0, &vte->vte_node, NULL,
CTLFLAG_READONLY, CTLTYPE_QUAD, "nentries",
NULL, NULL, 0, &vte->vte_count, 0, CTL_CREATE, CTL_EOL);
out:
vrele(nid.ni_vp);
return (error);
}
/*
* Remove either a single file from being monitored by Veriexec or an entire
* mount, depending on whether the vnode is for a VREG or a VDIR.
*
* Expects dict to have file.
*/
int
veriexec_delete(struct lwp *l, prop_dictionary_t dict)
{
struct veriexec_table_entry *vte;
struct nameidata nid;
int error;
NDINIT(&nid, LOOKUP, FOLLOW, UIO_SYSSPACE,
prop_string_cstring_nocopy(prop_dictionary_get(dict, "file")), l);
error = namei(&nid);
if (error)
return (error);
vte = veriexec_table_lookup(nid.ni_vp);
if (vte == NULL) {
error = ENOENT;
goto out;
}
/* XXX this should either receive the filename to remove OR a mount point! */
/* Delete an entire table */
if (nid.ni_vp->v_type == VDIR) {
sysctl_free(__UNCONST(vte->vte_node));
veriexec_tablecount--;
error = fileassoc_table_clear(nid.ni_vp->v_mount, veriexec_hook);
if (error)
goto out;
} else if (nid.ni_vp->v_type == VREG) {
error = fileassoc_clear(nid.ni_vp, veriexec_hook);
if (error)
goto out;
vte->vte_count--;
}
out:
vrele(nid.ni_vp);
return (error);
}
/*
* Convert Veriexec entry data to a dictionary readable by userland tools.
*/
void
veriexec_convert(struct veriexec_file_entry *vfe, prop_dictionary_t rdict)
{
prop_dictionary_set_uint8(rdict, "entry-type", vfe->type);
prop_dictionary_set_uint8(rdict, "status", vfe->status);
prop_dictionary_set(rdict, "fp-type",
prop_string_create_cstring(vfe->ops->type));
prop_dictionary_set(rdict, "fp",
prop_data_create_data(vfe->fp, vfe->ops->hash_len));
}
int
veriexec_unmountchk(struct mount *mp)
{
int error;
if (doing_shutdown)
return (0);
switch (veriexec_strict) {
case VERIEXEC_LEARNING:
case VERIEXEC_IDS:
error = 0;
break;
case VERIEXEC_IPS: {
struct veriexec_table_entry *vte;
vte = fileassoc_tabledata_lookup(mp, veriexec_hook);
if ((vte != NULL) && (vte->vte_count > 0)) {
log(LOG_ALERT, "Veriexec: IPS mode, preventing"
" unmount of \"%s\" with monitored files.",
mp->mnt_stat.f_mntonname);
error = EPERM;
} else
error = 0;
break;
}
case VERIEXEC_LOCKDOWN:
default:
log(LOG_ALERT, "Veriexec: Lockdown mode, preventing unmount "
"of \"%s\".\n", mp->mnt_stat.f_mntonname);
error = EPERM;
break;
}
return (0);
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: vfs_syscalls.c,v 1.278 2006/11/21 23:52:41 elad Exp $ */
/* $NetBSD: vfs_syscalls.c,v 1.279 2006/11/30 01:09:48 elad Exp $ */
/*
* Copyright (c) 1989, 1993
@ -37,7 +37,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: vfs_syscalls.c,v 1.278 2006/11/21 23:52:41 elad Exp $");
__KERNEL_RCSID(0, "$NetBSD: vfs_syscalls.c,v 1.279 2006/11/30 01:09:48 elad Exp $");
#include "opt_compat_netbsd.h"
#include "opt_compat_43.h"
@ -551,29 +551,9 @@ dounmount(struct mount *mp, int flags, struct lwp *l)
int used_syncer;
#if NVERIEXEC > 0
if (!doing_shutdown) {
if (veriexec_strict >= VERIEXEC_LOCKDOWN) {
log(LOG_ALERT, "Veriexec: Lockdown mode, "
"preventing unmount of \"%s\". (uid=%u)\n",
mp->mnt_stat.f_mntonname,
kauth_cred_getuid(l->l_cred));
return (EPERM);
}
if (veriexec_strict == VERIEXEC_IPS) {
struct veriexec_table_entry *vte;
/* Check if we have fingerprints on mount. */
vte = fileassoc_tabledata_lookup(mp, veriexec_hook);
if ((vte != NULL) && (vte->vte_count > 0)) {
log(LOG_ALERT, "Veriexec: IPS mode, preventing"
" unmount of \"%s\" with monitored files. "
"(uid=%u)\n", mp->mnt_stat.f_mntonname,
kauth_cred_getuid(l->l_cred));
return (EPERM);
}
}
}
error = veriexec_unmountchk(mp);
if (error)
return (error);
#endif /* NVERIEXEC > 0 */
#ifdef FILEASSOC

View File

@ -1,4 +1,4 @@
/* $NetBSD: vfs_vnops.c,v 1.128 2006/11/01 22:45:14 elad Exp $ */
/* $NetBSD: vfs_vnops.c,v 1.129 2006/11/30 01:09:47 elad Exp $ */
/*
* Copyright (c) 1982, 1986, 1989, 1993
@ -37,7 +37,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: vfs_vnops.c,v 1.128 2006/11/01 22:45:14 elad Exp $");
__KERNEL_RCSID(0, "$NetBSD: vfs_vnops.c,v 1.129 2006/11/30 01:09:47 elad Exp $");
#include "fs_union.h"
#include "veriexec.h"
@ -105,9 +105,9 @@ vn_open(struct nameidata *ndp, int fmode, int cmode)
struct vattr va;
int error;
#if NVERIEXEC > 0
struct veriexec_file_entry *vfe = NULL;
const char *pathbuf;
char *tmppathbuf;
boolean_t veriexec_monitored = FALSE;
#endif /* NVERIEXEC > 0 */
#if NVERIEXEC > 0
@ -208,7 +208,7 @@ restart:
if ((fmode & O_CREAT) == 0) {
#if NVERIEXEC > 0
if ((error = veriexec_verify(l, vp, pathbuf, VERIEXEC_FILE,
&vfe)) != 0)
&veriexec_monitored)) != 0)
goto bad;
#endif /* NVERIEXEC > 0 */
@ -226,7 +226,7 @@ restart:
(error = VOP_ACCESS(vp, VWRITE, cred, l)) != 0)
goto bad;
#if NVERIEXEC > 0
if (vfe != NULL) {
if (veriexec_monitored) {
veriexec_report("Write access request.",
pathbuf, l, REPORT_ALWAYS|REPORT_ALARM);
@ -235,7 +235,7 @@ restart:
error = EPERM;
goto bad;
} else {
veriexec_purge(vfe);
veriexec_purge(vp);
}
}
#endif /* NVERIEXEC > 0 */
@ -245,22 +245,21 @@ restart:
if (fmode & O_TRUNC) {
#if NVERIEXEC > 0
if ((error = veriexec_verify(l, vp, pathbuf, VERIEXEC_FILE,
&vfe)) != 0) {
&veriexec_monitored)) != 0) {
/*VOP_UNLOCK(vp, 0);*/
goto bad;
}
if (vfe != NULL) {
veriexec_report("truncate access request.",
pathbuf, l,
REPORT_VERBOSE | REPORT_ALARM);
if (veriexec_monitored) {
veriexec_report("Truncate access request.", pathbuf, l,
REPORT_VERBOSE | REPORT_ALARM);
/* IPS mode: Deny truncating monitored files. */
if (veriexec_strict >= 2) {
error = EPERM;
goto bad;
} else {
veriexec_purge(vfe);
veriexec_purge(vp);
}
}
#endif /* NVERIEXEC > 0 */

View File

@ -1,4 +1,4 @@
/* $NetBSD: verified_exec.h,v 1.43 2006/11/29 14:52:11 elad Exp $ */
/* $NetBSD: verified_exec.h,v 1.44 2006/11/30 01:09:47 elad Exp $ */
/*-
* Copyright 2005 Elad Efrat <elad@NetBSD.org>
@ -34,12 +34,15 @@
#include <sys/cdefs.h>
#include <sys/param.h>
#include <sys/hash.h>
#include <sys/ioctl.h>
#ifdef _KERNEL
#include <sys/malloc.h>
#include <uvm/uvm_extern.h>
#include <uvm/uvm_pglist.h>
#include <uvm/uvm_page.h>
#include <prop/proplib.h>
#endif /* _KERNEL */
/* Flags for a Veriexec entry. These can be OR'd together. */
#define VERIEXEC_DIRECT 0x01 /* Direct execution (exec) */
@ -53,11 +56,11 @@
#define VERIEXEC_DELETE _IOW('X', 0x3, struct plistref)
#define VERIEXEC_QUERY _IOWR('X', 0x4, struct plistref)
/* Verified exec sysctl objects. */
#define VERIEXEC_VERBOSE 1 /* Verbosity level. */
#define VERIEXEC_STRICT 2 /* Strict mode level. */
#define VERIEXEC_ALGORITHMS 3 /* Supported hashing algorithms. */
#define VERIEXEC_COUNT 4 /* # of fingerprinted files on device. */
/* Veriexec modes (strict levels). */
#define VERIEXEC_LEARNING 0 /* Learning mode. */
#define VERIEXEC_IDS 1 /* Intrusion detection mode. */
#define VERIEXEC_IPS 2 /* Intrusion prevention mode. */
#define VERIEXEC_LOCKDOWN 3 /* Lockdown mode. */
/* Valid status field values. */
#define FINGERPRINT_NOTEVAL 0 /* fingerprint has not been evaluated */
@ -69,64 +72,23 @@
#define PAGE_FP_READY 1 /* per-page fingerprints ready for use. */
#define PAGE_FP_FAIL 2 /* mismatch in per-page fingerprints. */
#ifdef _KERNEL
void veriexecattach(struct device *, struct device *, void *);
int veriexecopen(dev_t, int, int, struct lwp *);
int veriexecclose(dev_t, int, int, struct lwp *);
int veriexecioctl(dev_t, u_long, caddr_t, int, struct lwp *);
/* defined in kern_verifiedexec.c */
extern char *veriexec_fp_names;
extern int veriexec_verbose;
extern int veriexec_strict;
/* this one requires sysctl.h to be included before verified_exec.h */
#ifdef VERIEXEC_NEED_NODE
extern const struct sysctlnode *veriexec_count_node;
#endif /* VERIEXEC_NEED_NODE */
extern int veriexec_hook;
/*
* Operations vector for verified exec, this defines the characteristics
* for the fingerprint type.
* Function types: init, update, final.
*/
typedef void (*VERIEXEC_INIT_FN)(void *);
typedef void (*VERIEXEC_UPDATE_FN)(void *, u_char *, u_int);
typedef void (*VERIEXEC_FINAL_FN)(u_char *, void *);
typedef void (*veriexec_fpop_init_t)(void *);
typedef void (*veriexec_fpop_update_t)(void *, u_char *, u_int);
typedef void (*veriexec_fpop_final_t)(u_char *, void *);
struct veriexec_fp_ops {
const char *type;
size_t hash_len;
size_t context_size;
VERIEXEC_INIT_FN init;
VERIEXEC_UPDATE_FN update;
VERIEXEC_FINAL_FN final;
LIST_ENTRY(veriexec_fp_ops) entries;
};
#ifdef _KERNEL
MALLOC_DECLARE(M_VERIEXEC);
/* Veriexec per-file entry data. */
struct veriexec_file_entry {
u_char type; /* Entry type. */
u_char status; /* Evaluation status. */
u_char page_fp_status; /* Per-page FP status. */
u_char *fp; /* Fingerprint. */
void *page_fp; /* Per-page fingerprints */
size_t npages; /* Number of pages. */
size_t last_page_size; /* To support < PAGE_SIZE */
struct veriexec_fp_ops *ops; /* Fingerprint ops vector*/
};
struct veriexec_file_entry;
struct veriexec_table_entry;
/* Veriexec per-table data. */
struct veriexec_table_entry {
uint64_t vte_count; /* Number of Veriexec entries. */
const struct sysctlnode *vte_node;
};
/* Veriexec modes (strict levels). */
#define VERIEXEC_LEARNING 0 /* Learning mode. */
#define VERIEXEC_IDS 1 /* Intrusion detection mode. */
#define VERIEXEC_IPS 2 /* Intrusion prevention mode. */
#define VERIEXEC_LOCKDOWN 3 /* Lockdown mode. */
extern int veriexec_verbose;
extern int veriexec_strict;
/* Readable values for veriexec_report(). */
#define REPORT_ALWAYS 0x01 /* Always print */
@ -136,38 +98,31 @@ struct veriexec_table_entry {
#define REPORT_ALARM 0x10 /* Alarm - also print pid/uid/.. */
#define REPORT_LOGMASK (REPORT_ALWAYS|REPORT_VERBOSE|REPORT_DEBUG)
/* Initialize a fingerprint ops struct. */
#define VERIEXEC_OPINIT(ops, fp_type, hashlen, ctx_size, init_fn, \
update_fn, final_fn) \
do { \
(ops)->type = fp_type; \
(ops)->hash_len = (hashlen); \
(ops)->context_size = (ctx_size); \
(ops)->init = (VERIEXEC_INIT_FN) (init_fn); \
(ops)->update = (VERIEXEC_UPDATE_FN) (update_fn); \
(ops)->final = (VERIEXEC_FINAL_FN) (final_fn); \
} while (0);
void veriexecattach(struct device *, struct device *, void *);
int veriexecopen(dev_t, int, int, struct lwp *);
int veriexecclose(dev_t, int, int, struct lwp *);
int veriexecioctl(dev_t, u_long, caddr_t, int, struct lwp *);
int veriexec_add_fp_ops(struct veriexec_fp_ops *);
void veriexec_init(void);
struct veriexec_fp_ops *veriexec_find_ops(const char *name);
int veriexec_fp_calc(struct lwp *, struct vnode *, struct veriexec_file_entry *,
u_char *);
int veriexec_fp_cmp(struct veriexec_fp_ops *, u_char *, u_char *);
struct veriexec_table_entry *veriexec_tblfind(struct vnode *);
int veriexec_fpops_add(const char *, size_t, size_t, veriexec_fpop_init_t,
veriexec_fpop_update_t, veriexec_fpop_final_t);
struct veriexec_fpops *veriexec_fpops_lookup(const char *);
int veriexec_table_add(struct lwp *, prop_dictionary_t);
int veriexec_file_add(struct lwp *, prop_dictionary_t);
int veriexec_verify(struct lwp *, struct vnode *, const u_char *, int,
boolean_t *);
struct veriexec_file_entry *veriexec_lookup(struct vnode *);
int veriexec_hashadd(struct vnode *, struct veriexec_file_entry *);
int veriexec_verify(struct lwp *, struct vnode *,
const u_char *, int, struct veriexec_file_entry **);
int veriexec_page_verify(struct veriexec_file_entry *, struct vm_page *, size_t,
struct lwp *);
int veriexec_delete(struct lwp *, prop_dictionary_t);
void veriexec_convert(struct veriexec_file_entry *, prop_dictionary_t);
void veriexec_report(const u_char *, const u_char *, struct lwp *, int);
void veriexec_clear(void *, int);
void veriexec_purge(struct vnode *);
int veriexec_page_verify(struct veriexec_file_entry *, struct vm_page *,
size_t, struct lwp *);
int veriexec_removechk(struct vnode *, const char *, struct lwp *l);
int veriexec_renamechk(struct vnode *, const char *, struct vnode *,
const char *, struct lwp *);
void veriexec_report(const u_char *, const u_char *, struct lwp *, int);
void veriexec_clear(void *, int);
void veriexec_purge(struct veriexec_file_entry *);
int veriexec_unmountchk(struct mount *);
#endif /* _KERNEL */
#endif /* !_SYS_VERIFIED_EXEC_H_ */