Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


Add guarded module infrastructure
Kyle Hale [Wed, 10 Apr 2013 21:03:22 +0000 (16:03 -0500)]
This commit includes all of the changes for guarded modules that
do not touch the VMM core at all. This includes a host interface,
userspace utility, and Palacios extensions.

13 files changed:
linux_module/Makefile
linux_module/iface-guard-mods.c [new file with mode: 0644]
linux_module/iface-guard-mods.h [new file with mode: 0644]
linux_usr/Makefile
linux_usr/cJSON.c [new file with mode: 0644]
linux_usr/cJSON.h [new file with mode: 0644]
linux_usr/v3_register_gm.c [new file with mode: 0644]
palacios/include/gears/guard_mods.h [new file with mode: 0644]
palacios/include/gears/privilege.h [new file with mode: 0644]
palacios/src/gears/Kconfig
palacios/src/gears/Makefile
palacios/src/gears/ext_guard_mods.c [new file with mode: 0644]
palacios/src/gears/ext_priv.c [new file with mode: 0644]

index a7eeb53..d45c494 100644 (file)
@@ -44,6 +44,7 @@ v3vee-$(V3_CONFIG_HOST_HYPERCALL) += iface-host-hypercall.o
 v3vee-$(V3_CONFIG_EXT_CODE_INJECT) += iface-code-inject.o
 v3vee-$(V3_CONFIG_EXT_ENV_INJECT) += iface-env-inject.o
 v3vee-$(V3_CONFIG_EXT_SELECTIVE_SYSCALL_EXIT) += iface-syscall.o
+v3vee-$(V3_CONFIG_EXT_GUARD_MODULES) += iface-guard-mods.o
 
 
 v3vee-$(V3_CONFIG_HOST_PCI) += iface-host-pci.o
diff --git a/linux_module/iface-guard-mods.c b/linux_module/iface-guard-mods.c
new file mode 100644 (file)
index 0000000..67917d7
--- /dev/null
@@ -0,0 +1,211 @@
+/* 
+ * Linux interface for guarded module registration
+ *
+ * (c) Kyle C. Hale 2012
+ *
+ */
+
+#include <linux/uaccess.h>
+#include <linux/vmalloc.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/list.h>
+#include <gears/guard_mods.h>
+#include "palacios.h"
+#include "vm.h"
+#include "linux-exts.h"
+#include "iface-guard-mods.h"
+
+
+static int
+vm_register_mod (struct v3_guest * guest, 
+                 unsigned int cmd,
+                 unsigned long arg,
+                 void * priv_data) 
+{
+    uint64_t ret;
+    struct v3_guard_mod arg_mod;
+    struct v3_guard_mod * gm;
+    int i;
+
+    gm = palacios_alloc(sizeof(struct v3_guard_mod));
+    if (!gm) {
+        ERROR("palacios: error allocating guarded module\n");
+        return -EFAULT;
+    }
+
+    if (copy_from_user(&arg_mod, (void __user *)arg, sizeof(struct v3_guard_mod))) {
+        ERROR("palacios: error copying guarded module data from userspace\n");
+        return -EFAULT;
+    }
+
+    memcpy(gm, &arg_mod, sizeof(struct v3_guard_mod));
+
+    /* get module name */
+    gm->name = palacios_alloc(strnlen_user((char __user *)arg_mod.name, MAX_MOD_NAME_LEN)+1);
+    if (!gm->name) {
+        ERROR("Problem allocating space for mod name\n");
+        return -1;
+    }
+
+    if (strncpy_from_user(gm->name, (char __user *)arg_mod.name, MAX_MOD_NAME_LEN) == -EFAULT) {
+        ERROR("problem copying from userspace\n");
+        return -1;
+    }
+
+    /* get module content hash */
+    gm->content_hash = palacios_alloc(strnlen_user((char __user *)arg_mod.content_hash, MAX_HASH_LEN)+1);
+    if (!gm->content_hash) {
+        ERROR("Problem allocating space for content hash\n");
+        return -1;
+    }
+
+    if (strncpy_from_user(gm->content_hash, (char __user *)arg_mod.content_hash, MAX_HASH_LEN) == -EFAULT) {
+        ERROR("problem copying from userspace\n");
+        return -1;
+    }
+
+    /* get valid entry points */
+    gm->entry_points = palacios_alloc(sizeof(struct v3_guard_mod)*arg_mod.num_entries);
+    if (!gm->entry_points) {
+        ERROR("Problem allocating space for entry point array\n");
+        return -1;
+    }
+
+    if (copy_from_user(gm->entry_points, (void __user *)arg_mod.entry_points, sizeof(struct v3_guard_mod)*arg_mod.num_entries)
+        == -EFAULT) {
+        ERROR("problem copying from userspace\n");
+        return -1;
+    }
+
+    for (i = 0; i < gm->num_entries; i++) {
+        int len;
+        char * tmp;   
+
+        if ((len = strnlen_user((char __user *)gm->entry_points[i].name, MAX_MOD_NAME_LEN)+1) == -EFAULT) {
+            ERROR("problem getting strlen from userspace\n");
+            return -1;
+        }
+
+        tmp = palacios_alloc(len);
+        if (!tmp) {
+            ERROR("Problem allocating space for string\n");
+            return -1;
+        }
+
+        if (strncpy_from_user(tmp, (char __user *)gm->entry_points[i].name, MAX_MOD_NAME_LEN) == -EFAULT) {
+                ERROR("problem copying from userspace\n");
+                return -1;
+        }
+
+        gm->entry_points[i].name = tmp;
+    }
+
+    /* get list of privileges */
+    gm->priv_array = palacios_alloc(sizeof(char*)*arg_mod.num_privs);
+    if (!gm->priv_array) {
+        ERROR("Problem allocating space for privilege array\n");
+        return -1;
+    }
+
+    if (copy_from_user(gm->priv_array, (void __user *)arg_mod.priv_array, sizeof(char*)*arg_mod.num_privs)
+        == -EFAULT) {
+        ERROR("problem copying privilege array from userspace\n");
+        return -1;
+    }
+
+    for (i = 0; i < gm->num_privs; i++) {
+        int len;
+        char * tmp;
+        if ((len = strlen_user((char __user*)gm->priv_array[i]) + 1) == -EFAULT) {
+            ERROR("problem getting strlen from userspace\n");
+            return -1;
+        }
+
+        tmp = palacios_alloc(len);
+        if (!tmp) {
+            ERROR("Problem allocating space for privilege name\n");
+            return -1;
+        }
+
+        if (strncpy_from_user(tmp, (char __user *)gm->priv_array[i], MAX_MOD_NAME_LEN) == -EFAULT) {
+            ERROR("problem copying privilege from userspace\n");
+            return -1;
+        }
+
+        gm->priv_array[i] = tmp;
+    }
+    
+    INFO("Registering Guarded Module with Palacios\n");
+    ret = v3_register_gm(guest->v3_ctx,
+                          gm->name,
+                          gm->content_hash,
+                          gm->hcall_offset,
+                          gm->text_size,
+                          gm->num_entries,
+                          gm->num_privs,
+                          gm->priv_array,
+                          NULL,
+                          (void*)gm->entry_points);
+
+    if (!ret) {
+        ERROR("palacios: could not register guarded module: %s\n", arg_mod.name);
+        return -1;
+    }
+
+    arg_mod.id = ret;
+
+    if (copy_to_user((void __user *)arg, &arg_mod, sizeof(struct v3_guard_mod))) {
+        ERROR("palacios: error copying guarded module back to userspace\n");
+        return -1;
+    }
+
+    kfree(gm->name);
+    kfree(gm->content_hash);
+    for (i = 0; i < gm->num_entries; i++) {
+        kfree(gm->entry_points[i].name);
+    }
+    kfree(gm->entry_points);
+    kfree(gm);
+    return 0;
+}
+
+
+static int 
+init_guard_mods (void) 
+{
+    return 0;
+}
+
+
+static int 
+deinit_guard_mods (void) 
+{
+    return 0;
+}
+
+
+static int 
+guest_init_guard_mods (struct v3_guest * guest, void ** vm_data) 
+{
+    add_guest_ctrl(guest, V3_VM_REGISTER_MOD, vm_register_mod, NULL);
+    return 0;
+}
+
+
+static int 
+guest_deinit_guard_mods (struct v3_guest * guest, void * vm_data) 
+{
+    return 0;
+}
+
+
+static struct linux_ext guard_mods_ext = {
+    .name = "GUARDED_MODULES",
+    .init = init_guard_mods,
+    .deinit = deinit_guard_mods,
+    .guest_init = guest_init_guard_mods,
+    .guest_deinit = guest_deinit_guard_mods
+};
+
+register_extension(&guard_mods_ext);
diff --git a/linux_module/iface-guard-mods.h b/linux_module/iface-guard-mods.h
new file mode 100644 (file)
index 0000000..416e4b9
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef __IFACE_GUARD_MODS_H__
+#define __IFACE_GUARD_MODS_H__
+
+#define V3_VM_REGISTER_MOD 14124
+
+#define MAX_MOD_NAME_LEN 256
+#define MAX_HASH_LEN     128
+
+struct v3_entry_point {
+    char * name;
+    unsigned long offset;
+    char is_ret;
+    
+   /* TODO: Fix this HACKERY! These last two are placeholders */
+    void * hack[3];
+};
+
+
+struct v3_guard_mod {
+    char * name;                     /* GM name */
+    char * content_hash;    /* hash of the module .text segment */
+    unsigned int hcall_offset;    /* offset from .text to hypercall */
+    unsigned int text_size;             /* size of module .text segment */
+    unsigned int num_entries;           /* number of entry points */
+    unsigned int num_privs;
+    char ** priv_array;           /* each bit represent a requested privilege */
+    unsigned long long id;              /* GM ID */
+    struct v3_entry_point * entry_points;        /* entry point array (offsets) */
+};
+
+#endif
index 4f03c2a..b53732f 100644 (file)
@@ -49,7 +49,8 @@ EXPERIMENTAL_EXECS =  v3_simulate  \
                        v3_inject_ecc_scrubber_mce  \
                         v3_top_inject \
                         v3_env_inject \
-                       v3_syscall
+                       v3_syscall \
+                       v3_register_gm
 
 
 
@@ -89,6 +90,10 @@ libv3_ctrl.a : v3_ctrl.c v3_ctrl.h
        $(AR) ruv libv3_ctrl.a v3_ctrl.o
        rm -rf v3_ctrl.o 
 
+libjson.a : cJSON.c cJSON.h
+       $(CC) $(CFLAGS) -c cJSON.c
+       $(AR) ruv libjson.a cJSON.o
+       rm -rf cJSON.o
 #
 # Most tools compile in a straightforward way
 #
@@ -132,6 +137,8 @@ v3_user_host_dev_example : v3_user_host_dev_example.c libv3_user_host_dev.a
 v3_os_debug : v3_os_debug.c libv3_user_host_dev.a
        $(CC) $(CFLAGS) $< -I../linux_module -L. -lv3_user_host_dev -o $@
 
+v3_register_gm: v3_register_gm.c libjson.a libv3_ctrl.a v3_ctrl.h
+       $(CC) $(CFLAGS) $< -L. -lm -lv3_ctrl -ljson -o $@
 
 #
 # User keyed stream support includes a library and examples
diff --git a/linux_usr/cJSON.c b/linux_usr/cJSON.c
new file mode 100644 (file)
index 0000000..eb7c2f9
--- /dev/null
@@ -0,0 +1,514 @@
+/*
+  Copyright (c) 2009 Dave Gamble
+
+  Permission is hereby granted, free of charge, to any person obtaining a copy
+  of this software and associated documentation files (the "Software"), to deal
+  in the Software without restriction, including without limitation the rights
+  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+  copies of the Software, and to permit persons to whom the Software is
+  furnished to do so, subject to the following conditions:
+
+  The above copyright notice and this permission notice shall be included in
+  all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+  THE SOFTWARE.
+*/
+
+/* cJSON */
+/* JSON parser in C. */
+
+#include <string.h>
+#include <stdio.h>
+#include <math.h>
+#include <stdlib.h>
+#include <float.h>
+#include <limits.h>
+#include <ctype.h>
+#include "cJSON.h"
+
+static const char *ep;
+
+const char *cJSON_GetErrorPtr() {return ep;}
+
+static int cJSON_strcasecmp(const char *s1,const char *s2)
+{
+       if (!s1) return (s1==s2)?0:1;if (!s2) return 1;
+       for(; tolower(*s1) == tolower(*s2); ++s1, ++s2) if(*s1 == 0)    return 0;
+       return tolower(*(const unsigned char *)s1) - tolower(*(const unsigned char *)s2);
+}
+
+static void *(*cJSON_malloc)(size_t sz) = malloc;
+static void (*cJSON_free)(void *ptr) = free;
+
+static char* cJSON_strdup(const char* str)
+{
+      size_t len;
+      char* copy;
+
+      len = strlen(str) + 1;
+      if (!(copy = (char*)cJSON_malloc(len))) return 0;
+      memcpy(copy,str,len);
+      return copy;
+}
+
+void cJSON_InitHooks(cJSON_Hooks* hooks)
+{
+    if (!hooks) { /* Reset hooks */
+        cJSON_malloc = malloc;
+        cJSON_free = free;
+        return;
+    }
+
+       cJSON_malloc = (hooks->malloc_fn)?hooks->malloc_fn:malloc;
+       cJSON_free       = (hooks->free_fn)?hooks->free_fn:free;
+}
+
+/* Internal constructor. */
+static cJSON *cJSON_New_Item()
+{
+       cJSON* node = (cJSON*)cJSON_malloc(sizeof(cJSON));
+       if (node) memset(node,0,sizeof(cJSON));
+       return node;
+}
+
+/* Delete a cJSON structure. */
+void cJSON_Delete(cJSON *c)
+{
+       cJSON *next;
+       while (c)
+       {
+               next=c->next;
+               if (!(c->type&cJSON_IsReference) && c->child) cJSON_Delete(c->child);
+               if (!(c->type&cJSON_IsReference) && c->valuestring) cJSON_free(c->valuestring);
+               if (c->string) cJSON_free(c->string);
+               cJSON_free(c);
+               c=next;
+       }
+}
+
+/* Parse the input text to generate a number, and populate the result into item. */
+static const char *parse_number(cJSON *item,const char *num)
+{
+       double n=0,sign=1,scale=0;int subscale=0,signsubscale=1;
+
+       /* Could use sscanf for this? */
+       if (*num=='-') sign=-1,num++;   /* Has sign? */
+       if (*num=='0') num++;                   /* is zero */
+       if (*num>='1' && *num<='9')     do      n=(n*10.0)+(*num++ -'0');       while (*num>='0' && *num<='9'); /* Number? */
+       if (*num=='.' && num[1]>='0' && num[1]<='9') {num++;            do      n=(n*10.0)+(*num++ -'0'),scale--; while (*num>='0' && *num<='9');}      /* Fractional part? */
+       if (*num=='e' || *num=='E')             /* Exponent? */
+       {       num++;if (*num=='+') num++;     else if (*num=='-') signsubscale=-1,num++;              /* With sign? */
+               while (*num>='0' && *num<='9') subscale=(subscale*10)+(*num++ - '0');   /* Number? */
+       }
+
+       n=sign*n*pow(10.0,(scale+subscale*signsubscale));       /* number = +/- number.fraction * 10^+/- exponent */
+       
+       item->valuedouble=n;
+       item->valueint=(int)n;
+       item->type=cJSON_Number;
+       return num;
+}
+
+/* Render the number nicely from the given item into a string. */
+static char *print_number(cJSON *item)
+{
+       char *str;
+       double d=item->valuedouble;
+       if (fabs(((double)item->valueint)-d)<=DBL_EPSILON && d<=INT_MAX && d>=INT_MIN)
+       {
+               str=(char*)cJSON_malloc(21);    /* 2^64+1 can be represented in 21 chars. */
+               if (str) sprintf(str,"%d",item->valueint);
+       }
+       else
+       {
+               str=(char*)cJSON_malloc(64);    /* This is a nice tradeoff. */
+               if (str)
+               {
+                       if (fabs(floor(d)-d)<=DBL_EPSILON)                      sprintf(str,"%.0f",d);
+                       else if (fabs(d)<1.0e-6 || fabs(d)>1.0e9)       sprintf(str,"%e",d);
+                       else                                                                            sprintf(str,"%f",d);
+               }
+       }
+       return str;
+}
+
+/* Parse the input text into an unescaped cstring, and populate item. */
+static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
+static const char *parse_string(cJSON *item,const char *str)
+{
+       const char *ptr=str+1;char *ptr2;char *out;int len=0;unsigned uc,uc2;
+       if (*str!='\"') {ep=str;return 0;}      /* not a string! */
+       
+       while (*ptr!='\"' && *ptr && ++len) if (*ptr++ == '\\') ptr++;  /* Skip escaped quotes. */
+       
+       out=(char*)cJSON_malloc(len+1); /* This is how long we need for the string, roughly. */
+       if (!out) return 0;
+       
+       ptr=str+1;ptr2=out;
+       while (*ptr!='\"' && *ptr)
+       {
+               if (*ptr!='\\') *ptr2++=*ptr++;
+               else
+               {
+                       ptr++;
+                       switch (*ptr)
+                       {
+                               case 'b': *ptr2++='\b'; break;
+                               case 'f': *ptr2++='\f'; break;
+                               case 'n': *ptr2++='\n'; break;
+                               case 'r': *ptr2++='\r'; break;
+                               case 't': *ptr2++='\t'; break;
+                               case 'u':        /* transcode utf16 to utf8. */
+                                       sscanf(ptr+1,"%4x",&uc);ptr+=4; /* get the unicode char. */
+
+                                       if ((uc>=0xDC00 && uc<=0xDFFF) || uc==0)        break;  // check for invalid.
+
+                                       if (uc>=0xD800 && uc<=0xDBFF)   // UTF16 surrogate pairs.
+                                       {
+                                               if (ptr[1]!='\\' || ptr[2]!='u')        break;  // missing second-half of surrogate.
+                                               sscanf(ptr+3,"%4x",&uc2);ptr+=6;
+                                               if (uc2<0xDC00 || uc2>0xDFFF)           break;  // invalid second-half of surrogate.
+                                               uc=0x10000 | ((uc&0x3FF)<<10) | (uc2&0x3FF);
+                                       }
+
+                                       len=4;if (uc<0x80) len=1;else if (uc<0x800) len=2;else if (uc<0x10000) len=3; ptr2+=len;
+                                       
+                                       switch (len) {
+                                               case 4: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
+                                               case 3: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
+                                               case 2: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
+                                               case 1: *--ptr2 =(uc | firstByteMark[len]);
+                                       }
+                                       ptr2+=len;
+                                       break;
+                               default:  *ptr2++=*ptr; break;
+                       }
+                       ptr++;
+               }
+       }
+       *ptr2=0;
+       if (*ptr=='\"') ptr++;
+       item->valuestring=out;
+       item->type=cJSON_String;
+       return ptr;
+}
+
+/* Render the cstring provided to an escaped version that can be printed. */
+static char *print_string_ptr(const char *str)
+{
+       const char *ptr;char *ptr2,*out;int len=0;unsigned char token;
+       
+       if (!str) return cJSON_strdup("");
+       ptr=str;while ((token=*ptr) && ++len) {if (strchr("\"\\\b\f\n\r\t",token)) len++; else if (token<32) len+=5;ptr++;}
+       
+       out=(char*)cJSON_malloc(len+3);
+       if (!out) return 0;
+
+       ptr2=out;ptr=str;
+       *ptr2++='\"';
+       while (*ptr)
+       {
+               if ((unsigned char)*ptr>31 && *ptr!='\"' && *ptr!='\\') *ptr2++=*ptr++;
+               else
+               {
+                       *ptr2++='\\';
+                       switch (token=*ptr++)
+                       {
+                               case '\\':      *ptr2++='\\';   break;
+                               case '\"':      *ptr2++='\"';   break;
+                               case '\b':      *ptr2++='b';    break;
+                               case '\f':      *ptr2++='f';    break;
+                               case '\n':      *ptr2++='n';    break;
+                               case '\r':      *ptr2++='r';    break;
+                               case '\t':      *ptr2++='t';    break;
+                               default: sprintf(ptr2,"u%04x",token);ptr2+=5;   break;  /* escape and print */
+                       }
+               }
+       }
+       *ptr2++='\"';*ptr2++=0;
+       return out;
+}
+/* Invote print_string_ptr (which is useful) on an item. */
+static char *print_string(cJSON *item) {return print_string_ptr(item->valuestring);}
+
+/* Predeclare these prototypes. */
+static const char *parse_value(cJSON *item,const char *value);
+static char *print_value(cJSON *item,int depth,int fmt);
+static const char *parse_array(cJSON *item,const char *value);
+static char *print_array(cJSON *item,int depth,int fmt);
+static const char *parse_object(cJSON *item,const char *value);
+static char *print_object(cJSON *item,int depth,int fmt);
+
+/* Utility to jump whitespace and cr/lf */
+static const char *skip(const char *in) {while (in && *in && (unsigned char)*in<=32) in++; return in;}
+
+/* Parse an object - create a new root, and populate. */
+cJSON *cJSON_Parse(const char *value)
+{
+       cJSON *c=cJSON_New_Item();
+       ep=0;
+       if (!c) return 0;       /* memory fail */
+
+       if (!parse_value(c,skip(value))) {cJSON_Delete(c);return 0;}
+       return c;
+}
+
+/* Render a cJSON item/entity/structure to text. */
+char *cJSON_Print(cJSON *item)                         {return print_value(item,0,1);}
+char *cJSON_PrintUnformatted(cJSON *item)      {return print_value(item,0,0);}
+
+/* Parser core - when encountering text, process appropriately. */
+static const char *parse_value(cJSON *item,const char *value)
+{
+       if (!value)                                             return 0;       /* Fail on null. */
+       if (!strncmp(value,"null",4))   { item->type=cJSON_NULL;  return value+4; }
+       if (!strncmp(value,"false",5))  { item->type=cJSON_False; return value+5; }
+       if (!strncmp(value,"true",4))   { item->type=cJSON_True; item->valueint=1;      return value+4; }
+       if (*value=='\"')                               { return parse_string(item,value); }
+       if (*value=='-' || (*value>='0' && *value<='9'))        { return parse_number(item,value); }
+       if (*value=='[')                                { return parse_array(item,value); }
+       if (*value=='{')                                { return parse_object(item,value); }
+
+       ep=value;return 0;      /* failure. */
+}
+
+/* Render a value to text. */
+static char *print_value(cJSON *item,int depth,int fmt)
+{
+       char *out=0;
+       if (!item) return 0;
+       switch ((item->type)&255)
+       {
+               case cJSON_NULL:        out=cJSON_strdup("null");       break;
+               case cJSON_False:       out=cJSON_strdup("false");break;
+               case cJSON_True:        out=cJSON_strdup("true"); break;
+               case cJSON_Number:      out=print_number(item);break;
+               case cJSON_String:      out=print_string(item);break;
+               case cJSON_Array:       out=print_array(item,depth,fmt);break;
+               case cJSON_Object:      out=print_object(item,depth,fmt);break;
+       }
+       return out;
+}
+
+/* Build an array from input text. */
+static const char *parse_array(cJSON *item,const char *value)
+{
+       cJSON *child;
+       if (*value!='[')        {ep=value;return 0;}    /* not an array! */
+
+       item->type=cJSON_Array;
+       value=skip(value+1);
+       if (*value==']') return value+1;        /* empty array. */
+
+       item->child=child=cJSON_New_Item();
+       if (!item->child) return 0;              /* memory fail */
+       value=skip(parse_value(child,skip(value)));     /* skip any spacing, get the value. */
+       if (!value) return 0;
+
+       while (*value==',')
+       {
+               cJSON *new_item;
+               if (!(new_item=cJSON_New_Item())) return 0;     /* memory fail */
+               child->next=new_item;new_item->prev=child;child=new_item;
+               value=skip(parse_value(child,skip(value+1)));
+               if (!value) return 0;   /* memory fail */
+       }
+
+       if (*value==']') return value+1;        /* end of array */
+       ep=value;return 0;      /* malformed. */
+}
+
+/* Render an array to text */
+static char *print_array(cJSON *item,int depth,int fmt)
+{
+       char **entries;
+       char *out=0,*ptr,*ret;int len=5;
+       cJSON *child=item->child;
+       int numentries=0,i=0,fail=0;
+       
+       /* How many entries in the array? */
+       while (child) numentries++,child=child->next;
+       /* Allocate an array to hold the values for each */
+       entries=(char**)cJSON_malloc(numentries*sizeof(char*));
+       if (!entries) return 0;
+       memset(entries,0,numentries*sizeof(char*));
+       /* Retrieve all the results: */
+       child=item->child;
+       while (child && !fail)
+       {
+               ret=print_value(child,depth+1,fmt);
+               entries[i++]=ret;
+               if (ret) len+=strlen(ret)+2+(fmt?1:0); else fail=1;
+               child=child->next;
+       }
+       
+       /* If we didn't fail, try to malloc the output string */
+       if (!fail) out=(char*)cJSON_malloc(len);
+       /* If that fails, we fail. */
+       if (!out) fail=1;
+
+       /* Handle failure. */
+       if (fail)
+       {
+               for (i=0;i<numentries;i++) if (entries[i]) cJSON_free(entries[i]);
+               cJSON_free(entries);
+               return 0;
+       }
+       
+       /* Compose the output array. */
+       *out='[';
+       ptr=out+1;*ptr=0;
+       for (i=0;i<numentries;i++)
+       {
+               strcpy(ptr,entries[i]);ptr+=strlen(entries[i]);
+               if (i!=numentries-1) {*ptr++=',';if(fmt)*ptr++=' ';*ptr=0;}
+               cJSON_free(entries[i]);
+       }
+       cJSON_free(entries);
+       *ptr++=']';*ptr++=0;
+       return out;     
+}
+
+/* Build an object from the text. */
+static const char *parse_object(cJSON *item,const char *value)
+{
+       cJSON *child;
+       if (*value!='{')        {ep=value;return 0;}    /* not an object! */
+       
+       item->type=cJSON_Object;
+       value=skip(value+1);
+       if (*value=='}') return value+1;        /* empty array. */
+       
+       item->child=child=cJSON_New_Item();
+       if (!item->child) return 0;
+       value=skip(parse_string(child,skip(value)));
+       if (!value) return 0;
+       child->string=child->valuestring;child->valuestring=0;
+       if (*value!=':') {ep=value;return 0;}   /* fail! */
+       value=skip(parse_value(child,skip(value+1)));   /* skip any spacing, get the value. */
+       if (!value) return 0;
+       
+       while (*value==',')
+       {
+               cJSON *new_item;
+               if (!(new_item=cJSON_New_Item()))       return 0; /* memory fail */
+               child->next=new_item;new_item->prev=child;child=new_item;
+               value=skip(parse_string(child,skip(value+1)));
+               if (!value) return 0;
+               child->string=child->valuestring;child->valuestring=0;
+               if (*value!=':') {ep=value;return 0;}   /* fail! */
+               value=skip(parse_value(child,skip(value+1)));   /* skip any spacing, get the value. */
+               if (!value) return 0;
+       }
+       
+       if (*value=='}') return value+1;        /* end of array */
+       ep=value;return 0;      /* malformed. */
+}
+
+/* Render an object to text. */
+static char *print_object(cJSON *item,int depth,int fmt)
+{
+       char **entries=0,**names=0;
+       char *out=0,*ptr,*ret,*str;int len=7,i=0,j;
+       cJSON *child=item->child;
+       int numentries=0,fail=0;
+       /* Count the number of entries. */
+       while (child) numentries++,child=child->next;
+       /* Allocate space for the names and the objects */
+       entries=(char**)cJSON_malloc(numentries*sizeof(char*));
+       if (!entries) return 0;
+       names=(char**)cJSON_malloc(numentries*sizeof(char*));
+       if (!names) {cJSON_free(entries);return 0;}
+       memset(entries,0,sizeof(char*)*numentries);
+       memset(names,0,sizeof(char*)*numentries);
+
+       /* Collect all the results into our arrays: */
+       child=item->child;depth++;if (fmt) len+=depth;
+       while (child)
+       {
+               names[i]=str=print_string_ptr(child->string);
+               entries[i++]=ret=print_value(child,depth,fmt);
+               if (str && ret) len+=strlen(ret)+strlen(str)+2+(fmt?2+depth:0); else fail=1;
+               child=child->next;
+       }
+       
+       /* Try to allocate the output string */
+       if (!fail) out=(char*)cJSON_malloc(len);
+       if (!out) fail=1;
+
+       /* Handle failure */
+       if (fail)
+       {
+               for (i=0;i<numentries;i++) {if (names[i]) cJSON_free(names[i]);if (entries[i]) cJSON_free(entries[i]);}
+               cJSON_free(names);cJSON_free(entries);
+               return 0;
+       }
+       
+       /* Compose the output: */
+       *out='{';ptr=out+1;if (fmt)*ptr++='\n';*ptr=0;
+       for (i=0;i<numentries;i++)
+       {
+               if (fmt) for (j=0;j<depth;j++) *ptr++='\t';
+               strcpy(ptr,names[i]);ptr+=strlen(names[i]);
+               *ptr++=':';if (fmt) *ptr++='\t';
+               strcpy(ptr,entries[i]);ptr+=strlen(entries[i]);
+               if (i!=numentries-1) *ptr++=',';
+               if (fmt) *ptr++='\n';*ptr=0;
+               cJSON_free(names[i]);cJSON_free(entries[i]);
+       }
+       
+       cJSON_free(names);cJSON_free(entries);
+       if (fmt) for (i=0;i<depth-1;i++) *ptr++='\t';
+       *ptr++='}';*ptr++=0;
+       return out;     
+}
+
+/* Get Array size/item / object item. */
+int    cJSON_GetArraySize(cJSON *array)                                                        {cJSON *c=array->child;int i=0;while(c)i++,c=c->next;return i;}
+cJSON *cJSON_GetArrayItem(cJSON *array,int item)                               {cJSON *c=array->child;  while (c && item>0) item--,c=c->next; return c;}
+cJSON *cJSON_GetObjectItem(cJSON *object,const char *string)   {cJSON *c=object->child; while (c && cJSON_strcasecmp(c->string,string)) c=c->next; return c;}
+
+/* Utility for array list handling. */
+static void suffix_object(cJSON *prev,cJSON *item) {prev->next=item;item->prev=prev;}
+/* Utility for handling references. */
+static cJSON *create_reference(cJSON *item) {cJSON *ref=cJSON_New_Item();if (!ref) return 0;memcpy(ref,item,sizeof(cJSON));ref->string=0;ref->type|=cJSON_IsReference;ref->next=ref->prev=0;return ref;}
+
+/* Add item to array/object. */
+void   cJSON_AddItemToArray(cJSON *array, cJSON *item)                                         {cJSON *c=array->child;if (!item) return; if (!c) {array->child=item;} else {while (c && c->next) c=c->next; suffix_object(c,item);}}
+void   cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item)     {if (!item) return; if (item->string) cJSON_free(item->string);item->string=cJSON_strdup(string);cJSON_AddItemToArray(object,item);}
+void   cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item)                                                {cJSON_AddItemToArray(array,create_reference(item));}
+void   cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item)    {cJSON_AddItemToObject(object,string,create_reference(item));}
+
+cJSON *cJSON_DetachItemFromArray(cJSON *array,int which)                       {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return 0;
+       if (c->prev) c->prev->next=c->next;if (c->next) c->next->prev=c->prev;if (c==array->child) array->child=c->next;c->prev=c->next=0;return c;}
+void   cJSON_DeleteItemFromArray(cJSON *array,int which)                       {cJSON_Delete(cJSON_DetachItemFromArray(array,which));}
+cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string) {int i=0;cJSON *c=object->child;while (c && cJSON_strcasecmp(c->string,string)) i++,c=c->next;if (c) return cJSON_DetachItemFromArray(object,i);return 0;}
+void   cJSON_DeleteItemFromObject(cJSON *object,const char *string) {cJSON_Delete(cJSON_DetachItemFromObject(object,string));}
+
+/* Replace array/object items with new ones. */
+void   cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem)         {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return;
+       newitem->next=c->next;newitem->prev=c->prev;if (newitem->next) newitem->next->prev=newitem;
+       if (c==array->child) array->child=newitem; else newitem->prev->next=newitem;c->next=c->prev=0;cJSON_Delete(c);}
+void   cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem){int i=0;cJSON *c=object->child;while(c && cJSON_strcasecmp(c->string,string))i++,c=c->next;if(c){newitem->string=cJSON_strdup(string);cJSON_ReplaceItemInArray(object,i,newitem);}}
+
+/* Create basic types: */
+cJSON *cJSON_CreateNull()                                              {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_NULL;return item;}
+cJSON *cJSON_CreateTrue()                                              {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_True;return item;}
+cJSON *cJSON_CreateFalse()                                             {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_False;return item;}
+cJSON *cJSON_CreateBool(int b)                                 {cJSON *item=cJSON_New_Item();if(item)item->type=b?cJSON_True:cJSON_False;return item;}
+cJSON *cJSON_CreateNumber(double num)                  {cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_Number;item->valuedouble=num;item->valueint=(int)num;}return item;}
+cJSON *cJSON_CreateString(const char *string)  {cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_String;item->valuestring=cJSON_strdup(string);}return item;}
+cJSON *cJSON_CreateArray()                                             {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Array;return item;}
+cJSON *cJSON_CreateObject()                                            {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Object;return item;}
+
+/* Create Arrays: */
+cJSON *cJSON_CreateIntArray(int *numbers,int count)                            {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
+cJSON *cJSON_CreateFloatArray(float *numbers,int count)                        {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
+cJSON *cJSON_CreateDoubleArray(double *numbers,int count)              {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
+cJSON *cJSON_CreateStringArray(const char **strings,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateString(strings[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
diff --git a/linux_usr/cJSON.h b/linux_usr/cJSON.h
new file mode 100644 (file)
index 0000000..b7a6cd3
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+  Copyright (c) 2009 Dave Gamble
+  Permission is hereby granted, free of charge, to any person obtaining a copy
+  of this software and associated documentation files (the "Software"), to deal
+  in the Software without restriction, including without limitation the rights
+  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+  copies of the Software, and to permit persons to whom the Software is
+  furnished to do so, subject to the following conditions:
+  The above copyright notice and this permission notice shall be included in
+  all copies or substantial portions of the Software.
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+  THE SOFTWARE.
+*/
+
+#ifndef cJSON__h
+#define cJSON__h
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/* cJSON Types: */
+#define cJSON_False 0
+#define cJSON_True 1
+#define cJSON_NULL 2
+#define cJSON_Number 3
+#define cJSON_String 4
+#define cJSON_Array 5
+#define cJSON_Object 6
+       
+#define cJSON_IsReference 256
+
+/* The cJSON structure: */
+typedef struct cJSON {
+       struct cJSON *next,*prev;       /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
+       struct cJSON *child;            /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
+
+       int type;                                       /* The type of the item, as above. */
+
+       char *valuestring;                      /* The item's string, if type==cJSON_String */
+       int valueint;                           /* The item's number, if type==cJSON_Number */
+       double valuedouble;                     /* The item's number, if type==cJSON_Number */
+
+       char *string;                           /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
+} cJSON;
+
+typedef struct cJSON_Hooks {
+      void *(*malloc_fn)(size_t sz);
+      void (*free_fn)(void *ptr);
+} cJSON_Hooks;
+
+/* Supply malloc, realloc and free functions to cJSON */
+extern void cJSON_InitHooks(cJSON_Hooks* hooks);
+
+
+/* Supply a block of JSON, and this returns a cJSON object you can interrogate. Call cJSON_Delete when finished. */
+extern cJSON *cJSON_Parse(const char *value);
+/* Render a cJSON entity to text for transfer/storage. Free the char* when finished. */
+extern char  *cJSON_Print(cJSON *item);
+/* Render a cJSON entity to text for transfer/storage without any formatting. Free the char* when finished. */
+extern char  *cJSON_PrintUnformatted(cJSON *item);
+/* Delete a cJSON entity and all subentities. */
+extern void   cJSON_Delete(cJSON *c);
+
+/* Returns the number of items in an array (or object). */
+extern int       cJSON_GetArraySize(cJSON *array);
+/* Retrieve item number "item" from array "array". Returns NULL if unsuccessful. */
+extern cJSON *cJSON_GetArrayItem(cJSON *array,int item);
+/* Get item "string" from object. Case insensitive. */
+extern cJSON *cJSON_GetObjectItem(cJSON *object,const char *string);
+
+/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */
+extern const char *cJSON_GetErrorPtr();
+       
+/* These calls create a cJSON item of the appropriate type. */
+extern cJSON *cJSON_CreateNull();
+extern cJSON *cJSON_CreateTrue();
+extern cJSON *cJSON_CreateFalse();
+extern cJSON *cJSON_CreateBool(int b);
+extern cJSON *cJSON_CreateNumber(double num);
+extern cJSON *cJSON_CreateString(const char *string);
+extern cJSON *cJSON_CreateArray();
+extern cJSON *cJSON_CreateObject();
+
+/* These utilities create an Array of count items. */
+extern cJSON *cJSON_CreateIntArray(int *numbers,int count);
+extern cJSON *cJSON_CreateFloatArray(float *numbers,int count);
+extern cJSON *cJSON_CreateDoubleArray(double *numbers,int count);
+extern cJSON *cJSON_CreateStringArray(const char **strings,int count);
+
+/* Append item to the specified array/object. */
+extern void cJSON_AddItemToArray(cJSON *array, cJSON *item);
+extern void    cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item);
+/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */
+extern void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
+extern void    cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item);
+
+/* Remove/Detatch items from Arrays/Objects. */
+extern cJSON *cJSON_DetachItemFromArray(cJSON *array,int which);
+extern void   cJSON_DeleteItemFromArray(cJSON *array,int which);
+extern cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string);
+extern void   cJSON_DeleteItemFromObject(cJSON *object,const char *string);
+       
+/* Update array items. */
+extern void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem);
+extern void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);
+
+#define cJSON_AddNullToObject(object,name)     cJSON_AddItemToObject(object, name, cJSON_CreateNull())
+#define cJSON_AddTrueToObject(object,name)     cJSON_AddItemToObject(object, name, cJSON_CreateTrue())
+#define cJSON_AddFalseToObject(object,name)            cJSON_AddItemToObject(object, name, cJSON_CreateFalse())
+#define cJSON_AddNumberToObject(object,name,n) cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n))
+#define cJSON_AddStringToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateString(s))
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/linux_usr/v3_register_gm.c b/linux_usr/v3_register_gm.c
new file mode 100644 (file)
index 0000000..50411b2
--- /dev/null
@@ -0,0 +1,154 @@
+/* 
+ * V3 Guarded Module registration utility
+ *
+ * This code allows a user to register a 
+ * guest driver module to be guarded upon
+ * injection into a guest.  *
+ * (c) Kyle C. Hale, 2012
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <malloc.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+
+#include "v3_ctrl.h"
+#include "iface-guard-mods.h"
+#include "cJSON.h"
+
+#define SET_PRIV(x, i) ((x) |= 1U << (i))
+
+
+/* Parse text to JSON, then render back to text, and print! */
+static void 
+populate_gm (char * filename, struct v3_guard_mod * m)
+{
+    int fd, i, nents, nrets;
+    char * data;
+    struct stat stats;
+    cJSON *json, *tmp, *tmp2, *ep, *sub_ep;
+    
+       fd = open(filename, O_RDONLY);
+    if (fd < 0) {
+        fprintf(stderr, "Error opening file: %s\n", filename);
+        exit(0);
+    }
+
+    if (fstat(fd, &stats) == -1) {
+        fprintf(stderr, "Error stating file: %s\n", filename);
+        exit(0);
+    }
+
+       data = malloc(stats.st_size);
+    v3_read_file(fd, stats.st_size, data);
+    close(fd);
+
+       json = cJSON_Parse(data);
+
+       if (!json) {
+        fprintf(stderr, "Error before: [%s]\n",cJSON_GetErrorPtr());
+        goto out;
+    } 
+
+    m->name = cJSON_Print(cJSON_GetObjectItem(json, "module_name"));
+    m->content_hash = cJSON_Print(cJSON_GetObjectItem(json, "content_hash"));
+
+    tmp = cJSON_GetObjectItem(json, "size");
+    m->text_size = tmp->valueint;
+
+    tmp = cJSON_GetObjectItem(json, "hcall_offset");
+    m->hcall_offset = tmp->valueint;
+
+    /* extract all the valid entry points */
+    tmp = cJSON_GetObjectItem(json, "entry_points");
+    nents = cJSON_GetArraySize(tmp);
+
+    tmp2 = cJSON_GetObjectItem(json, "ret_points");
+    nrets = cJSON_GetArraySize(tmp2);
+
+
+    m->num_entries = nents + nrets;
+    printf("num entries: %d, nents: %d, nrets: %d\n", m->num_entries, nents, nrets);
+    m->entry_points = malloc(sizeof(struct v3_entry_point)*m->num_entries);
+
+    for (i = 0; i < nents; i++) {
+        ep = cJSON_GetArrayItem(tmp, i);
+        sub_ep = cJSON_GetArrayItem(ep, 0);
+
+        m->entry_points[i].name = cJSON_Print(sub_ep);
+        m->entry_points[i].is_ret = 0;
+
+        sub_ep = cJSON_GetArrayItem(ep, 1);
+        m->entry_points[i].offset = sub_ep->valueint;
+    }
+
+
+    for (i = nents; i < m->num_entries; i++) {
+        ep = cJSON_GetArrayItem(tmp2, i - nents);
+        sub_ep = cJSON_GetArrayItem(ep, 0);
+
+        m->entry_points[i].name = cJSON_Print(sub_ep);
+        m->entry_points[i].is_ret = 1;
+
+        sub_ep = cJSON_GetArrayItem(ep, 1);
+        m->entry_points[i].offset = sub_ep->valueint;
+    }
+
+    tmp = cJSON_GetObjectItem(json, "privileges");
+    m->num_privs = cJSON_GetArraySize(tmp);
+    m->priv_array = malloc(sizeof(char*)*m->num_privs);
+    if (!m->priv_array) {
+        fprintf(stderr, "Problem allocating privilege array in userspace\n");
+        goto out;
+    }
+
+    for (i = 0; i < m->num_privs; i++) {
+        ep = cJSON_GetArrayItem(tmp, i);
+        m->priv_array[i] = cJSON_Print(ep);
+    }
+
+out:
+    cJSON_Delete(json);
+       free(data);
+}
+
+
+int main (int argc, char **argv) {
+    struct v3_guard_mod mod; 
+    char *dev_file, *json_file;
+    uint64_t ret;
+
+    if (argc < 2) {
+        v3_usage("<vm-device> <json>\n");
+        return -1;
+    }
+
+    dev_file  = argv[1];
+    json_file = argv[2];
+
+    populate_gm(json_file, &mod);
+
+    printf("Registering guarded module: %s, size: %d, offset: %d\n", mod.name, mod.text_size, mod.hcall_offset);
+
+    mod.id = 0;
+
+    ret = v3_vm_ioctl(dev_file, V3_VM_REGISTER_MOD, &mod);
+
+    if (ret < 0) {
+        fprintf(stderr, "Problem registering module\n");
+        return -1;
+    }
+    
+    if (!mod.id) {
+        fprintf(stderr, "Could not register guarded module\n");
+    } else {
+        printf("Module successfully registered [0x%llx]\n", mod.id);
+    }
+
+       return 0;
+}
diff --git a/palacios/include/gears/guard_mods.h b/palacios/include/gears/guard_mods.h
new file mode 100644 (file)
index 0000000..806e550
--- /dev/null
@@ -0,0 +1,101 @@
+/* 
+ * This file is part of the Palacios Virtual Machine Monitor developed
+ * by the V3VEE Project with funding from the United States National 
+ * Science Foundation and the Department of Energy.  
+ *
+ * The V3VEE Project is a joint project between Northwestern University
+ * and the University of New Mexico.  You can find out more at 
+ * http://www.v3vee.org
+ *
+ * Copyright (c) 2012, Kyle C. Hale <kh@u.northwestern.edu> 
+ * Copyright (c) 2012, The V3VEE Project <http://www.v3vee.org> 
+ * All rights reserved.
+ *
+ * Author: Kyle C. Hale <kh@u.northwestern.edu>
+ *
+ * This is free software.  You are permitted to use,
+ * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
+ */
+
+#ifndef __GUARD_MODS_H__
+#define __GUARD_MODS_H__
+
+
+#ifdef __V3VEE__
+
+#define HCALL_INSTR_LEN 3
+#define MAX_BORDER_NESTING 128
+
+enum v3_mod_state {
+    INIT,
+    PRIV,
+    NO_PRIV,
+};
+
+/* these need to be updated when
+ * load address is received */
+struct v3_entry_point {
+    char * name;
+    addr_t addr;
+    uint8_t is_ret; /* indicates that this is a return point */
+
+    struct v3_gm * gm;
+    struct list_head er_node;
+};
+
+
+struct v3_gm {
+    char * name;
+    char * content_hash;
+    ulong_t stack_hash;
+    uint_t num_entries;
+    uint_t hcall_offset;
+    uint_t text_size;
+    addr_t load_addr;           /* this is a GVA */
+    ullong_t id;
+    struct v3_entry_point * entry_points;
+    enum v3_mod_state state;
+    struct list_head priv_list; /* list of privileges associated with this GM */
+    struct list_head mod_node;
+    struct list_head er_list;
+    void * private_data;
+    int callback_nesting;  
+    int kernel_nesting;
+    addr_t r11_stack_kernel[MAX_BORDER_NESTING];
+    addr_t r11_stack_callback[MAX_BORDER_NESTING];
+    addr_t entry_rsp;
+    addr_t exit_rsp;
+
+};
+
+#define V3_GUARD_INIT_HCALL  0x6000
+#define V3_BIN_CALL_HCALL    0x6001
+#define V3_BOUT_RET_HCALL    0x6002
+#define V3_BOUT_CALL_HCALL   0x6003
+#define V3_BIN_RET_HCALL     0x6004
+
+struct v3_guarded_mods {
+    struct list_head mod_list;
+    struct hashtable * mod_id_table;
+    struct hashtable * mod_name_table;
+    struct hashtable * er_hash;   /* hash for quick lookups on valid entries/returns */
+};
+
+
+#endif /* __V3VEE__ */
+
+unsigned long long
+v3_register_gm  (void *  vm, 
+                 char *  name,
+                 char *  hash,
+                 unsigned int hc_off,
+                 unsigned int size,
+                 unsigned int nentries,
+                 unsigned int nprivs,
+                 char ** priv_array,
+                 void * private_data, 
+                 void * entry_points);
+
+
+#endif /* __GUARD_MODS_H__ */
+
diff --git a/palacios/include/gears/privilege.h b/palacios/include/gears/privilege.h
new file mode 100644 (file)
index 0000000..4f3ca53
--- /dev/null
@@ -0,0 +1,52 @@
+#ifndef __PRIVILEGE_H__
+#define __PRIVILEGE_H__
+
+
+struct v3_privileges {
+
+    struct list_head priv_list;
+    struct hashtable * priv_table;
+
+};
+
+struct v3_priv {
+    const char * name;
+    
+
+    int (*init)   (struct guest_info * core, void ** private_data);
+    int (*lower)  (struct guest_info * core, void * private_data);
+    int (*raise)  (struct guest_info * core, void * private_data);
+    int (*deinit) (struct guest_info * core, void * private_data);
+
+    void * private_data;
+
+    struct list_head priv_node;
+    
+};
+
+struct v3_priv * v3_lookup_priv (struct v3_vm_info * vm, const char * name);
+
+int v3_core_raise_all_privs (struct guest_info * core);
+int v3_core_lower_all_privs (struct guest_info * core);
+
+int v3_bind_privilege (struct guest_info * core,
+                       const char * priv_name,
+                       int (*init)   (struct guest_info * core, void ** private_data),
+                       int (*lower)  (struct guest_info * core, void * private_data),
+                       int (*raise)  (struct guest_info * core, void * private_data),
+                       int (*deinit) (struct guest_info * core, void * private_data),
+                       void * priv_data);
+
+                           
+/*
+
+#define register_privilege(priv)                         \
+    static struct v3_priv * _v3_priv                     \
+    __attribute__((used))                                \
+    __attribute__((unused, __section__("_v3_privileges"),\
+                    aligned(sizeof(addr_t))))            \
+    = priv;
+
+*/
+
+#endif
index 46db427..1961d69 100644 (file)
@@ -7,6 +7,7 @@ config GEARS
       This is the Guest Examination and Revision Services, an extension used
       to modify guest code and implement guest-context VMM services in Palacios
 
+
 config EXT_SW_INTERRUPTS
     bool "Enable interception and hooking of software interrupts"
     depends on GEARS
@@ -101,4 +102,35 @@ config EXT_CODE_INJECT
          This option will allow code to be injected and run in the
          guest context
 
+config EXT_PRIV
+    bool "Allow privileges to be given to code modules"
+    depends on GEARS
+    default n
+    help
+      This option allows different code modules in the guest to be
+      given privileges such as uninhibited access to devices etc.
+
+config DEBUG_EXT_PRIV
+    bool "Allow privileged module debugging"
+    depends on EXT_PRIV
+    default n
+    help
+      Turns on debugging output for privilege extension
+
+config EXT_GUARD_MODULES
+    bool "Allow guarded execution of guest modules"
+    depends on GEARS
+    depends on EXT_PRIV
+    default n
+    help
+      This option allows priveledge hardware access to kernel drivers/modules
+      in the guest. Requires instrumentation of guest driver/module.
+
+config DEBUG_EXT_GUARD_MODS
+    bool "Allow guarded module debugging"
+    depends on EXT_GUARD_MODULES
+    default n
+    help
+      Turns on debugging output for guarded modules extension
+
 endmenu
index 001b043..8de6c26 100644 (file)
@@ -4,6 +4,8 @@ obj-$(V3_CONFIG_EXT_EXECVE_HOOK) += ext_execve_hook.o
 obj-$(V3_CONFIG_EXT_EXECVE_HOOK) += ext_process_environment.o
 obj-$(V3_CONFIG_EXT_CODE_INJECT) += ext_code_inject.o
 obj-$(V3_CONFIG_EXT_ENV_INJECT) += ext_env_inject.o
+obj-$(V3_CONFIG_EXT_GUARD_MODULES) += ext_guard_mods.o
+obj-$(V3_CONFIG_EXT_PRIV) += ext_priv.o
 
 obj-y += null.o
 
diff --git a/palacios/src/gears/ext_guard_mods.c b/palacios/src/gears/ext_guard_mods.c
new file mode 100644 (file)
index 0000000..0923255
--- /dev/null
@@ -0,0 +1,634 @@
+/* 
+ * This file is part of the Palacios Virtual Machine Monitor developed
+ * by the V3VEE Project with funding from the United States National 
+ * Science Foundation and the Department of Energy.  
+ *
+ * The V3VEE Project is a joint project between Northwestern University
+ * and the University of New Mexico.  You can find out more at 
+ * http://www.v3vee.org
+ *
+ * Copyright (c) 2012, Kyle C. Hale <kh@u.norhtwestern.edu>
+ * Copyright (c) 2012, The V3VEE Project <http://www.v3vee.org> 
+ * All rights reserved.
+ *
+ * Author: Kyle C. Hale <kh@u.northwestern.edu>
+ *
+ * This is free software.  You are permitted to use,
+ * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
+ */
+
+#include <palacios/vmm.h>
+#include <palacios/vm_guest.h>
+#include <palacios/vm_guest_mem.h>
+#include <palacios/vmm_extensions.h>
+#include <palacios/vmm_decoder.h>
+#include <palacios/vmm_types.h>
+#include <palacios/vmm_hypercall.h>
+#include <palacios/vmm_hashtable.h>
+#include <palacios/vmm_util.h>
+#include <palacios/vmm_mem_hook.h>
+#include <palacios/vmcb.h>
+#include <gears/privilege.h>
+#include <gears/guard_mods.h>
+
+#ifndef V3_CONFIG_DEBUG_EXT_GUARD_MODS
+#undef PrintDebug
+#define PrintDebug(fmt, args...)
+#endif
+
+
+static struct v3_guarded_mods global_mods;
+
+static struct v3_gm * current_gm;
+
+/* generates an id for a module using
+ * the TSC and a hash */
+static inline void 
+gen_mod_id (ullong_t * id) 
+{
+    ullong_t val, ret;
+    rdtscll(val);
+    ret = (ullong_t)v3_hash_long((ulong_t)val, sizeof(ullong_t)*8);
+    PrintDebug(VM_NONE, VCORE_NONE,"GM: Generating new module ID: 0x%llx\n", ret);
+    *id = ret;
+}
+
+
+static inline void 
+free_mod (struct v3_gm * mod) 
+{
+    struct v3_priv * p = NULL;
+    struct v3_priv * tmp = NULL;
+    struct v3_entry_point * er = NULL;
+    struct v3_entry_point * etmp = NULL;
+    int i;
+
+    /* free the privilege list */
+    list_for_each_entry_safe(p, tmp, &(mod->priv_list), priv_node) {
+        list_del(&(p->priv_node));
+        V3_Free(p);
+    }
+
+    V3_Free(mod->name);
+    V3_Free(mod->content_hash);
+
+    list_for_each_entry_safe(er, etmp, &(mod->er_list), er_node) {
+        list_del(&er->er_node);
+    }
+
+    for (i = 0; i < mod->num_entries; i++) {
+        V3_Free(mod->entry_points[i].name);
+    }
+
+    V3_Free(mod->entry_points);
+    V3_Free(mod);
+}
+
+
+static int 
+add_privs_to_list (struct v3_vm_info * vm,
+                   struct list_head * list, 
+                   unsigned int nprivs,
+                   char ** priv_array)
+{
+    struct v3_priv * priv = NULL;
+    int i;
+
+    for (i = 0 ; i < nprivs; i++) {
+        if ((priv = v3_lookup_priv(vm, priv_array[i])) == NULL) {
+            PrintError(VM_NONE, VCORE_NONE,"Guarded module requested non-existent privilege: %s\n", priv_array[i]);
+            return -1;
+        } else {
+            list_add(&(priv->priv_node), list);
+        }
+    }
+    
+    return 0;
+}
+
+
+static uint_t 
+mod_name_hash_fn (addr_t key)
+{
+    char * name = (char*)key;
+    return v3_hash_buffer((uint8_t*)name, strlen(name));
+}
+
+
+static int 
+mod_name_eq_fn (addr_t key1, addr_t key2)
+{
+    char * name1 = (char*)key1;
+    char * name2 = (char*)key2;
+    return (strcmp(name1, name2) == 0);
+}
+
+
+static uint_t 
+mod_id_hash_fn (addr_t key) 
+{
+    return v3_hash_long(key, sizeof(ullong_t) * 8);
+}
+
+
+static int 
+mod_id_eq_fn (addr_t key1, addr_t key2) 
+{
+    return (key1 == key2);
+}
+
+
+static uint_t 
+entry_addr_hash_fn (addr_t key) 
+{
+    return v3_hash_long(key, sizeof(addr_t) * 8);
+}
+
+
+static int 
+entry_addr_eq_fn (addr_t key1, addr_t key2) 
+{
+    return (key1 == key2);
+}
+
+
+/* GUARD INIT 
+ *
+ * This is invoked through a hypercall that has been instrumented in the
+ * guarded module's routine denoted by the module_init macro.
+ */
+/* TODO: add text hash check here */
+static int
+guard_init (struct guest_info * core, unsigned int hcall_id, void * priv_data)
+{
+    ullong_t mod_id;
+    struct v3_gm * gm;
+    struct v3_guarded_mods * mods = &global_mods;
+    struct v3_entry_point * er = NULL;
+    struct v3_entry_point * tmp = NULL;
+    struct v3_priv * priv = NULL;
+    struct v3_priv * ptmp = NULL;
+
+    /* the guarded module should provide its ID in RBX */
+    mod_id = core->vm_regs.rbx;
+
+    V3_Print(VM_NONE, VCORE_NONE, "Received init request from GM (id=0x%llx)\n", mod_id);
+
+    /* check if the corresponding module exists */
+    if ((gm = (struct v3_gm*)v3_htable_search(mods->mod_id_table, (addr_t)mod_id)) == 0) {
+        PrintError(VM_NONE, VCORE_NONE,"Module (id=0x%llx) not found\n", mod_id);
+        return -1;
+    }
+
+    PrintDebug(VM_NONE, VCORE_NONE,"GM: initializing guarded module %s\n", gm->name);
+
+    /* infer load address */
+    gm->load_addr = core->rip - HCALL_INSTR_LEN - gm->hcall_offset;
+    
+    PrintDebug(VM_NONE, VCORE_NONE,"\tNew GM load address: %p\n", (void*)gm->load_addr);
+
+    list_for_each_entry_safe(er, tmp, &(gm->er_list), er_node) {
+
+        /* fix up the dynamic address of the entry point */
+        er->addr += gm->load_addr;
+
+        /* check if this entry point already exists */
+        if (v3_htable_search(mods->er_hash, er->addr)) {
+            PrintError(VM_NONE, VCORE_NONE,"GM: Error! Entry point already exists!\n");
+            return -1;
+        }
+
+        /* add the new entry point to the global hash */
+        v3_htable_insert(mods->er_hash, er->addr, (addr_t)er);
+    }
+
+    PrintDebug(VM_NONE, VCORE_NONE,"GM: Raising privileges\n");
+
+    
+    /* module will come up in privileged mode */
+    gm->state = PRIV;
+
+    /* raise all of the module's privileges */
+    list_for_each_entry_safe(priv, ptmp, &(gm->priv_list), priv_node) {
+        if (priv->raise(core, priv->private_data) < 0) {
+            PrintError(VM_NONE, VCORE_NONE,"GM: Problem raising privilege\n");
+            return -1;
+        }
+    }
+
+    /* get the entry RSP for integrity checks */
+    addr_t hva;
+    if (v3_gva_to_hva(core, 
+        get_addr_linear(core, (addr_t)core->vm_regs.rsp, &(core->segments.ss)),
+        &hva) < 0) {
+            PrintError(VM_NONE, VCORE_NONE,"GM: Problem translating stack address\n");
+            return -1;
+    }
+    gm->entry_rsp = hva;
+
+    /* this is just to be consistent with other entry types, r11 isn't used in init */
+    gm->r11_stack_callback[gm->callback_nesting] = core->vm_regs.r11;
+    gm->callback_nesting++;
+
+    PrintDebug(VM_NONE, VCORE_NONE,"GM: Guarded module initialized, set to PRIV\n");
+
+    current_gm = gm;
+
+    return 0;
+}
+
+
+/* BORDER IN CALL
+ *
+ * This is invoked when the kernel calls the module (through a callback function)
+ *
+ * TODO: the stack checking model here is crappy, but will be updated to only
+ * look at frame pointers and return addresses. 
+ */
+static int 
+border_in_call (struct guest_info * core, unsigned int hcall_id, void * priv_data)
+{
+    struct v3_guarded_mods * mods = &global_mods;
+    struct v3_entry_point * er;
+    struct v3_gm * gm = current_gm;
+    struct v3_priv * priv = NULL;
+    struct v3_priv * tmp = NULL;
+
+
+    addr_t entry = core->rip - HCALL_INSTR_LEN;
+
+    er = (struct v3_entry_point*)v3_htable_search(mods->er_hash, entry);
+    if (!er) {
+        PrintError(VM_NONE, VCORE_NONE,"Attempt to enter at an invalid entry point (%p)\n", (void*)entry);
+    } else {
+
+        gm = er->gm;
+
+        /* if this is first entry, record rsp */
+        if (gm->callback_nesting == 0) {
+            addr_t hva;
+            if (v3_gva_to_hva(core, 
+               get_addr_linear(core, (addr_t)core->vm_regs.rsp, &core->segments.ss),
+               &hva) < 0) {
+                    PrintError(VM_NONE, VCORE_NONE,"GM: Problem translating stack address\n");
+                    return -1;
+            }
+            gm->entry_rsp = hva;
+        }
+
+        if (gm->callback_nesting >= MAX_BORDER_NESTING) {
+            PrintError(VM_NONE, VCORE_NONE,"GM: Too much nesting of border crossings\n");
+            return -1;
+        } else {
+            gm->r11_stack_callback[gm->callback_nesting] = core->vm_regs.r11;
+            gm->callback_nesting++;
+        }
+
+        if (gm->state == INIT) {
+            PrintError(VM_NONE, VCORE_NONE,"ERROR: module reached guard entry without being initialized!\n");
+            return 0;
+        }
+
+        gm->state = PRIV;
+
+        PrintDebug(VM_NONE, VCORE_NONE,"Entry request at %p granted to GM (%s)\n", (void*)entry, gm->name);
+
+        list_for_each_entry_safe(priv, tmp, &(gm->priv_list), priv_node) {
+
+            if (priv->raise(core, priv->private_data) < 0) {
+                PrintError(VM_NONE, VCORE_NONE,"GM: Problem raising privilege\n");
+                return -1;
+            }
+
+        }
+
+    }
+    
+    return 0;
+}
+
+
+/*  BORDER-OUT RETURN
+ * 
+ * This is invoked when the module returns to the kernel, after being invoked through
+ * a callback function.
+ */
+static int 
+border_out_return (struct guest_info * core, unsigned int hcall_id, void * priv_data) 
+{
+    struct v3_gm * gm = current_gm;
+    struct v3_priv * priv = NULL;
+    struct v3_priv * tmp = NULL;
+
+    gm->callback_nesting--;
+
+    /* restore the guest's return address */
+    core->vm_regs.r11 = gm->r11_stack_callback[gm->callback_nesting];
+    gm->r11_stack_callback[gm->callback_nesting] = 0;
+
+    /* Only lower privilege when we reach nesting 0 */
+    if (gm->callback_nesting <= 0)  {
+
+        PrintDebug(VM_NONE, VCORE_NONE,"GM: Granting exit request to GM (%s)\n", gm->name);
+        list_for_each_entry_safe(priv, tmp, &(gm->priv_list), priv_node) {
+
+            if (priv->lower(core, priv->private_data) < 0) {
+                PrintError(VM_NONE, VCORE_NONE,"GM: Problem lowering privilege\n");
+                return -1;
+            }
+        
+        }
+
+        gm->state = NO_PRIV;
+
+    } else {
+        PrintDebug(VM_NONE, VCORE_NONE,"Priv Lower requested, but still at nesting level (%d)\n", gm->callback_nesting);
+    }
+
+    return 0;
+}
+
+
+/* BORDER-OUT CALL
+ *
+ * This is invoked when the module calls out to the kernel, results in lowering of privilege
+ *
+ */
+static int
+border_out_call (struct guest_info * core, unsigned int hcall_id, void * priv_data) {
+
+    struct v3_gm * gm = current_gm;
+    struct v3_priv * priv = NULL;
+    struct v3_priv * tmp = NULL;
+
+    /* TODO: um...we seem to be getting a border out call in NO_PRIV state */
+    if (1 || gm->state == PRIV || gm->state == INIT) {
+
+        gm->r11_stack_kernel[gm->kernel_nesting] = core->vm_regs.r11;
+        gm->kernel_nesting++;
+
+        PrintDebug(VM_NONE, VCORE_NONE,"GM: Granting border out call request to GM (%s)\n", gm->name);
+        list_for_each_entry_safe(priv, tmp, &(gm->priv_list), priv_node) {
+            if (priv->lower(core, priv->private_data) < 0) {
+                PrintError(VM_NONE, VCORE_NONE,"GM: Problem lowering privilege\n");
+                return -1;
+            }
+
+        }
+
+        if (v3_gva_to_hva(core, 
+            get_addr_linear(core, (addr_t)core->vm_regs.rsp, &(core->segments.ss)),
+            &gm->exit_rsp) < 0) {
+            PrintError(VM_NONE, VCORE_NONE,"GM: border out, error translating rsp addr\n");
+            return -1;
+        }
+
+        if (gm->entry_rsp && gm->exit_rsp && gm->state == PRIV && (gm->entry_rsp >= gm->exit_rsp)) {
+            gm->stack_hash = v3_hash_buffer((uchar_t*)gm->exit_rsp, gm->entry_rsp - gm->exit_rsp);
+        }
+
+        gm->state = NO_PRIV;
+
+    } else {
+        PrintError(VM_NONE, VCORE_NONE,"GM: Trying to run border-out without privilege\n"); 
+    }
+
+    /* else, do nothing */
+    return 0;
+}
+
+
+/* BORDER-IN RETURN
+ * 
+ * This is invoked when the kernel returns control to the module after a border-out call
+ * Results in privilege raise
+ *
+ */
+static int
+border_in_return (struct guest_info * core, unsigned int hcall_id, void * priv_data) {
+    struct v3_guarded_mods * mods = &global_mods;
+    struct v3_gm * gm = NULL;
+    struct v3_priv * priv = NULL;
+    struct v3_priv * tmp = NULL;
+    struct v3_entry_point * er = NULL;
+
+    addr_t entry = core->rip - HCALL_INSTR_LEN;
+    if ((er = (struct v3_entry_point*)v3_htable_search(mods->er_hash, entry)) == 0) {
+        PrintError(VM_NONE, VCORE_NONE,"Attempt to enter at an invalid entry point (%p)\n", (void*)entry);
+    } else {
+        gm = er->gm;
+
+        /* restore the guest's return address */
+        gm->kernel_nesting--;
+        core->vm_regs.r11 = gm->r11_stack_kernel[gm->kernel_nesting];
+        gm->r11_stack_kernel[gm->kernel_nesting] = 0;
+
+        
+        if (gm->state == NO_PRIV) {
+            PrintDebug(VM_NONE, VCORE_NONE,"GM: Granting border in return request to GM (%s)\n", gm->name);
+            list_for_each_entry_safe(priv, tmp, &(gm->priv_list), priv_node) {
+                if (priv->raise(core, priv->private_data) < 0) {
+                    PrintError(VM_NONE, VCORE_NONE,"GM: Problem raising privilege\n");
+                    return -1;
+                }
+            }
+
+            if (gm->entry_rsp && gm->exit_rsp && (gm->entry_rsp > gm->exit_rsp)) {
+                if (v3_hash_buffer((uchar_t*)gm->exit_rsp, gm->entry_rsp - gm->exit_rsp) != gm->stack_hash) {
+                }
+            }
+
+            gm->state = PRIV;
+        } 
+    }
+
+    return 0;
+}
+
+
+static int 
+init_gm (struct v3_vm_info * vm, v3_cfg_tree_t * cfg, void ** priv_data) 
+{
+    struct v3_guarded_mods * mods = &global_mods;
+    
+    *priv_data = mods;
+
+    INIT_LIST_HEAD(&(mods->mod_list));
+
+    if (!(mods->mod_name_table = v3_create_htable(0, mod_name_hash_fn, mod_name_eq_fn))) {
+        PrintError(VM_NONE, VCORE_NONE,"GM: Could not create GM module name hashtable\n");
+        return -1;
+    }
+
+    if (!(mods->mod_id_table = v3_create_htable(0, mod_id_hash_fn, mod_id_eq_fn))) {
+        PrintError(VM_NONE, VCORE_NONE,"GM: Could not create GM module ID hashtable\n");
+        return -1;
+    }
+
+    if (!(mods->er_hash = v3_create_htable(0, entry_addr_hash_fn, entry_addr_eq_fn))) {
+        PrintError(VM_NONE, VCORE_NONE,"GM: Could not create GM entry point hashtable\n");
+        return -1;
+    }
+
+    /* these hypercalls will be invoked with a module id (hash) in rax. */
+    if (v3_register_hypercall(vm, V3_BIN_CALL_HCALL, border_in_call, mods) < 0    ||
+        v3_register_hypercall(vm, V3_BOUT_RET_HCALL, border_out_return, mods) < 0 ||
+        v3_register_hypercall(vm, V3_BIN_RET_HCALL, border_in_return, mods) < 0   ||
+        v3_register_hypercall(vm, V3_BOUT_CALL_HCALL, border_out_call, mods) < 0  ||
+        v3_register_hypercall(vm, V3_GUARD_INIT_HCALL, guard_init, mods) < 0) {
+        PrintError(VM_NONE, VCORE_NONE,"GM: Problem registering hypercalls\n");
+        return -1;
+    }
+
+    return 0;
+}
+
+
+static int 
+deinit_gm (struct v3_vm_info * vm, void * priv_data) 
+{
+    struct v3_guarded_mods * mods = (struct v3_guarded_mods *)priv_data;
+    struct v3_gm * mod = NULL;
+    struct v3_gm * tmp = NULL;
+
+    list_for_each_entry_safe(mod, tmp, &(mods->mod_list), mod_node) {
+        free_mod(mod);
+    }
+
+    v3_free_htable(mods->mod_id_table, 0, 0);
+    v3_free_htable(mods->mod_name_table, 0, 0);
+    v3_free_htable(mods->er_hash, 0, 0);
+
+    if (v3_remove_hypercall(vm, V3_BIN_CALL_HCALL) < 0 ||
+        v3_remove_hypercall(vm, V3_BOUT_RET_HCALL) < 0  ||
+        v3_remove_hypercall(vm, V3_BIN_RET_HCALL) < 0  ||
+        v3_remove_hypercall(vm, V3_BOUT_CALL_HCALL) < 0  ||
+        v3_remove_hypercall(vm, V3_GUARD_INIT_HCALL) < 0) {
+
+        PrintError(VM_NONE, VCORE_NONE,"GM: Problem removing GM hypercalls\n");
+        return -1;
+    }
+
+    return 0;
+}
+
+
+/* returns 0 on error, module id on success */
+unsigned long long
+v3_register_gm  (void *  vm, 
+                 char *  name,
+                 char *  hash,
+                 unsigned int hc_off,
+                 unsigned int size,
+                 unsigned int nentries,
+                 unsigned int nprivs,
+                 char ** priv_array,
+                 void * private_data, 
+                 void * entry_points)
+{
+    struct v3_guarded_mods * mods = &global_mods;
+    struct v3_gm * mod;
+    ullong_t mod_id;
+    int i;
+    char * tmp;
+
+    if (!name) {
+        PrintError(VM_NONE, VCORE_NONE,"Invalid module name\n");
+        return 0;
+    }
+
+    if (v3_htable_search(mods->mod_name_table, (addr_t)name)) {
+        PrintError(VM_NONE, VCORE_NONE,"Multiple instances of guarded module (%s)\n", name);
+        return 0;
+    }
+
+    /* generate a unique identifier for this module */
+    gen_mod_id(&mod_id);  
+
+    mod = (struct v3_gm *)V3_Malloc(sizeof(struct v3_gm));
+    if (!mod) {
+        PrintError(VM_NONE, VCORE_NONE,"Problem allocating guarded module\n");
+        return 0;
+    }
+
+    memset(mod, 0, sizeof(struct v3_gm));
+
+    V3_Print(VM_NONE, VCORE_NONE, "V3 GM Registration: received name (%s)\n", name);
+    mod->name = V3_Malloc(strlen(name)+1);
+    if (!mod->name) {
+        PrintError(VM_NONE, VCORE_NONE,"Problem allocating space for mod name\n");
+        return -1;
+    }
+
+    V3_Print(VM_NONE, VCORE_NONE, "V3 GM Registration: received hash (%s)\n", hash);
+    mod->content_hash = V3_Malloc(strlen(hash)+1);
+    if (!mod->content_hash) {
+        PrintError(VM_NONE, VCORE_NONE,"Problem allocating space for content hash\n");
+        return -1;
+    }
+    strcpy(mod->name, name);
+    strcpy(mod->content_hash, hash);
+
+    mod->hcall_offset     = hc_off;
+    mod->text_size        = size;
+    mod->num_entries      = nentries;
+    mod->private_data     = private_data;
+    mod->id               = mod_id;
+    mod->callback_nesting = 0;
+    mod->kernel_nesting   = 0;
+
+    INIT_LIST_HEAD(&(mod->priv_list));
+    if (add_privs_to_list(vm, &(mod->priv_list), nprivs, priv_array) == -1) {
+        PrintError(VM_NONE, VCORE_NONE,"Could not add privileges to guarded module\n");
+        return -1;
+    }
+
+    mod->state      = INIT;
+    mod->stack_hash = 0;
+
+    /* setup the valid entry points */
+    INIT_LIST_HEAD(&(mod->er_list));
+
+    mod->entry_points = V3_Malloc(sizeof(struct v3_entry_point)*mod->num_entries);
+
+    if (!mod->entry_points) {
+        PrintError(VM_NONE, VCORE_NONE,"Problem allocating entry point array\n");
+        return -1;
+    }
+
+    memcpy(mod->entry_points, entry_points, sizeof(struct v3_entry_point)*mod->num_entries);
+    
+    /* entries are added to the list, but can't be hashed yet since we're using
+     * the load address as a key, but we haven't fixed these addresses up yet */
+    for (i = 0; i < mod->num_entries; i++) {
+        tmp = V3_Malloc(strlen(mod->entry_points[i].name)+1);
+        if (!tmp) {
+            PrintError(VM_NONE, VCORE_NONE,"Problem allocating space for name locally\n");
+            return -1;
+        }
+        strcpy(tmp, mod->entry_points[i].name);
+        mod->entry_points[i].name = tmp;
+        mod->entry_points[i].gm   = mod;
+        list_add(&(mod->entry_points[i].er_node), &(mod->er_list));
+    }
+
+    //v3_htable_insert(mods->mod_id_table, mod_id, (addr_t)mod);
+    // TODO: this will change the content hash of the module code segment, fix!
+    v3_htable_insert(mods->mod_id_table, (addr_t)0xa3aeea3aeebadbad, (addr_t)mod);
+    v3_htable_insert(mods->mod_name_table, (addr_t)name, (addr_t)mod);
+    list_add(&(mod->mod_node), &(mods->mod_list));
+    return mod_id;
+}
+
+
+static struct v3_extension_impl guard_mods_impl = {
+       .name = "guard_mods",
+       .vm_init = init_gm,
+       .vm_deinit = deinit_gm,
+       .core_init = NULL,
+       .core_deinit = NULL,
+       .on_entry = NULL,
+       .on_exit = NULL
+};
+
+register_extension(&guard_mods_impl);
diff --git a/palacios/src/gears/ext_priv.c b/palacios/src/gears/ext_priv.c
new file mode 100644 (file)
index 0000000..06eb7d9
--- /dev/null
@@ -0,0 +1,219 @@
+/* 
+ * This file is part of the Palacios Virtual Machine Monitor developed
+ * by the V3VEE Project with funding from the United States National 
+ * Science Foundation and the Department of Energy.  
+ *
+ * The V3VEE Project is a joint project between Northwestern University
+ * and the University of New Mexico.  You can find out more at 
+ * http://www.v3vee.org
+ *
+ * Copyright (c) 2012, Kyle C. Hale <kh@u.norhtwestern.edu>
+ * Copyright (c) 2012, The V3VEE Project <http://www.v3vee.org> 
+ * All rights reserved.
+ *
+ * Author: Kyle C. Hale <kh@u.northwestern.edu>
+ *
+ * This is free software.  You are permitted to use,
+ * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
+ */
+
+#include <palacios/vmm.h>
+#include <palacios/vmm_string.h>
+#include <palacios/vmm_hashtable.h>
+#include <palacios/vmm_extensions.h>
+#include <palacios/vmm_decoder.h>
+#include <palacios/vm_guest.h>
+#include <palacios/vm_guest_mem.h>
+
+#include <gears/privilege.h>
+
+#ifndef V3_CONFIG_DEBUG_EXT_PRIV
+#undef PrintDebug
+#define PrintDebug(fmt, args...)
+#endif
+
+static struct v3_privileges * global_privs;
+
+static uint_t 
+priv_hash_fn (addr_t key) 
+{
+    return v3_hash_buffer((uint8_t*)key, strlen((char*)key));
+}
+
+
+static int 
+priv_eq_fn (addr_t key1, addr_t key2) 
+{
+    return (strcmp((char*)key1, (char*)key2) == 0);
+}
+
+
+static int 
+init_priv (struct v3_vm_info * vm, v3_cfg_tree_t * cfg, void ** priv_data) 
+{
+    struct v3_privileges * p = V3_Malloc(sizeof(struct v3_privileges));
+
+    global_privs = p;
+
+    if (!p) {
+        PrintError(VM_NONE, VCORE_NONE,"Priv: Problem allocating privileges\n");
+        return -1;
+    }
+
+    INIT_LIST_HEAD(&(p->priv_list));
+
+    *priv_data = p;
+
+    if (!(p->priv_table = v3_create_htable(0, priv_hash_fn, priv_eq_fn))) {
+        PrintError(VM_NONE, VCORE_NONE,"Priv: Problem creating privilege hash table\n");
+        return -1;
+    }
+
+    return 0;
+}
+
+
+static int 
+deinit_priv (struct v3_vm_info * vm, void * priv_data) 
+{
+    struct v3_privileges * privs = (struct v3_privileges *)priv_data;
+    struct v3_priv * p = NULL;
+    struct v3_priv * tmp = NULL;
+
+    list_for_each_entry_safe(p, tmp, &(privs->priv_list), priv_node) {
+        list_del(&(p->priv_node));
+        V3_Free(p);
+    }
+
+    v3_free_htable(privs->priv_table, 0, 0);
+
+    return 0;
+}
+
+
+struct v3_priv * 
+v3_lookup_priv (struct v3_vm_info * vm, const char * name) 
+{
+    struct v3_privileges * p = global_privs;
+    return ((struct v3_priv*)v3_htable_search(p->priv_table, (addr_t)name));
+}
+
+
+static int 
+deinit_all_privs (struct guest_info * core, 
+                     void * priv_data,
+                     void * core_data) 
+{
+    struct v3_privileges * p = global_privs;
+    struct v3_priv * priv = NULL;
+    struct v3_priv * tmp = NULL;
+
+    list_for_each_entry_safe(priv, tmp, &p->priv_list, priv_node) {
+        if (priv->deinit(core, priv->private_data) < 0) {
+            PrintError(VM_NONE, VCORE_NONE,"Problem deiniting privilege on core (%s)\n", priv->name);
+        }
+    }
+
+    return 0;
+}
+
+
+int 
+v3_core_raise_all_privs (struct guest_info * core)
+{
+    struct v3_privileges * p = global_privs;
+    struct v3_priv * priv = NULL;
+    struct v3_priv * tmp = NULL;
+
+    list_for_each_entry_safe(priv, tmp, &p->priv_list, priv_node) {
+    
+        if (priv->raise(core, priv->private_data) < 0) {
+            PrintError(VM_NONE, VCORE_NONE,"Priv: Problem lowering privilege on core (%s)\n", priv->name);
+            return -1;
+        }
+
+    }
+
+    return 0;
+}
+
+
+int 
+v3_core_lower_all_privs (struct guest_info * core) 
+{
+    struct v3_privileges * p = global_privs;
+    struct v3_priv * priv = NULL;
+    struct v3_priv * tmp = NULL;
+
+    list_for_each_entry_safe(priv, tmp, &p->priv_list, priv_node) {
+        
+        if (priv->lower(core, priv->private_data) < 0) {
+            PrintError(VM_NONE, VCORE_NONE,"Priv: Problem lowering privilege on core (%s)\n", priv->name);
+            return -1;
+        }
+
+    }
+
+    return 0;
+}
+
+
+int 
+v3_bind_privilege (struct guest_info * core,
+                   const char * priv_name,
+                   int (*init)   (struct guest_info * core, void ** private_data),
+                   int (*lower)  (struct guest_info * core, void * private_data),
+                   int (*raise)  (struct guest_info * core, void * private_data),
+                   int (*deinit) (struct guest_info * core, void * private_data),
+                   void * priv_data)
+{
+    struct v3_privileges * p = global_privs;
+    struct v3_priv * priv = v3_lookup_priv(core->vm_info, priv_name);
+    if (priv) {
+        PrintError(VM_NONE, VCORE_NONE,"Priv: Privilege (%s) already exists\n", priv_name);
+        return -1;
+    }
+
+    priv = (struct v3_priv *)V3_Malloc(sizeof(struct v3_priv));
+    
+    if (!priv) {
+        PrintError(VM_NONE, VCORE_NONE,"Priv: Problem allocating privilege\n");
+        return -1;
+    }
+
+    PrintDebug(VM_NONE, VCORE_NONE,"Priv: Binding privilege (%s)\n", priv_name);
+
+    priv->init         = init;
+    priv->lower        = lower;
+    priv->raise        = raise;
+    priv->deinit       = deinit;
+    priv->private_data = priv_data;
+
+    if (v3_htable_insert(p->priv_table, (addr_t)priv_name, (addr_t)priv) == 0) {
+        PrintError(VM_NONE, VCORE_NONE,"Priv: Could not register privilege (%s)\n", priv_name);
+        return -1;
+    }
+
+    if (priv->init(core, &priv->private_data) < 0) {
+        PrintError(VM_NONE, VCORE_NONE,"Priv: Could not initialize privilege (%s)\n", priv_name);
+        return -1;
+    }
+
+    V3_Print(VM_NONE, VCORE_NONE, "Privilege (%s) bound and initialized successfully\n", priv_name);
+
+    return 0;
+}
+                            
+
+
+static struct v3_extension_impl priv_impl = {
+       .name = "privilege",
+       .vm_init = init_priv,
+       .vm_deinit = deinit_priv,
+       .core_init = NULL,
+       .core_deinit = deinit_all_privs,
+       .on_entry = NULL,
+       .on_exit = NULL
+};
+
+register_extension(&priv_impl);