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, &params) == -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--