Subject: Re: verified exec per page fingerprints
To: Brett Lymn <blymn@baesystems.com.au>
From: Brett Lymn <blymn@baesystems.com.au>
List: tech-kern
Date: 12/06/2005 23:46:45
--cWoXeonUoKmBZSoM
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
Folks,
This is another iteration of the per page fingerprints. I
have added code to carefully unbusy the pages prior to doing a getattr
this does seem to have fixed a deadlock I observed. When a running
process has pages modified on the disk image and the pager brings
those pages back in from disk the process is killed which is correct.
Unfortunately, I am not doing something right - the kernel panics in
genfs_putpages() when the machine shuts down or a filesystem is
unmounted (I suspect it would panic on a fsflush too but I have not
tried that). I am not sure what I am doing wrong here... the code is
very similar to the error path in genfs_getpages() but, something
wrong I am doing. I have a kernel core dump and will poke around some
more trying to work it out...
Attached are the latest patches - I don't recommend using them unless
you like random crashings.
--
Brett Lymn
--cWoXeonUoKmBZSoM
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="veriexec_per_page.diff"
? sys/arch/i386/compile/ROVER
? sys/arch/i386/conf/ROVER
Index: sbin/veriexecctl/veriexecctl.8
===================================================================
RCS file: /cvsroot/src/sbin/veriexecctl/veriexecctl.8,v
retrieving revision 1.19
diff -u -r1.19 veriexecctl.8
--- sbin/veriexecctl/veriexecctl.8 5 Oct 2005 13:58:49 -0000 1.19
+++ sbin/veriexecctl/veriexecctl.8 6 Dec 2005 12:56:49 -0000
@@ -69,8 +69,11 @@
.Em path
is the full path to the file and
.Em type
-is the type of fingerprint used, see above for the default list.
-Other fingerprints may be available depending on kernel configuration.
+is the type of fingerprint used.
+The fingerprint types available depends on the kernel configuration.
+A list of supported fingerprint types can by found by querying the
+variable kern.veriexec.algorithms using
+.Xr sysctl 8 .
The
.Em fingerprint
field is a hexadecimal representation of the fingerprint for
@@ -78,7 +81,7 @@
The field
.Em options
contains the associated options for the file.
-Currently there are seven valid options:
+Valid options are:
.Pp
.Bl -tag -width INTERPRETER -compact
.It Dv DIRECT
@@ -117,10 +120,14 @@
.Dv FILE
option.
.It Dv UNTRUSTED
-This option is used to indicate that the file is located on
-untrusted storage, and its fingerprint should not be cached,
-but calculated each time it is accessed and when pages with
-this file as backing store are paged in.
+Indicates that the storage the file is on is not under direct control
+of the kernel and, therefore, the file cannot be guaranteed not to be
+modified.
+Enabling this flag will cause the veriexec kernel subsystem
+to perform fingerprinting at the memory page level and verify these
+fingerprints when paging parts of the file into memory.
+Enabling this flag will cause an increase in executable start up time,
+an increase in kernel memory usage and decrease in paging performance.
.El
.Pp
There must be only one executable/fingerprint pair per line.
Index: sbin/veriexecctl/veriexecctl.c
===================================================================
RCS file: /cvsroot/src/sbin/veriexecctl/veriexecctl.c,v
retrieving revision 1.17
diff -u -r1.17 veriexecctl.c
--- sbin/veriexecctl/veriexecctl.c 5 Oct 2005 13:48:48 -0000 1.17
+++ sbin/veriexecctl/veriexecctl.c 6 Dec 2005 12:56:49 -0000
@@ -141,7 +141,7 @@
* If there's no access type specified, use the default.
*/
if (!(params.type & (VERIEXEC_DIRECT|VERIEXEC_INDIRECT|VERIEXEC_FILE)))
- params.type |= VERIEXEC_DIRECT;
+ params.type |= (VERIEXEC_DIRECT | VERIEXEC_INDIRECT);
if (ioctl(gfd, VERIEXEC_LOAD, ¶ms) == -1)
warn("Cannot load params from `%s'", params.file);
free(params.fingerprint);
Index: sys/kern/kern_verifiedexec.c
===================================================================
RCS file: /cvsroot/src/sys/kern/kern_verifiedexec.c,v
retrieving revision 1.45
diff -u -r1.45 kern_verifiedexec.c
--- sys/kern/kern_verifiedexec.c 12 Oct 2005 14:26:47 -0000 1.45
+++ sys/kern/kern_verifiedexec.c 6 Dec 2005 12:57:01 -0000
@@ -56,6 +56,7 @@
#include <crypto/sha2/sha2.h>
#include <crypto/ripemd160/rmd160.h>
#include <sys/md5.h>
+#include <uvm/uvm.h>
#include <uvm/uvm_extern.h>
int veriexec_verbose;
@@ -66,6 +67,10 @@
const struct sysctlnode *veriexec_count_node;
+static void
+veriexec_release_pages(int npages, int error, struct vm_page **pps,
+ struct vnode *vp);
+
/* Veriexecs table of hash types and their associated information. */
LIST_HEAD(veriexec_ops_head, veriexec_fp_ops) veriexec_ops_list;
@@ -220,12 +225,10 @@
panic("veriexec: Operations vector is NULL");
}
-#if 0 /* XXX - for now */
if ((vhe->type & VERIEXEC_UNTRUSTED) &&
(vhe->page_fp_status == PAGE_FP_NONE))
do_perpage = 1;
else
-#endif
do_perpage = 0;
ctx = (void *) malloc(vhe->ops->context_size, M_TEMP, M_WAITOK);
@@ -514,7 +517,7 @@
*/
int
veriexec_page_verify(struct veriexec_hash_entry *vhe, struct vattr *va,
- struct vm_page *pg, size_t idx)
+ const struct vm_page *pg, size_t idx)
{
void *ctx;
u_char *fp;
@@ -591,6 +594,96 @@
return (error);
}
+int
+veriexec_block_verify(struct vnode *vp, struct vm_page **pps,
+ voff_t offset, int npages)
+{
+ struct veriexec_hash_entry *vhe;
+ struct vattr va;
+ struct uvm_object *uobj = &vp->v_uobj;
+ voff_t offidx, i;
+ int error;
+ UVMHIST_FUNC("veriexec_block_verify"); UVMHIST_CALLED(ubchist);
+
+
+ /*
+ * Unbusy pages to avoid a deadlock when getting the attributes
+ * for the file.
+ */
+ simple_lock(&uobj->vmobjlock);
+ uvm_page_unbusy(pps, npages);
+ simple_unlock(&uobj->vmobjlock);
+
+ error = VOP_GETATTR(vp, &va, curlwp->l_proc->p_ucred,
+ curlwp->l_proc);
+ if (error) {
+ veriexec_release_pages(npages, error, pps, vp);
+ return (error);
+ }
+
+ simple_lock(&uobj->vmobjlock);
+ for (i = 0; i < npages; i++) {
+ if (pps[i] == NULL) {
+ continue;
+ }
+ UVMHIST_LOG(ubchist, "busying pg %p flags 0x%x",
+ pps[i], pps[i]->flags, 0,0);
+ pps[i]->flags = (PG_WANTED|PG_BUSY);
+ UVM_PAGE_OWN(pg, "veriexec_block_verify");
+ }
+ simple_unlock(&uobj->vmobjlock);
+
+ vhe = veriexec_lookup(va.va_fsid, va.va_fileid);
+ if ((vhe == NULL) || (vhe->page_fp == NULL))
+ return (0);
+
+ offidx = (offset >> PAGE_SHIFT);
+
+ for (i = 0; i < npages; i++) {
+ error = veriexec_page_verify(vhe, &va, pps[i], i + offidx);
+ if (error) {
+ veriexec_release_pages(npages, error, pps, vp);
+ return (error);
+ }
+ }
+
+ return (0);
+}
+
+/*
+ * Release uvm pages - called if an error occurs during page verification.
+ */
+static void
+veriexec_release_pages(int npages, int error, struct vm_page **pps,
+ struct vnode *vp)
+{
+ struct uvm_object *uobj = &vp->v_uobj;
+ int i;
+ UVMHIST_FUNC("veriexec_release_pages"); UVMHIST_CALLED(ubchist);
+
+ /*
+ * On error, release all the pages requested,
+ * the page in may have worked but we are not
+ * interested if the fingerprinting fails.
+ */
+ simple_lock(&uobj->vmobjlock);
+ for (i = 0; i < npages; i++) {
+ if (pps[i] == NULL) {
+ continue;
+ }
+ UVMHIST_LOG(ubchist, "veriexec examining pg %p flags 0x%x",
+ pps[i], pps[i]->flags, 0,0);
+ pps[i]->flags |= PG_RELEASED;
+ }
+ uvm_lock_pageq();
+ uvm_page_unbusy(pps, npages);
+ /* uvm_pagefree??? XXXX */
+ uvm_unlock_pageq();
+ simple_unlock(&uobj->vmobjlock);
+ UVMHIST_LOG(ubchist, "veriexec returning error %d",
+ error,0,0,0);
+}
+
/*
* Veriexec remove policy code.
*/
Index: sys/sys/verified_exec.h
===================================================================
RCS file: /cvsroot/src/sys/sys/verified_exec.h,v
retrieving revision 1.21
diff -u -r1.21 verified_exec.h
--- sys/sys/verified_exec.h 7 Oct 2005 18:07:46 -0000 1.21
+++ sys/sys/verified_exec.h 6 Dec 2005 12:57:03 -0000
@@ -199,7 +199,8 @@
int veriexec_verify(struct proc *, struct vnode *, struct vattr *,
const u_char *, int, struct veriexec_hash_entry **);
int veriexec_page_verify(struct veriexec_hash_entry *, struct vattr *,
- struct vm_page *, size_t);
+ const struct vm_page *, size_t);
+int veriexec_block_verify(struct vnode *, struct vm_page **, voff_t, int);
int veriexec_removechk(struct proc *, struct vnode *, const char *);
int veriexec_renamechk(struct vnode *, const char *, const char *);
void veriexec_init_fp_ops(void);
Index: sys/uvm/uvm_vnode.c
===================================================================
RCS file: /cvsroot/src/sys/uvm/uvm_vnode.c,v
retrieving revision 1.66
diff -u -r1.66 uvm_vnode.c
--- sys/uvm/uvm_vnode.c 27 Jun 2005 02:29:32 -0000 1.66
+++ sys/uvm/uvm_vnode.c 6 Dec 2005 12:57:03 -0000
@@ -55,6 +55,7 @@
#include "fs_nfs.h"
#include "opt_uvmhist.h"
#include "opt_ddb.h"
+#include "opt_verified_exec.h"
#include <sys/param.h>
#include <sys/systm.h>
@@ -68,6 +69,9 @@
#include <sys/conf.h>
#include <sys/pool.h>
#include <sys/mount.h>
+#ifdef VERIFIED_EXEC
+#include <sys/verified_exec.h>
+#endif /* VERIFIED_EXEC */
#include <miscfs/specfs/specdev.h>
@@ -299,6 +303,12 @@
UVMHIST_LOG(ubchist, "vp %p off 0x%x", vp, (int)offset, 0,0);
error = VOP_GETPAGES(vp, offset, pps, npagesp, centeridx,
access_type, advice, flags);
+
+#ifdef VERIFIED_EXEC
+ if ((!error) && !(flags & PGO_LOCKED))
+ error = veriexec_block_verify(vp, pps, offset, *npagesp);
+#endif /* VERIFIED_EXEC */
+
return error;
}
--cWoXeonUoKmBZSoM--