- Avoid pollution of struct vnode. Save the fingerprint evaluation status

in the veriexec table entry; the lookups are very cheap now. Suggested
  by Chuq.

- Handle non-regular (!VREG) files correctly).

- Remove (no longer needed) FINGERPRINT_NOENTRY.
This commit is contained in:
elad 2005-06-19 18:22:36 +00:00
parent 3d0edb52b9
commit c3caa55d4d
6 changed files with 71 additions and 93 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: verified_exec.c,v 1.15 2005/06/17 17:46:18 elad Exp $ */
/* $NetBSD: verified_exec.c,v 1.16 2005/06/19 18:22:36 elad Exp $ */
/*-
* Copyright 2005 Elad Efrat <elad@bsd.org.il>
@ -31,9 +31,9 @@
#include <sys/cdefs.h>
#if defined(__NetBSD__)
__KERNEL_RCSID(0, "$NetBSD: verified_exec.c,v 1.15 2005/06/17 17:46:18 elad Exp $");
__KERNEL_RCSID(0, "$NetBSD: verified_exec.c,v 1.16 2005/06/19 18:22:36 elad Exp $");
#else
__RCSID("$Id: verified_exec.c,v 1.15 2005/06/17 17:46:18 elad Exp $\n$NetBSD: verified_exec.c,v 1.15 2005/06/17 17:46:18 elad Exp $");
__RCSID("$Id: verified_exec.c,v 1.16 2005/06/19 18:22:36 elad Exp $\n$NetBSD: verified_exec.c,v 1.16 2005/06/19 18:22:36 elad Exp $");
#endif
#include <sys/param.h>
@ -215,8 +215,6 @@ veriexecioctl(dev_t dev __unused, u_long cmd, caddr_t data,
return (EINVAL);
}
nid.ni_vp->fp_status = FINGERPRINT_NOTEVAL;
/* Get attributes for device and inode. */
error = VOP_GETATTR(nid.ni_vp, &va, p->p_ucred, p);
if (error)
@ -267,6 +265,7 @@ veriexecioctl(dev_t dev __unused, u_long cmd, caddr_t data,
e = malloc(sizeof(*e), M_TEMP, M_WAITOK);
e->inode = va.va_fileid;
e->type = params->type;
e->status = FINGERPRINT_NOTEVAL;
if ((e->ops = veriexec_find_ops(params->fp_type)) == NULL) {
free(e, M_TEMP);
printf("Veriexec: veriexecioctl: Invalid or unknown "
@ -276,14 +275,14 @@ veriexecioctl(dev_t dev __unused, u_long cmd, caddr_t data,
return(EINVAL);
}
/*
* Just a bit of a sanity check - require the size of
* the fp to be passed in, check this against the expected
* size. Of course userland could lie deliberately, this
* really only protects against the obvious fumble of
* changing the fp type but not updating the fingerprint
* string.
*/
/*
* Just a bit of a sanity check - require the size of
* the fp to be passed in, check this against the expected
* size. Of course userland could lie deliberately, this
* really only protects against the obvious fumble of
* changing the fp type but not updating the fingerprint
* string.
*/
if (e->ops->hash_len != params->size) {
printf("Veriexec: veriexecioctl: Inconsistent "
"fingerprint size for type \"%s\" for file "

View File

@ -1,4 +1,4 @@
/* $NetBSD: kern_verifiedexec.c,v 1.27 2005/06/17 22:39:08 elad Exp $ */
/* $NetBSD: kern_verifiedexec.c,v 1.28 2005/06/19 18:22:36 elad Exp $ */
/*-
* Copyright 2005 Elad Efrat <elad@bsd.org.il>
@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: kern_verifiedexec.c,v 1.27 2005/06/17 22:39:08 elad Exp $");
__KERNEL_RCSID(0, "$NetBSD: kern_verifiedexec.c,v 1.28 2005/06/19 18:22:36 elad Exp $");
#include <sys/param.h>
#include <sys/mount.h>
@ -351,47 +351,46 @@ veriexec_hashadd(struct veriexec_hashtbl *tbl, struct veriexec_hash_entry *e)
*/
int
veriexec_verify(struct proc *p, struct vnode *vp, struct vattr *va,
const u_char *name, int flag)
const u_char *name, int flag, struct veriexec_hash_entry **ret)
{
u_char *digest;
struct veriexec_hash_entry *vhe = NULL;
u_char *digest = NULL;
int error = 0;
/* Evaluate fingerprint if needed and set the status on the vp. */
if (vp->fp_status == FINGERPRINT_NOTEVAL) {
if ((vp->v_type != VREG) || (vp->vhe =
veriexec_lookup(va->va_fsid, va->va_fileid)) == NULL) {
vp->fp_status = FINGERPRINT_NOENTRY;
goto out;
}
/* XXXEE Ignore non-VREG files. */
if (vp->v_type != VREG)
return (0);
veriexec_dprintf(("veriexec: veriexec_verify: Got entry for "
"%s. (dev=%d, inode=%u)\n", name,
va->va_fsid, va->va_fileid));
/* Lookup veriexec table entry, save pointer if requested. */
vhe = veriexec_lookup(va->va_fsid, va->va_fileid);
if (ret != NULL)
*ret = vhe;
if (vhe == NULL)
goto out;
digest = (u_char *) malloc(vp->vhe->ops->hash_len, M_TEMP,
/* Evaluate fingerprint if needed. */
if (vhe->status == FINGERPRINT_NOTEVAL) {
/* Calculate fingerprint for on-disk file. */
digest = (u_char *) malloc(vhe->ops->hash_len, M_TEMP,
M_WAITOK);
error = veriexec_fp_calc(p, vp, vp->vhe, va->va_size, digest);
error = veriexec_fp_calc(p, vp, vhe, va->va_size, digest);
if (error) {
veriexec_dprintf(("veriexec: veriexec_verify: "
"Calculation error.\n"));
/* XXXEE verbose+ printf here */
free(digest, M_TEMP);
return (error);
}
if (veriexec_fp_cmp(vp->vhe->ops, vp->vhe->fp, digest) == 0) {
vp->fp_status = FINGERPRINT_VALID;
/* Compare fingerprint with loaded data. */
if (veriexec_fp_cmp(vhe->ops, vhe->fp, digest) == 0) {
vhe->status = FINGERPRINT_VALID;
} else {
vp->fp_status = FINGERPRINT_NOMATCH;
vhe->status = FINGERPRINT_NOMATCH;
}
free(digest, M_TEMP);
}
if (vp->vhe == NULL)
goto out;
if (flag != vp->vhe->type) {
if (flag != vhe->type) {
veriexec_report("Incorrect access type.", name, va, p,
REPORT_NOVERBOSE, REPORT_ALARM,
REPORT_NOPANIC);
@ -402,7 +401,19 @@ veriexec_verify(struct proc *p, struct vnode *vp, struct vattr *va,
}
out:
switch (vp->fp_status) {
/* No entry in the veriexec tables. */
if (vhe == NULL) {
veriexec_report("veriexec_verify: No entry.", name, va,
p, REPORT_VERBOSE, REPORT_NOALARM, REPORT_NOPANIC);
/* Lockdown mode: Deny access to non-monitored files. */
if (veriexec_strict >= 3)
return (EPERM);
return (0);
}
switch (vhe->status) {
case FINGERPRINT_NOTEVAL:
/* Should not happen. */
veriexec_report("veriexec_verify: Not-evaluated status "
@ -427,17 +438,6 @@ out:
break;
case FINGERPRINT_NOENTRY:
/* No entry in the list. */
veriexec_report("veriexec_verify: No entry.", name, va,
p, REPORT_VERBOSE, REPORT_NOALARM, REPORT_NOPANIC);
/* Lockdown mode: Deny access to non-monitored files. */
if (veriexec_strict >= 3)
error = EPERM;
break;
default:
/*
* Should never happen.
@ -494,8 +494,6 @@ veriexec_removechk(struct proc *p, struct vnode *vp, const char *pathbuf)
free(vhe->fp, M_TEMP);
free(vhe, M_TEMP);
tbl->hash_count--;
vp->fp_status = FINGERPRINT_NOENTRY;
vp->vhe = NULL;
return (error);
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: vfs_subr.c,v 1.249 2005/06/15 16:59:27 elad Exp $ */
/* $NetBSD: vfs_subr.c,v 1.250 2005/06/19 18:22:36 elad Exp $ */
/*-
* Copyright (c) 1997, 1998, 2004, 2005 The NetBSD Foundation, Inc.
@ -80,7 +80,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: vfs_subr.c,v 1.249 2005/06/15 16:59:27 elad Exp $");
__KERNEL_RCSID(0, "$NetBSD: vfs_subr.c,v 1.250 2005/06/19 18:22:36 elad Exp $");
#include "opt_inet.h"
#include "opt_ddb.h"
@ -587,10 +587,6 @@ getnewvnode(enum vtagtype tag, struct mount *mp, int (**vops)(void *),
vp->v_usecount = 1;
vp->v_flag = 0;
vp->v_socket = NULL;
#ifdef VERIFIED_EXEC
vp->fp_status = FINGERPRINT_NOTEVAL;
vp->vhe = NULL;
#endif
}
vp->v_type = VNON;
vp->v_vnlock = &vp->v_lock;

View File

@ -1,4 +1,4 @@
/* $NetBSD: vfs_vnops.c,v 1.91 2005/06/17 17:46:18 elad Exp $ */
/* $NetBSD: vfs_vnops.c,v 1.92 2005/06/19 18:22:36 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.91 2005/06/17 17:46:18 elad Exp $");
__KERNEL_RCSID(0, "$NetBSD: vfs_vnops.c,v 1.92 2005/06/19 18:22:36 elad Exp $");
#include "fs_union.h"
@ -100,15 +100,9 @@ vn_open(struct nameidata *ndp, int fmode, int cmode)
struct ucred *cred = p->p_ucred;
struct vattr va;
int error;
#ifdef NEVER /* for the moment I am not convinced this is needed since NDINIT should do this lookup...XXXX blymn */
char pathbuf[MAXPATHLEN];
unsigned pathlen;
if (ndp->ni_segflg == UIO_SYSSPACE)
error = copystr(pathbuf, ndp->ni_dirp, MAXPATHLEN, &pathlen);
else
error = copyinstr(pathbuf, ndp->ni_dirp,MAXPATHLEN, &pathlen);
#endif
#ifdef VERIFIED_EXEC
struct veriexec_hash_entry *vhe = NULL;
#endif /* VERIFIED_EXEC */
restart:
if (fmode & O_CREAT) {
@ -196,7 +190,7 @@ restart:
#ifdef VERIFIED_EXEC
/* XXX may need pathbuf instead */
if ((error = veriexec_verify(p, vp, &va, ndp->ni_dirp,
VERIEXEC_FILE)) != 0)
VERIEXEC_FILE, &vhe)) != 0)
goto bad;
#endif
@ -214,7 +208,7 @@ restart:
(error = VOP_ACCESS(vp, VWRITE, cred, p)) != 0)
goto bad;
#ifdef VERIFIED_EXEC
if (vp->fp_status != FINGERPRINT_NOENTRY) {
if (vhe != NULL) {
veriexec_report("Write access request.",
ndp->ni_dirp, &va, p,
REPORT_NOVERBOSE,
@ -226,7 +220,7 @@ restart:
error = EPERM;
goto bad;
} else {
vp->fp_status = FINGERPRINT_NOTEVAL;
vhe->status = FINGERPRINT_NOTEVAL;
}
}
#endif

View File

@ -1,4 +1,4 @@
/* $NetBSD: verified_exec.h,v 1.12 2005/05/29 16:07:10 elad Exp $ */
/* $NetBSD: verified_exec.h,v 1.13 2005/06/19 18:22:37 elad Exp $ */
/*-
* Copyright 2005 Elad Efrat <elad@bsd.org.il>
@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: verified_exec.h,v 1.12 2005/05/29 16:07:10 elad Exp $");
__KERNEL_RCSID(0, "$NetBSD: verified_exec.h,v 1.13 2005/06/19 18:22:37 elad Exp $");
/*
*
@ -119,11 +119,17 @@ struct veriexec_fp_ops {
struct veriexec_hash_entry {
ino_t inode; /* Inode number. */
unsigned char type; /* Entry type. */
unsigned char status; /* Evaluation status. */
unsigned char *fp; /* Fingerprint. */
struct veriexec_fp_ops *ops; /* Fingerprint ops vector*/
LIST_ENTRY(veriexec_hash_entry) entries; /* List pointer. */
};
/* Valid status field values. */
#define FINGERPRINT_NOTEVAL 0 /* fingerprint has not been evaluated */
#define FINGERPRINT_VALID 1 /* fingerprint evaluated and matches list */
#define FINGERPRINT_NOMATCH 2 /* fingerprint evaluated but does not match */
LIST_HEAD(veriexec_hashhead, veriexec_hash_entry) *hash_tbl;
/* Veriexec hash table information. */
@ -175,13 +181,11 @@ struct veriexec_fp_ops *veriexec_find_ops(u_char *name);
int veriexec_fp_calc(struct proc *, struct vnode *,
struct veriexec_hash_entry *, uint64_t, u_char *);
int veriexec_fp_cmp(struct veriexec_fp_ops *, u_char *, u_char *);
struct veriexec_hashtbl *veriexec_tblfind(dev_t);
struct veriexec_hash_entry *veriexec_lookup(dev_t, ino_t);
int veriexec_hashadd(struct veriexec_hashtbl *, struct veriexec_hash_entry *);
int veriexec_verify(struct proc *, struct vnode *, struct vattr *,
const u_char *, int);
const u_char *, int, struct veriexec_hash_entry **);
int veriexec_removechk(struct proc *, struct vnode *, const char *);
void veriexec_init_fp_ops(void);
void veriexec_report(const u_char *, const u_char *, struct vattr *,

View File

@ -1,4 +1,4 @@
/* $NetBSD: vnode.h,v 1.139 2005/06/17 17:46:18 elad Exp $ */
/* $NetBSD: vnode.h,v 1.140 2005/06/19 18:22:37 elad Exp $ */
/*
* Copyright (c) 1989, 1993
@ -121,15 +121,12 @@ struct vnode {
struct lock *v_vnlock; /* pointer to lock */
void *v_data; /* private data for fs */
struct klist v_klist; /* knotes attached to vnode */
#ifdef VERIFIED_EXEC
u_char fp_status; /* fingerprint status */
struct veriexec_hash_entry *vhe; /* veriexec table entry */
#endif
};
#define v_mountedhere v_un.vu_mountedhere
#define v_socket v_un.vu_socket
#define v_specinfo v_un.vu_specinfo
#define v_fifoinfo v_un.vu_fifoinfo
/*
* All vnode locking operations should use vp->v_vnlock. For leaf filesystems
* (such as ffs, lfs, msdosfs, etc), vp->v_vnlock = &vp->v_lock. For
@ -181,16 +178,6 @@ extern struct simplelock global_v_numoutput_slock;
simple_unlock(&global_v_numoutput_slock); \
} while (/*CONSTCOND*/ 0)
/*
* Valid states for the fingerprint flag - if signed exec is being used
*/
#ifdef VERIFIED_EXEC
#define FINGERPRINT_NOTEVAL 0 /* fingerprint has not been evaluated */
#define FINGERPRINT_VALID 1 /* fingerprint evaluated and matches list */
#define FINGERPRINT_NOMATCH 2 /* fingerprint evaluated but does not match */
#define FINGERPRINT_NOENTRY 3 /* fingerprint evaluated but no list entry */
#endif
/*
* Vnode attributes. A field value of VNOVAL represents a field whose value
* is unavailable (getattr) or which is not to be changed (setattr).