All of lore.kernel.org
 help / color / mirror / Atom feed
* [Xense-devel][PATCH][2/4] Xen Securtiy Modules: FLASK
@ 2007-05-07 21:41 George S. Coker, II
  2007-05-07 23:24 ` Chris Wright
  2007-05-08  3:15 ` Mark Williamson
  0 siblings, 2 replies; 5+ messages in thread
From: George S. Coker, II @ 2007-05-07 21:41 UTC (permalink / raw)
  To: xen-devel, xense-devel

[-- Attachment #1: Type: text/plain, Size: 176 bytes --]

Updates in this patch set include:
    - reintroduction of rcu locking support in security cache 
    - track xsm changes

Signed-off-by: George Coker <gscoker@alpha.ncsc.mil>

[-- Attachment #2: flask-xsm-050707-xen-15011.diff --]
[-- Type: text/x-patch, Size: 299572 bytes --]

diff -r 62b752969edf -r 2b79cd115561 Config.mk
--- a/Config.mk	Mon May 07 14:50:16 2007 -0400
+++ b/Config.mk	Mon May 07 14:51:17 2007 -0400
@@ -75,6 +75,14 @@ CFLAGS += $(foreach i, $(EXTRA_INCLUDES)
 #Enable XSM security module.  Enabling XSM requires selection of an 
 #XSM security module.
 XSM_ENABLE ?= y
+ifeq ($(XSM_ENABLE),y)
+FLASK_ENABLE ?= y
+ifeq ($(FLASK_ENABLE),y)
+FLASK_DEVELOP ?= y
+FLASK_BOOTPARAM ?= y
+FLASK_AVC_STATS ?= y
+endif
+endif
 
 # If ACM_SECURITY = y, then the access control module is compiled
 # into Xen and the policy type can be set by the boot policy file
diff -r 62b752969edf -r 2b79cd115561 xen/Rules.mk
--- a/xen/Rules.mk	Mon May 07 14:50:16 2007 -0400
+++ b/xen/Rules.mk	Mon May 07 14:51:17 2007 -0400
@@ -51,13 +51,17 @@ ALL_OBJS-$(ACM_SECURITY) += $(BASEDIR)/a
 ALL_OBJS-$(ACM_SECURITY) += $(BASEDIR)/acm/built_in.o
 ALL_OBJS-y               += $(BASEDIR)/arch/$(TARGET_ARCH)/built_in.o
 
-CFLAGS-y               += -g -D__XEN__
-CFLAGS-$(XSM_ENABLE)   += -DXSM_ENABLE
-CFLAGS-$(ACM_SECURITY) += -DACM_SECURITY
-CFLAGS-$(verbose)      += -DVERBOSE
-CFLAGS-$(crash_debug)  += -DCRASH_DEBUG
-CFLAGS-$(perfc)        += -DPERF_COUNTERS
-CFLAGS-$(perfc_arrays) += -DPERF_ARRAYS
+CFLAGS-y                  += -g -D__XEN__
+CFLAGS-$(XSM_ENABLE)      += -DXSM_ENABLE
+CFLAGS-$(FLASK_ENABLE)    += -DFLASK_ENABLE -DXSM_MAGIC=0xf97cff8c
+CFLAGS-$(FLASK_DEVELOP)   += -DFLASK_DEVELOP
+CFLAGS-$(FLASK_BOOTPARAM) += -DFLASK_BOOTPARAM
+CFLAGS-$(FLASK_AVC_STATS) += -DFLASK_AVC_STATS
+CFLAGS-$(ACM_SECURITY)    += -DACM_SECURITY
+CFLAGS-$(verbose)         += -DVERBOSE
+CFLAGS-$(crash_debug)     += -DCRASH_DEBUG
+CFLAGS-$(perfc)           += -DPERF_COUNTERS
+CFLAGS-$(perfc_arrays)    += -DPERF_ARRAYS
 
 ifneq ($(max_phys_cpus),)
 CFLAGS-y               += -DMAX_PHYS_CPUS=$(max_phys_cpus)
diff -r 62b752969edf -r 2b79cd115561 xen/common/vsprintf.c
--- a/xen/common/vsprintf.c	Mon May 07 14:50:16 2007 -0400
+++ b/xen/common/vsprintf.c	Mon May 07 14:51:17 2007 -0400
@@ -513,6 +513,224 @@ EXPORT_SYMBOL(vscnprintf);
 EXPORT_SYMBOL(vscnprintf);
 
 /**
+ * vsscanf - Unformat a buffer into a list of arguments
+ * @buf:	input buffer
+ * @fmt:	format of buffer
+ * @args:	arguments
+ */
+int vsscanf(const char * buf, const char * fmt, va_list args)
+{
+	const char *str = buf;
+	const char *next;
+	char digit;
+	int num = 0;
+	int qualifier;
+	int base;
+	int field_width;
+	int is_sign = 0;
+
+	while(*fmt && *str) {
+		/* skip any white space in format */
+		/* white space in format matchs any amount of
+		 * white space, including none, in the input.
+		 */
+		if (isspace(*fmt)) {
+			while (isspace(*fmt))
+				++fmt;
+			while (isspace(*str))
+				++str;
+		}
+
+		/* anything that is not a conversion must match exactly */
+		if (*fmt != '%' && *fmt) {
+			if (*fmt++ != *str++)
+				break;
+			continue;
+		}
+
+		if (!*fmt)
+			break;
+		++fmt;
+		
+		/* skip this conversion.
+		 * advance both strings to next white space
+		 */
+		if (*fmt == '*') {
+			while (!isspace(*fmt) && *fmt)
+				fmt++;
+			while (!isspace(*str) && *str)
+				str++;
+			continue;
+		}
+
+		/* get field width */
+		field_width = -1;
+		if (isdigit(*fmt))
+			field_width = skip_atoi(&fmt);
+
+		/* get conversion qualifier */
+		qualifier = -1;
+		if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' ||
+		    *fmt == 'Z' || *fmt == 'z') {
+			qualifier = *fmt++;
+			if (unlikely(qualifier == *fmt)) {
+				if (qualifier == 'h') {
+					qualifier = 'H';
+					fmt++;
+				} else if (qualifier == 'l') {
+					qualifier = 'L';
+					fmt++;
+				}
+			}
+		}
+		base = 10;
+		is_sign = 0;
+
+		if (!*fmt || !*str)
+			break;
+
+		switch(*fmt++) {
+		case 'c':
+		{
+			char *s = (char *) va_arg(args,char*);
+			if (field_width == -1)
+				field_width = 1;
+			do {
+				*s++ = *str++;
+			} while (--field_width > 0 && *str);
+			num++;
+		}
+		continue;
+		case 's':
+		{
+			char *s = (char *) va_arg(args, char *);
+			if(field_width == -1)
+				field_width = INT_MAX;
+			/* first, skip leading white space in buffer */
+			while (isspace(*str))
+				str++;
+
+			/* now copy until next white space */
+			while (*str && !isspace(*str) && field_width--) {
+				*s++ = *str++;
+			}
+			*s = '\0';
+			num++;
+		}
+		continue;
+		case 'n':
+			/* return number of characters read so far */
+		{
+			int *i = (int *)va_arg(args,int*);
+			*i = str - buf;
+		}
+		continue;
+		case 'o':
+			base = 8;
+			break;
+		case 'x':
+		case 'X':
+			base = 16;
+			break;
+		case 'i':
+                        base = 0;
+		case 'd':
+			is_sign = 1;
+		case 'u':
+			break;
+		case '%':
+			/* looking for '%' in str */
+			if (*str++ != '%') 
+				return num;
+			continue;
+		default:
+			/* invalid format; stop here */
+			return num;
+		}
+
+		/* have some sort of integer conversion.
+		 * first, skip white space in buffer.
+		 */
+		while (isspace(*str))
+			str++;
+
+		digit = *str;
+		if (is_sign && digit == '-')
+			digit = *(str + 1);
+
+		if (!digit
+                    || (base == 16 && !isxdigit(digit))
+                    || (base == 10 && !isdigit(digit))
+                    || (base == 8 && (!isdigit(digit) || digit > '7'))
+                    || (base == 0 && !isdigit(digit)))
+				break;
+
+		switch(qualifier) {
+		case 'H':	/* that's 'hh' in format */
+			if (is_sign) {
+				signed char *s = (signed char *) va_arg(args,signed char *);
+				*s = (signed char) simple_strtol(str,&next,base);
+			} else {
+				unsigned char *s = (unsigned char *) va_arg(args, unsigned char *);
+				*s = (unsigned char) simple_strtoul(str, &next, base);
+			}
+			break;
+		case 'h':
+			if (is_sign) {
+				short *s = (short *) va_arg(args,short *);
+				*s = (short) simple_strtol(str,&next,base);
+			} else {
+				unsigned short *s = (unsigned short *) va_arg(args, unsigned short *);
+				*s = (unsigned short) simple_strtoul(str, &next, base);
+			}
+			break;
+		case 'l':
+			if (is_sign) {
+				long *l = (long *) va_arg(args,long *);
+				*l = simple_strtol(str,&next,base);
+			} else {
+				unsigned long *l = (unsigned long*) va_arg(args,unsigned long*);
+				*l = simple_strtoul(str,&next,base);
+			}
+			break;
+		case 'L':
+			if (is_sign) {
+				long long *l = (long long*) va_arg(args,long long *);
+				*l = simple_strtoll(str,&next,base);
+			} else {
+				unsigned long long *l = (unsigned long long*) va_arg(args,unsigned long long*);
+				*l = simple_strtoull(str,&next,base);
+			}
+			break;
+		case 'Z':
+		case 'z':
+		{
+			size_t *s = (size_t*) va_arg(args,size_t*);
+			*s = (size_t) simple_strtoul(str,&next,base);
+		}
+		break;
+		default:
+			if (is_sign) {
+				int *i = (int *) va_arg(args, int*);
+				*i = (int) simple_strtol(str,&next,base);
+			} else {
+				unsigned int *i = (unsigned int*) va_arg(args, unsigned int*);
+				*i = (unsigned int) simple_strtoul(str,&next,base);
+			}
+			break;
+		}
+		num++;
+
+		if (!next)
+			break;
+		str = next;
+	}
+	return num;
+}
+
+EXPORT_SYMBOL(vsscanf);
+
+/**
  * snprintf - Format a string and place it in a buffer
  * @buf: The buffer to place the result into
  * @size: The size of the buffer, including the trailing null space
@@ -561,6 +779,25 @@ int scnprintf(char * buf, size_t size, c
 }
 EXPORT_SYMBOL(scnprintf);
 
+/**
+ * sscanf - Unformat a buffer into a list of arguments
+ * @buf:	input buffer
+ * @fmt:	formatting of buffer
+ * @...:	resulting arguments
+ */
+int sscanf(const char * buf, const char * fmt, ...)
+{
+	va_list args;
+	int i;
+
+	va_start(args,fmt);
+	i = vsscanf(buf,fmt,args);
+	va_end(args);
+	return i;
+}
+
+EXPORT_SYMBOL(sscanf);
+
 /*
  * Local variables:
  * mode: C
diff -r 62b752969edf -r 2b79cd115561 xen/include/public/flask_op.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/include/public/flask_op.h	Mon May 07 14:51:17 2007 -0400
@@ -0,0 +1,44 @@
+/*
+ *  This file contains the flask_op hypercall commands and definitions.
+ *
+ *  Author:  George Coker, <gscoker@alpha.ncsc.mil>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2,
+ *  as published by the Free Software Foundation.
+ */
+
+#ifndef __FLASK_OP_H__
+#define __FLASK_OP_H__
+
+#define FLASK_LOAD              1
+#define FLASK_GETENFORCE        2
+#define FLASK_SETENFORCE        3
+#define FLASK_CONTEXT_TO_SID    4
+#define FLASK_SID_TO_CONTEXT    5
+#define FLASK_ACCESS            6
+#define FLASK_CREATE            7
+#define FLASK_RELABEL           8
+#define FLASK_USER              9
+#define FLASK_POLICYVERS        10
+#define FLASK_GETBOOL           11
+#define FLASK_SETBOOL           12
+#define FLASK_COMMITBOOLS       13
+#define FLASK_MLS               14
+#define FLASK_DISABLE           15
+#define FLASK_GETAVC_THRESHOLD  16
+#define FLASK_SETAVC_THRESHOLD  17
+#define FLASK_AVC_HASHSTATS     18
+#define FLASK_AVC_CACHESTATS    19
+#define FLASK_MEMBER            20
+
+typedef struct flask_op {
+    int   size;
+    char *buf;
+} flask_op_t;
+
+DEFINE_XEN_GUEST_HANDLE(flask_op_t);
+
+long do_flask_op (int cmd, XEN_GUEST_HANDLE(xsm_op_t) u_flask_op);
+
+#endif
diff -r 62b752969edf -r 2b79cd115561 xen/include/xen/lib.h
--- a/xen/include/xen/lib.h	Mon May 07 14:50:16 2007 -0400
+++ b/xen/include/xen/lib.h	Mon May 07 14:51:17 2007 -0400
@@ -75,6 +75,10 @@ extern int scnprintf(char * buf, size_t 
     __attribute__ ((format (printf, 3, 4)));
 extern int vscnprintf(char *buf, size_t size, const char *fmt, va_list args)
     __attribute__ ((format (printf, 3, 0)));
+extern int sscanf(const char * buf, const char * fmt, ...)
+    __attribute__ ((format (scanf, 2, 3)));
+extern int vsscanf(const char * buf, const char * fmt, va_list args)
+    __attribute__ ((format (scanf, 2, 0)));
 
 long simple_strtol(
     const char *cp,const char **endp, unsigned int base);
diff -r 62b752969edf -r 2b79cd115561 xen/xsm/Makefile
--- a/xen/xsm/Makefile	Mon May 07 14:50:16 2007 -0400
+++ b/xen/xsm/Makefile	Mon May 07 14:51:17 2007 -0400
@@ -3,3 +3,5 @@ ifeq ($(XSM_ENABLE),y)
 ifeq ($(XSM_ENABLE),y)
 obj-y += dummy.o
 endif
+
+subdir-$(FLASK_ENABLE) += flask
diff -r 62b752969edf -r 2b79cd115561 xen/xsm/flask/Makefile
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/Makefile	Mon May 07 14:51:17 2007 -0400
@@ -0,0 +1,7 @@
+obj-y += avc.o
+obj-y += hooks.o
+obj-y += flask_op.o
+
+subdir-y += ss
+
+CFLAGS += -I./include
diff -r 62b752969edf -r 2b79cd115561 xen/xsm/flask/avc.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/avc.c	Mon May 07 14:51:17 2007 -0400
@@ -0,0 +1,779 @@
+/*
+ * Implementation of the kernel access vector cache (AVC).
+ *
+ * Authors:  Stephen Smalley, <sds@epoch.ncsc.mil>
+ *           James Morris <jmorris@redhat.com>
+ *
+ * Update:   KaiGai, Kohei <kaigai@ak.jp.nec.com>
+ *     Replaced the avc_lock spinlock by RCU.
+ *
+ * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License version 2,
+ *      as published by the Free Software Foundation.
+ */
+ 
+/* Ported to Xen 3.0, George Coker, <gscoker@alpha.ncsc.mil> */
+ 
+#include <xen/lib.h>
+#include <xen/xmalloc.h>
+#include <xen/types.h>
+#include <xen/list.h>
+#include <xen/spinlock.h>
+#include <xen/prefetch.h>
+#include <xen/kernel.h>
+#include <xen/sched.h>
+#include <xen/init.h>
+#include <xen/rcupdate.h>
+#include <asm/atomic.h>
+#include <asm/current.h>
+
+#include "avc.h"
+#include "avc_ss.h"
+
+static const struct av_perm_to_string
+{
+    u16 tclass;
+    u32 value;
+    const char *name;
+} av_perm_to_string[] = {
+#define S_(c, v, s) { c, v, s },
+#include "av_perm_to_string.h"
+#undef S_
+};
+
+static const char *class_to_string[] = {
+#define S_(s) s,
+#include "class_to_string.h"
+#undef S_
+};
+
+#define TB_(s) static const char * s [] = {
+#define TE_(s) };
+#define S_(s) s,
+#include "common_perm_to_string.h"
+#undef TB_
+#undef TE_
+#undef S_
+
+static const struct av_inherit
+{
+    u16 tclass;
+    const char **common_pts;
+    u32 common_base;
+} av_inherit[] = {
+#define S_(c, i, b) { c, common_##i##_perm_to_string, b },
+#include "av_inherit.h"
+#undef S_
+};
+
+#define AVC_CACHE_SLOTS            512
+#define AVC_DEF_CACHE_THRESHOLD        512
+#define AVC_CACHE_RECLAIM        16
+
+#ifdef FLASK_AVC_STATS
+#define avc_cache_stats_incr(field)                 \
+do {                                \
+    __get_cpu_var(avc_cache_stats).field++;        \
+} while (0)
+#else
+#define avc_cache_stats_incr(field)    do {} while (0)
+#endif
+
+struct avc_entry {
+    u32            ssid;
+    u32            tsid;
+    u16            tclass;
+    struct av_decision    avd;
+    atomic_t        used;    /* used recently */
+};
+
+struct avc_node {
+    struct avc_entry    ae;
+    struct list_head    list;
+    struct rcu_head     rhead;
+};
+
+struct avc_cache {
+    struct list_head    slots[AVC_CACHE_SLOTS];
+    spinlock_t        slots_lock[AVC_CACHE_SLOTS]; /* lock for writes */
+    atomic_t        lru_hint;    /* LRU hint for reclaim scan */
+    atomic_t        active_nodes;
+    u32            latest_notif;    /* latest revocation notification */
+};
+
+struct avc_callback_node {
+    int (*callback) (u32 event, u32 ssid, u32 tsid,
+                     u16 tclass, u32 perms,
+                     u32 *out_retained);
+    u32 events;
+    u32 ssid;
+    u32 tsid;
+    u16 tclass;
+    u32 perms;
+    struct avc_callback_node *next;
+};
+
+/* Exported via Flask hypercall */
+unsigned int avc_cache_threshold = AVC_DEF_CACHE_THRESHOLD;
+
+#ifdef FLASK_AVC_STATS
+DEFINE_PER_CPU(struct avc_cache_stats, avc_cache_stats) = { 0 };
+#endif
+
+static struct avc_cache avc_cache;
+static struct avc_callback_node *avc_callbacks;
+
+static inline int avc_hash(u32 ssid, u32 tsid, u16 tclass)
+{
+    return (ssid ^ (tsid<<2) ^ (tclass<<4)) & (AVC_CACHE_SLOTS - 1);
+}
+
+/**
+ * avc_dump_av - Display an access vector in human-readable form.
+ * @tclass: target security class
+ * @av: access vector
+ */
+static void avc_dump_av(u16 tclass, u32 av)
+{
+    const char **common_pts = NULL;
+    u32 common_base = 0;
+    int i, i2, perm;
+
+    if (av == 0) {
+        printk(" null");
+        return;
+    }
+
+    for (i = 0; i < ARRAY_SIZE(av_inherit); i++) {
+        if (av_inherit[i].tclass == tclass) {
+            common_pts = av_inherit[i].common_pts;
+            common_base = av_inherit[i].common_base;
+            break;
+        }
+    }
+
+    printk(" {");
+    i = 0;
+    perm = 1;
+    while (perm < common_base) {
+        if (perm & av) {
+            printk(" %s", common_pts[i]);
+            av &= ~perm;
+        }
+        i++;
+        perm <<= 1;
+    }
+
+    while (i < sizeof(av) * 8) {
+        if (perm & av) {
+            for (i2 = 0; i2 < ARRAY_SIZE(av_perm_to_string); i2++) {
+                if ((av_perm_to_string[i2].tclass == tclass) &&
+                    (av_perm_to_string[i2].value == perm))
+                    break;
+            }
+            if (i2 < ARRAY_SIZE(av_perm_to_string)) {
+                printk(" %s", av_perm_to_string[i2].name);
+                av &= ~perm;
+            }
+        }
+        i++;
+        perm <<= 1;
+    }
+
+    if (av)
+        printk(" 0x%x", av);
+
+    printk(" }");
+}
+
+/**
+ * avc_dump_query - Display a SID pair and a class in human-readable form.
+ * @ssid: source security identifier
+ * @tsid: target security identifier
+ * @tclass: target security class
+ */
+static void avc_dump_query(u32 ssid, u32 tsid, u16 tclass)
+{
+    int rc;
+    char *scontext;
+    u32 scontext_len;
+
+    rc = security_sid_to_context(ssid, &scontext, &scontext_len);
+    if (rc)
+        printk("ssid=%d", ssid);
+    else {
+        printk("scontext=%s", scontext);
+        xfree(scontext);
+    }
+
+    rc = security_sid_to_context(tsid, &scontext, &scontext_len);
+    if (rc)
+        printk(" tsid=%d", tsid);
+    else {
+        printk(" tcontext=%s", scontext);
+        xfree(scontext);
+    }
+    printk("\n");
+    printk("tclass=%s", class_to_string[tclass]);
+}
+
+/**
+ * avc_init - Initialize the AVC.
+ *
+ * Initialize the access vector cache.
+ */
+void __init avc_init(void)
+{
+    int i;
+
+    for (i = 0; i < AVC_CACHE_SLOTS; i++) {
+        INIT_LIST_HEAD(&avc_cache.slots[i]);
+        spin_lock_init(&avc_cache.slots_lock[i]);
+    }
+    atomic_set(&avc_cache.active_nodes, 0);
+    atomic_set(&avc_cache.lru_hint, 0);
+
+    printk("AVC INITIALIZED\n");
+}
+
+int avc_get_hash_stats(char *page)
+{
+    int i, chain_len, max_chain_len, slots_used;
+    struct avc_node *node;
+
+    rcu_read_lock();
+
+    slots_used = 0;
+    max_chain_len = 0;
+    for (i = 0; i < AVC_CACHE_SLOTS; i++) {
+        if (!list_empty(&avc_cache.slots[i])) {
+            slots_used++;
+            chain_len = 0;
+            list_for_each_entry_rcu(node, &avc_cache.slots[i], list)
+                chain_len++;
+            if (chain_len > max_chain_len)
+                max_chain_len = chain_len;
+        }
+    }
+
+    rcu_read_unlock();
+    
+    return snprintf(page, PAGE_SIZE, "entries: %d\nbuckets used: %d/%d\n"
+             "longest chain: %d\n",
+             atomic_read(&avc_cache.active_nodes),
+             slots_used, AVC_CACHE_SLOTS, max_chain_len);
+}
+
+static void avc_node_free(struct rcu_head *rhead)
+{
+    struct avc_node *node = container_of(rhead, struct avc_node, rhead);
+    xfree(node);
+    avc_cache_stats_incr(frees);
+}
+
+static void avc_node_delete(struct avc_node *node)
+{
+    list_del_rcu(&node->list);
+    call_rcu(&node->rhead, avc_node_free);
+    atomic_dec(&avc_cache.active_nodes);
+}
+
+static void avc_node_kill(struct avc_node *node)
+{
+    xfree(node);
+    avc_cache_stats_incr(frees);
+    atomic_dec(&avc_cache.active_nodes);
+}
+
+static void avc_node_replace(struct avc_node *new, struct avc_node *old)
+{
+    list_replace_rcu(&old->list, &new->list);
+    call_rcu(&old->rhead, avc_node_free);
+    atomic_dec(&avc_cache.active_nodes);
+}
+
+static inline int avc_reclaim_node(void)
+{
+    struct avc_node *node;
+    int hvalue, try, ecx;
+	unsigned long flags;
+
+    for (try = 0, ecx = 0; try < AVC_CACHE_SLOTS; try++ ) {
+        atomic_inc(&avc_cache.lru_hint);
+        hvalue =  atomic_read(&avc_cache.lru_hint) & (AVC_CACHE_SLOTS - 1);
+
+		spin_lock_irqsave(&avc_cache.slots_lock[hvalue], flags);
+
+        list_for_each_entry(node, &avc_cache.slots[hvalue], list) {
+            if (atomic_dec_and_test(&node->ae.used)) {
+                /* Recently Unused */
+                avc_node_delete(node);
+                avc_cache_stats_incr(reclaims);
+                ecx++;
+                if (ecx >= AVC_CACHE_RECLAIM) {
+					spin_unlock_irqrestore(&avc_cache.slots_lock[hvalue], flags);
+                    goto out;
+                }
+            }
+        }
+		spin_unlock_irqrestore(&avc_cache.slots_lock[hvalue], flags);
+    }    
+out:
+    return ecx;
+}
+
+static struct avc_node *avc_alloc_node(void)
+{
+    struct avc_node *node;
+
+    node = xmalloc(struct avc_node);
+    if (!node)
+        goto out;
+
+    memset(node, 0, sizeof(*node));
+    INIT_RCU_HEAD(&node->rhead);
+    INIT_LIST_HEAD(&node->list);
+    atomic_set(&node->ae.used, 1);
+    avc_cache_stats_incr(allocations);
+
+    atomic_inc(&avc_cache.active_nodes);
+    if (atomic_read(&avc_cache.active_nodes) > avc_cache_threshold)
+        avc_reclaim_node();
+
+out:
+    return node;
+}
+
+static void avc_node_populate(struct avc_node *node, u32 ssid, u32 tsid, u16 tclass, struct avc_entry *ae)
+{
+    node->ae.ssid = ssid;
+    node->ae.tsid = tsid;
+    node->ae.tclass = tclass;
+    memcpy(&node->ae.avd, &ae->avd, sizeof(node->ae.avd));
+}
+
+static inline struct avc_node *avc_search_node(u32 ssid, u32 tsid, u16 tclass)
+{
+    struct avc_node *node, *ret = NULL;
+    int hvalue;
+
+    hvalue = avc_hash(ssid, tsid, tclass);
+    list_for_each_entry_rcu(node, &avc_cache.slots[hvalue], list) {
+        if (ssid == node->ae.ssid &&
+            tclass == node->ae.tclass &&
+            tsid == node->ae.tsid) {
+            ret = node;
+            break;
+        }
+    }
+
+    if (ret == NULL) {
+        /* cache miss */
+        goto out;
+    }
+
+    /* cache hit */
+    if (atomic_read(&ret->ae.used) != 1)
+        atomic_set(&ret->ae.used, 1);
+out:
+    return ret;
+}
+
+/**
+ * avc_lookup - Look up an AVC entry.
+ * @ssid: source security identifier
+ * @tsid: target security identifier
+ * @tclass: target security class
+ * @requested: requested permissions, interpreted based on @tclass
+ *
+ * Look up an AVC entry that is valid for the
+ * @requested permissions between the SID pair
+ * (@ssid, @tsid), interpreting the permissions
+ * based on @tclass.  If a valid AVC entry exists,
+ * then this function return the avc_node.
+ * Otherwise, this function returns NULL.
+ */
+static struct avc_node *avc_lookup(u32 ssid, u32 tsid, u16 tclass, u32 requested)
+{
+    struct avc_node *node;
+
+    avc_cache_stats_incr(lookups);
+    node = avc_search_node(ssid, tsid, tclass);
+
+    if (node && ((node->ae.avd.decided & requested) == requested)) {
+        avc_cache_stats_incr(hits);
+        goto out;
+    }
+
+    node = NULL;
+    avc_cache_stats_incr(misses);
+out:
+    return node;
+}
+
+static int avc_latest_notif_update(int seqno, int is_insert)
+{
+    int ret = 0;
+    static DEFINE_SPINLOCK(notif_lock);
+    unsigned long flag;
+
+    spin_lock_irqsave(&notif_lock, flag);
+    if (is_insert) {
+        if (seqno < avc_cache.latest_notif) {
+            printk(KERN_WARNING "avc:  seqno %d < latest_notif %d\n",
+                   seqno, avc_cache.latest_notif);
+            ret = -EAGAIN;
+        }
+    } else {
+        if (seqno > avc_cache.latest_notif)
+            avc_cache.latest_notif = seqno;
+    }
+    spin_unlock_irqrestore(&notif_lock, flag);
+
+    return ret;
+}
+
+/**
+ * avc_insert - Insert an AVC entry.
+ * @ssid: source security identifier
+ * @tsid: target security identifier
+ * @tclass: target security class
+ * @ae: AVC entry
+ *
+ * Insert an AVC entry for the SID pair
+ * (@ssid, @tsid) and class @tclass.
+ * The access vectors and the sequence number are
+ * normally provided by the security server in
+ * response to a security_compute_av() call.  If the
+ * sequence number @ae->avd.seqno is not less than the latest
+ * revocation notification, then the function copies
+ * the access vectors into a cache entry, returns
+ * avc_node inserted. Otherwise, this function returns NULL.
+ */
+static struct avc_node *avc_insert(u32 ssid, u32 tsid, u16 tclass, struct avc_entry *ae)
+{
+    struct avc_node *pos, *node = NULL;
+    int hvalue;
+	unsigned long flag;
+
+    if (avc_latest_notif_update(ae->avd.seqno, 1))
+        goto out;
+
+    node = avc_alloc_node();
+    if (node) {
+        hvalue = avc_hash(ssid, tsid, tclass);
+        avc_node_populate(node, ssid, tsid, tclass, ae);
+
+		spin_lock_irqsave(&avc_cache.slots_lock[hvalue], flag);
+        list_for_each_entry(pos, &avc_cache.slots[hvalue], list) {
+            if (pos->ae.ssid == ssid &&
+                pos->ae.tsid == tsid &&
+                pos->ae.tclass == tclass) {
+                    avc_node_replace(node, pos);
+                goto found;
+            }
+        }
+        list_add_rcu(&node->list, &avc_cache.slots[hvalue]);
+found:
+		spin_unlock_irqrestore(&avc_cache.slots_lock[hvalue], flag);
+    }
+out:
+    return node;
+}
+
+/**
+ * avc_audit - Audit the granting or denial of permissions.
+ * @ssid: source security identifier
+ * @tsid: target security identifier
+ * @tclass: target security class
+ * @requested: requested permissions
+ * @avd: access vector decisions
+ * @result: result from avc_has_perm_noaudit
+ * @a:  auxiliary audit data
+ *
+ * Audit the granting or denial of permissions in accordance
+ * with the policy.  This function is typically called by
+ * avc_has_perm() after a permission check, but can also be
+ * called directly by callers who use avc_has_perm_noaudit()
+ * in order to separate the permission check from the auditing.
+ * For example, this separation is useful when the permission check must
+ * be performed under a lock, to allow the lock to be released
+ * before calling the auditing code.
+ */
+void avc_audit(u32 ssid, u32 tsid,
+               u16 tclass, u32 requested,
+               struct av_decision *avd, int result, struct avc_audit_data *a)
+{
+    struct domain *d = current->domain;
+    u32 denied, audited;
+
+    denied = requested & ~avd->allowed;
+    if (denied) {
+        audited = denied;
+        if (!(audited & avd->auditdeny))
+            return;
+    } else if (result) {
+        audited = denied = requested;
+        } else {
+        audited = requested;
+        if (!(audited & avd->auditallow))
+            return;
+    }
+
+    printk("avc:  %s ", denied ? "denied" : "granted");
+    avc_dump_av(tclass, audited);
+    printk(" for ");
+
+    if (a && a->d)
+        d = a->d;
+    if (d)
+        printk("domid=%d", d->domain_id);
+
+    printk("\n");
+    avc_dump_query(ssid, tsid, tclass);
+    printk("\n");
+
+}
+
+/**
+ * avc_add_callback - Register a callback for security events.
+ * @callback: callback function
+ * @events: security events
+ * @ssid: source security identifier or %SECSID_WILD
+ * @tsid: target security identifier or %SECSID_WILD
+ * @tclass: target security class
+ * @perms: permissions
+ *
+ * Register a callback function for events in the set @events
+ * related to the SID pair (@ssid, @tsid) and
+ * and the permissions @perms, interpreting
+ * @perms based on @tclass.  Returns %0 on success or
+ * -%ENOMEM if insufficient memory exists to add the callback.
+ */
+int avc_add_callback(int (*callback)(u32 event, u32 ssid, u32 tsid,
+                                     u16 tclass, u32 perms,
+                                     u32 *out_retained),
+                     u32 events, u32 ssid, u32 tsid,
+                     u16 tclass, u32 perms)
+{
+    struct avc_callback_node *c;
+    int rc = 0;
+
+    c = xmalloc(struct avc_callback_node);
+    if (!c) {
+        rc = -ENOMEM;
+        goto out;
+    }
+
+    c->callback = callback;
+    c->events = events;
+    c->ssid = ssid;
+    c->tsid = tsid;
+    c->perms = perms;
+    c->next = avc_callbacks;
+    avc_callbacks = c;
+out:
+    return rc;
+}
+
+static inline int avc_sidcmp(u32 x, u32 y)
+{
+    return (x == y || x == SECSID_WILD || y == SECSID_WILD);
+}
+
+/**
+ * avc_update_node Update an AVC entry
+ * @event : Updating event
+ * @perms : Permission mask bits
+ * @ssid,@tsid,@tclass : identifier of an AVC entry
+ *
+ * if a valid AVC entry doesn't exist,this function returns -ENOENT.
+ * if kmalloc() called internal returns NULL, this function returns -ENOMEM.
+ * otherwise, this function update the AVC entry. The original AVC-entry object
+ * will release later by RCU.
+ */
+static int avc_update_node(u32 event, u32 perms, u32 ssid, u32 tsid, u16 tclass)
+{
+    int hvalue, rc = 0;
+	unsigned long flag;
+    struct avc_node *pos, *node, *orig = NULL;
+    
+    node = avc_alloc_node();
+    if (!node) {
+        rc = -ENOMEM;
+        goto out;
+    }
+
+    hvalue = avc_hash(ssid, tsid, tclass);    
+	spin_lock_irqsave(&avc_cache.slots_lock[hvalue], flag);
+
+    list_for_each_entry(pos, &avc_cache.slots[hvalue], list){
+        if ( ssid==pos->ae.ssid &&
+             tsid==pos->ae.tsid &&
+             tclass==pos->ae.tclass ){
+            orig = pos;
+            break;
+        }
+    }
+
+    if (!orig) {
+        rc = -ENOENT;
+        avc_node_kill(node);
+        goto out_unlock;
+    }
+
+    /*
+     * Copy and replace original node.
+     */
+
+    avc_node_populate(node, ssid, tsid, tclass, &orig->ae);
+
+    switch (event) {
+    case AVC_CALLBACK_GRANT:
+        node->ae.avd.allowed |= perms;
+        break;
+    case AVC_CALLBACK_TRY_REVOKE:
+    case AVC_CALLBACK_REVOKE:
+        node->ae.avd.allowed &= ~perms;
+        break;
+    case AVC_CALLBACK_AUDITALLOW_ENABLE:
+        node->ae.avd.auditallow |= perms;
+        break;
+    case AVC_CALLBACK_AUDITALLOW_DISABLE:
+        node->ae.avd.auditallow &= ~perms;
+        break;
+    case AVC_CALLBACK_AUDITDENY_ENABLE:
+        node->ae.avd.auditdeny |= perms;
+        break;
+    case AVC_CALLBACK_AUDITDENY_DISABLE:
+        node->ae.avd.auditdeny &= ~perms;
+        break;
+    }
+    avc_node_replace(node, orig);
+out_unlock:
+	spin_unlock_irqrestore(&avc_cache.slots_lock[hvalue], flag);
+out:
+    return rc;
+}
+
+/**
+ * avc_ss_reset - Flush the cache and revalidate migrated permissions.
+ * @seqno: policy sequence number
+ */
+int avc_ss_reset(u32 seqno)
+{
+    struct avc_callback_node *c;
+    int i, rc = 0;
+	unsigned long flag;
+    struct avc_node *node;
+
+    for (i = 0; i < AVC_CACHE_SLOTS; i++) {
+		spin_lock_irqsave(&avc_cache.slots_lock[i], flag);
+        list_for_each_entry(node, &avc_cache.slots[i], list)
+            avc_node_delete(node);
+		spin_unlock_irqrestore(&avc_cache.slots_lock[i], flag);
+    }
+    
+    for (c = avc_callbacks; c; c = c->next) {
+        if (c->events & AVC_CALLBACK_RESET) {
+            rc = c->callback(AVC_CALLBACK_RESET,
+                     0, 0, 0, 0, NULL);
+            if (rc)
+                goto out;
+        }
+    }
+
+    avc_latest_notif_update(seqno, 0);
+out:
+    return rc;
+}
+
+/**
+ * avc_has_perm_noaudit - Check permissions but perform no auditing.
+ * @ssid: source security identifier
+ * @tsid: target security identifier
+ * @tclass: target security class
+ * @requested: requested permissions, interpreted based on @tclass
+ * @avd: access vector decisions
+ *
+ * Check the AVC to determine whether the @requested permissions are granted
+ * for the SID pair (@ssid, @tsid), interpreting the permissions
+ * based on @tclass, and call the security server on a cache miss to obtain
+ * a new decision and add it to the cache.  Return a copy of the decisions
+ * in @avd.  Return %0 if all @requested permissions are granted,
+ * -%EACCES if any permissions are denied, or another -errno upon
+ * other errors.  This function is typically called by avc_has_perm(),
+ * but may also be called directly to separate permission checking from
+ * auditing, e.g. in cases where a lock must be held for the check but
+ * should be released for the auditing.
+ */
+int avc_has_perm_noaudit(u32 ssid, u32 tsid,
+                         u16 tclass, u32 requested,
+                         struct av_decision *avd)
+{
+    struct avc_node *node;
+    struct avc_entry entry, *p_ae;
+    int rc = 0;
+    u32 denied;
+
+    rcu_read_lock();
+
+    node = avc_lookup(ssid, tsid, tclass, requested);
+    if (!node) {
+        rcu_read_unlock();
+        rc = security_compute_av(ssid,tsid,tclass,requested,&entry.avd);
+        if (rc)
+            goto out;
+        rcu_read_lock();
+        node = avc_insert(ssid,tsid,tclass,&entry);
+    }
+
+    p_ae = node ? &node->ae : &entry;
+
+    if (avd)
+        memcpy(avd, &p_ae->avd, sizeof(*avd));
+
+    denied = requested & ~(p_ae->avd.allowed);
+
+    if (!requested || denied) {
+        if (flask_enforcing)
+            rc = -EACCES;
+        else
+            if (node)
+                avc_update_node(AVC_CALLBACK_GRANT,requested,
+                        ssid,tsid,tclass);
+    }
+
+    rcu_read_unlock();
+out:
+    return rc;
+}
+
+/**
+ * avc_has_perm - Check permissions and perform any appropriate auditing.
+ * @ssid: source security identifier
+ * @tsid: target security identifier
+ * @tclass: target security class
+ * @requested: requested permissions, interpreted based on @tclass
+ * @auditdata: auxiliary audit data
+ *
+ * Check the AVC to determine whether the @requested permissions are granted
+ * for the SID pair (@ssid, @tsid), interpreting the permissions
+ * based on @tclass, and call the security server on a cache miss to obtain
+ * a new decision and add it to the cache.  Audit the granting or denial of
+ * permissions in accordance with the policy.  Return %0 if all @requested
+ * permissions are granted, -%EACCES if any permissions are denied, or
+ * another -errno upon other errors.
+ */
+int avc_has_perm(u32 ssid, u32 tsid, u16 tclass,
+                 u32 requested, struct avc_audit_data *auditdata)
+{
+    struct av_decision avd;
+    int rc;
+
+    rc = avc_has_perm_noaudit(ssid, tsid, tclass, requested, &avd);
+    avc_audit(ssid, tsid, tclass, requested, &avd, rc, auditdata);
+    return rc;
+}
diff -r 62b752969edf -r 2b79cd115561 xen/xsm/flask/flask_op.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/flask_op.c	Mon May 07 14:51:17 2007 -0400
@@ -0,0 +1,1046 @@
+/*
+ *  This file contains the flask_op hypercall and associated functions.
+ *
+ *  Author:  George Coker, <gscoker@alpha.ncsc.mil>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2,
+ *  as published by the Free Software Foundation.
+ */
+
+#include <xen/errno.h>
+#include <xsm/xsm.h>
+#include <xen/guest_access.h>
+
+#include <public/flask_op.h>
+
+#include <avc.h>
+#include <avc_ss.h>
+#include <objsec.h>
+#include <conditional.h>
+
+#ifdef FLASK_DEVELOP
+int flask_enforcing = 0;
+integer_param("flask_enforcing", flask_enforcing);
+#endif
+
+#ifdef FLASK_BOOTPARAM
+int flask_enabled = 1;
+integer_param("flask_enabled", flask_enabled);
+#endif
+
+static DEFINE_SPINLOCK(sel_sem);
+
+/* global data for booleans */
+static int bool_num = 0;
+static int *bool_pending_values = NULL;
+
+extern int ss_initialized;
+
+extern struct xsm_operations *original_ops;
+
+static int domain_has_security(struct domain *d, u32 perms)
+{
+    struct domain_security_struct *dsec;
+    
+    dsec = d->ssid;
+    if (!dsec)
+        return -EACCES;
+        
+    return avc_has_perm(dsec->sid, SECINITSID_SECURITY, SECCLASS_SECURITY, 
+                                                                perms, NULL);
+}
+
+static int flask_security_user(char *buf, int size)
+{
+    char *page = NULL;
+    char *con, *user, *ptr;
+    u32 sid, *sids;
+    int length;
+    char *newcon;
+    int i, rc;
+    u32 len, nsids;
+        
+    length = domain_has_security(current->domain, SECURITY__COMPUTE_USER);
+    if (length)
+        return length;
+            
+    length = -ENOMEM;
+    con = xmalloc_array(char, size+1);
+    if (!con)
+        return length;
+    memset(con, 0, size+1);
+    
+    user = xmalloc_array(char, size+1);
+    if (!user)
+        goto out;
+    memset(user, 0, size+1);
+    
+    length = -ENOMEM;
+    page = xmalloc_bytes(PAGE_SIZE);
+    if (!page)
+        goto out2;
+    memset(page, 0, PAGE_SIZE);
+
+    length = -EFAULT;
+    if ( copy_from_user(page, buf, size) )
+        goto out2;
+        
+    length = -EINVAL;
+    if (sscanf(page, "%s %s", con, user) != 2)
+        goto out2;
+
+    length = security_context_to_sid(con, strlen(con)+1, &sid);
+    if (length < 0)
+        goto out2;
+            
+    length = security_get_user_sids(sid, user, &sids, &nsids);
+    if (length < 0)
+        goto out2;
+    
+    memset(page, 0, PAGE_SIZE);
+    length = snprintf(page, PAGE_SIZE, "%u", nsids) + 1;
+    ptr = page + length;
+    for (i = 0; i < nsids; i++) {
+        rc = security_sid_to_context(sids[i], &newcon, &len);
+        if (rc) {
+            length = rc;
+            goto out3;
+        }
+        if ((length + len) >= PAGE_SIZE) {
+            xfree(newcon);
+            length = -ERANGE;
+            goto out3;
+        }
+        memcpy(ptr, newcon, len);
+        xfree(newcon);
+        ptr += len;
+        length += len;
+    }
+    
+    if ( copy_to_user(buf, page, length) )
+        length = -EFAULT;
+        
+out3:
+    xfree(sids);
+out2:
+    if (page)
+        xfree(page);
+    xfree(user);
+out:
+    xfree(con);
+    return length;
+}
+
+static int flask_security_relabel(char *buf, int size)
+{
+    char *scon, *tcon;
+    u32 ssid, tsid, newsid;
+    u16 tclass;
+    int length;
+    char *newcon;
+    u32 len;
+
+    length = domain_has_security(current->domain, SECURITY__COMPUTE_RELABEL);
+    if (length)
+        return length;
+            
+    length = -ENOMEM;
+    scon = xmalloc_array(char, size+1);
+    if (!scon)
+        return length;
+    memset(scon, 0, size+1);
+        
+    tcon = xmalloc_array(char, size+1);
+    if (!tcon)
+        goto out;
+    memset(tcon, 0, size+1);
+        
+    length = -EINVAL;
+    if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3)
+        goto out2;
+            
+    length = security_context_to_sid(scon, strlen(scon)+1, &ssid);
+    if (length < 0)
+        goto out2;
+    length = security_context_to_sid(tcon, strlen(tcon)+1, &tsid);
+    if (length < 0)
+        goto out2;
+            
+    length = security_change_sid(ssid, tsid, tclass, &newsid);
+    if (length < 0)
+        goto out2;
+            
+    length = security_sid_to_context(newsid, &newcon, &len);
+    if (length < 0)
+        goto out2;
+            
+    if (len > PAGE_SIZE) {
+        length = -ERANGE;
+        goto out3;
+    }
+        
+    if ( copy_to_user(buf, newcon, len) )
+        len = -EFAULT;
+
+    length = len;
+        
+out3:
+    xfree(newcon);
+out2:
+    xfree(tcon);
+out:
+    xfree(scon);
+    return length;
+}
+
+static int flask_security_create(char *buf, int size)
+{
+    char *scon, *tcon;
+    u32 ssid, tsid, newsid;
+    u16 tclass;
+    int length;
+    char *newcon;
+    u32 len;
+
+    length = domain_has_security(current->domain, SECURITY__COMPUTE_CREATE);
+    if (length)
+        return length;
+            
+    length = -ENOMEM;
+    scon = xmalloc_array(char, size+1);
+    if (!scon)
+        return length;
+    memset(scon, 0, size+1);
+        
+    tcon = xmalloc_array(char, size+1);
+    if (!tcon)
+        goto out;
+    memset(tcon, 0, size+1);
+        
+    length = -EINVAL;
+    if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3)
+        goto out2;
+
+    length = security_context_to_sid(scon, strlen(scon)+1, &ssid);
+    if (length < 0)
+        goto out2;
+    length = security_context_to_sid(tcon, strlen(tcon)+1, &tsid);
+    if (length < 0)
+        goto out2;
+            
+    length = security_transition_sid(ssid, tsid, tclass, &newsid);
+    if (length < 0)
+        goto out2;
+        
+    length = security_sid_to_context(newsid, &newcon, &len);
+    if (length < 0)    
+        goto out2;
+            
+    if (len > PAGE_SIZE) {
+        printk( "%s:  context size (%u) exceeds payload "
+                "max\n", __FUNCTION__, len);
+        length = -ERANGE;
+        goto out3;
+    }
+        
+    if ( copy_to_user(buf, newcon, len) )
+        len = -EFAULT;
+
+    length = len;
+        
+out3:
+    xfree(newcon);
+out2:
+    xfree(tcon);
+out:
+    xfree(scon);
+    return length;
+}
+
+static int flask_security_access(char *buf, int size)
+{
+    char *page = NULL;
+    char *scon, *tcon;
+    u32 ssid, tsid;
+    u16 tclass;
+    u32 req;
+    struct av_decision avd;
+    int length;
+
+    length = domain_has_security(current->domain, SECURITY__COMPUTE_AV);
+    if (length)
+        return length;
+        
+    length = -ENOMEM;
+    scon = xmalloc_array(char, size+1);
+    if (!scon)
+        return length;
+    memset(scon, 0, size+1);
+        
+    tcon = xmalloc_array(char, size+1);
+    if (!tcon)
+        goto out;
+    memset(tcon, 0, size+1);
+        
+    length = -EINVAL;
+    if (sscanf(buf, "%s %s %hu %x", scon, tcon, &tclass, &req) != 4)
+        goto out2;
+            
+    length = security_context_to_sid(scon, strlen(scon)+1, &ssid);
+    if (length < 0)
+        goto out2;
+    length = security_context_to_sid(tcon, strlen(tcon)+1, &tsid);
+    if (length < 0)
+        goto out2;
+            
+    length = security_compute_av(ssid, tsid, tclass, req, &avd);
+    if (length < 0)
+        goto out2;
+    
+    page = (char *)xmalloc_bytes(PAGE_SIZE);
+    if (!page) {
+        length = -ENOMEM;
+        goto out2;
+    }
+    
+    memset(page, 0, PAGE_SIZE);
+
+    length = snprintf(page, PAGE_SIZE, "%x %x %x %x %u", 
+                avd.allowed, avd.decided,
+                avd.auditallow, avd.auditdeny, 
+                avd.seqno);
+                
+    if ( copy_to_user(buf, page, length) )
+        length = -EFAULT;
+        
+out2:
+    xfree(tcon);
+out:
+    xfree(scon);
+    return length;
+}
+
+static int flask_security_member(char *buf, int size)
+{
+    char *scon, *tcon;
+    u32 ssid, tsid, newsid;
+    u16 tclass;
+    int length;
+    char *newcon;
+    u32 len;
+
+    length = domain_has_security(current->domain, SECURITY__COMPUTE_MEMBER);
+    if (length)
+        return length;
+            
+    length = -ENOMEM;
+    scon = xmalloc_array(char, size+1);
+    if (!scon)
+        return length;
+    memset(scon, 0, size+1);
+    
+    tcon = xmalloc_array(char, size+1);
+    if (!tcon)
+        goto out;
+    memset(tcon, 0, size+1);
+    
+    length = -EINVAL;
+    if (sscanf(buf, "%s, %s, %hu", scon, tcon, &tclass) != 3)
+        goto out2;
+            
+    length = security_context_to_sid(scon, strlen(scon)+1, &ssid);
+    if (length < 0)
+        goto out2;
+    length = security_context_to_sid(tcon, strlen(tcon)+1, &tsid);
+    if (length < 0)
+        goto out2;
+            
+    length = security_member_sid(ssid, tsid, tclass, &newsid);
+    if (length < 0)
+        goto out2;
+
+    length = security_sid_to_context(newsid, &newcon, &len);
+    if (length < 0)
+        goto out2;
+            
+    if (len > PAGE_SIZE) {
+        printk("%s:  context size (%u) exceeds payload "
+                "max\n", __FUNCTION__, len);
+        length = -ERANGE;
+        goto out3;
+    }
+        
+    if ( copy_to_user(buf, newcon, len) )
+        len = -EFAULT;
+        
+    length = len;
+        
+out3:
+    xfree(newcon);
+out2:
+    xfree(tcon);
+out:
+    xfree(scon);
+    return length;
+}
+
+static int flask_security_setenforce(char *buf, int count)
+{
+    char *page = NULL;
+    int length;
+    int new_value;
+    
+    if (count < 0 || count >= PAGE_SIZE)
+        return -ENOMEM;
+        
+    page = (char *)xmalloc_bytes(PAGE_SIZE);
+    if (!page)
+        return -ENOMEM;
+    memset(page, 0, PAGE_SIZE);
+    length = -EFAULT;
+    if (copy_from_user(page, buf, count))
+        goto out;
+
+    length = -EINVAL;
+    if (sscanf(page, "%d", &new_value) != 1)
+        goto out;
+    
+    if (new_value != flask_enforcing) {
+        length = domain_has_security(current->domain, SECURITY__SETENFORCE);
+        if (length)
+            goto out;
+        flask_enforcing = new_value;
+        if (flask_enforcing)
+            avc_ss_reset(0);
+    }
+    length = count;
+    
+out:
+    xfree(page);
+    return length;
+}
+
+static int flask_security_context(char *buf, int count)
+{
+    char *page = NULL;
+    u32 sid;
+    int length;
+
+    length = domain_has_security(current->domain, SECURITY__CHECK_CONTEXT);
+    if (length)
+        goto out;
+    
+    if (count < 0 || count >= PAGE_SIZE)
+        return -ENOMEM;
+    
+    page = (char *)xmalloc_bytes(PAGE_SIZE);
+    if (!page)
+        return -ENOMEM;
+    memset(page, 0, PAGE_SIZE);
+    length = -EFAULT;
+    if (copy_from_user(page, buf, count))
+        goto out;
+        
+    length = security_context_to_sid(page, count, &sid);
+    if (length < 0)
+        goto out;
+
+    memset(page, 0, PAGE_SIZE);
+    length = snprintf(page, PAGE_SIZE, "%u", sid);
+
+    if ( copy_to_user(buf, page, count) )
+        length = -EFAULT;
+    
+out:
+    xfree(page);
+    return length;
+}
+
+static int flask_security_sid(char *buf, int count)
+{
+    char *page = NULL;
+    char *context;
+    u32 sid;
+    u32 len;
+    int length;
+
+    length = domain_has_security(current->domain, SECURITY__CHECK_CONTEXT);
+    if (length)
+        goto out;
+    
+    if (count < 0 || count >= PAGE_SIZE)
+        return -ENOMEM;
+    
+    page = (char *)xmalloc_bytes(PAGE_SIZE);
+    if (!page)
+        return -ENOMEM;
+    memset(page, 0, PAGE_SIZE);
+    length = -EFAULT;
+    if (copy_from_user(page, buf, count))
+        goto out;
+ 
+    if (sscanf(page, "%u", &sid) != 1)
+        goto out;
+       
+    length = security_sid_to_context(sid, &context, &len);
+    if (length < 0)
+        goto out;
+
+    if ( copy_to_user(buf, context, len) )
+        length = -EFAULT;
+    
+    xfree(context);
+
+out:
+    xfree(page);
+    return length;
+}
+
+int flask_disable(void)
+{
+    static int flask_disabled = 0;
+
+    if (ss_initialized) {
+        /* Not permitted after initial policy load. */
+        return -EINVAL;
+    }
+
+    if (flask_disabled) {
+        /* Only do this once. */
+        return -EINVAL;
+    }
+
+    printk("Flask:  Disabled at runtime.\n");
+
+    flask_disabled = 1;
+
+    /* Reset xsm_ops to the original module. */
+    xsm_ops = original_ops;
+
+    return 0;
+}
+
+static int flask_security_disable(char *buf, int count)
+{
+    char *page = NULL;
+    int length;
+    int new_value;
+
+    if (count < 0 || count >= PAGE_SIZE)
+        return -ENOMEM;
+    page = (char *)xmalloc_bytes(PAGE_SIZE);
+    if (!page)
+        return -ENOMEM;
+    memset(page, 0, PAGE_SIZE);
+    length = -EFAULT;
+    if (copy_from_user(page, buf, count))
+        goto out;
+
+    length = -EINVAL;
+    if (sscanf(page, "%d", &new_value) != 1)
+        goto out;
+
+    if (new_value) {
+        length = flask_disable();
+        if (length < 0)
+            goto out;
+    }
+
+    length = count;
+    
+out:
+    xfree(page);
+    return length;
+}
+
+static int flask_security_setavc_threshold(char *buf, int count)
+{
+    char *page = NULL;
+    int ret;
+    int new_value;
+
+    if (count < 0 || count >= PAGE_SIZE) {
+        ret = -ENOMEM;
+        goto out;
+    }
+
+    page = (char*)xmalloc_bytes(PAGE_SIZE);
+    if (!page)
+        return -ENOMEM;
+    memset(page, 0, PAGE_SIZE);
+
+    if (copy_from_user(page, buf, count)) {
+        ret = -EFAULT;
+        goto out_free;
+    }
+
+    if (sscanf(page, "%u", &new_value) != 1) {
+        ret = -EINVAL;
+        goto out_free;
+    }
+
+    if (new_value != avc_cache_threshold) {
+        ret = domain_has_security(current->domain, SECURITY__SETSECPARAM);
+        if (ret)
+            goto out_free;
+        avc_cache_threshold = new_value;
+    }
+    ret = count;
+    
+out_free:
+    xfree(page);
+out:
+    return ret;
+}
+
+static int flask_security_set_bool(char *buf, int count)
+{
+    char *page = NULL;
+    int length = -EFAULT;
+    int i, new_value;
+
+    spin_lock(&sel_sem);
+        
+    length = domain_has_security(current->domain, SECURITY__SETBOOL);
+    if (length)
+        goto out;
+    
+    if (count < 0 || count >= PAGE_SIZE) {
+        length = -ENOMEM;
+        goto out;
+    }
+        
+    page = (char *)xmalloc_bytes(PAGE_SIZE);
+    if (!page) {
+        length = -ENOMEM;
+        goto out;
+    }
+    memset(page, 0, PAGE_SIZE);
+
+    if (copy_from_user(page, buf, count))
+        goto out;
+        
+    length = -EINVAL;
+    if (sscanf(page, "%d %d", &i, &new_value) != 2)
+        goto out;
+        
+    if (new_value) {
+        new_value = 1;
+    }
+    
+    bool_pending_values[i] = new_value;
+    length = count;
+    
+out:
+    spin_unlock(&sel_sem);
+    if (page)
+        xfree(page);
+    return length;
+}
+
+static int flask_security_commit_bools(char *buf, int count)
+{
+    char *page = NULL;
+    int length = -EFAULT;
+    int new_value;
+
+    spin_lock(&sel_sem);
+    
+    length = domain_has_security(current->domain, SECURITY__SETBOOL);
+    if (length)
+        goto out;
+        
+    if (count < 0 || count >= PAGE_SIZE) {
+        length = -ENOMEM;
+        goto out;
+    }
+    
+    page = (char *)xmalloc_bytes(PAGE_SIZE);
+    if (!page) {
+        length = -ENOMEM;
+        goto out;
+    }
+    memset(page, 0, PAGE_SIZE);
+
+    if (copy_from_user(page, buf, count))
+        goto out;
+        
+    length = -EINVAL;
+    if (sscanf(page, "%d", &new_value) != 1)
+        goto out;
+        
+    if (new_value) {
+        security_set_bools(bool_num, bool_pending_values);
+    }
+    
+    length = count;
+    
+out:
+    spin_unlock(&sel_sem);
+    if (page)
+        xfree(page);
+    return length;
+}
+
+static int flask_security_get_bool(char *buf, int count)
+{
+    char *page = NULL;
+    int length;
+    int i, cur_enforcing;
+    
+    spin_lock(&sel_sem);
+    
+    length = -EFAULT;
+
+    if (count < 0 || count > PAGE_SIZE) {
+        length = -EINVAL;
+        goto out;
+    }
+    
+    page = (char *)xmalloc_bytes(PAGE_SIZE);
+    if (!page) {
+        length = -ENOMEM;
+        goto out;
+    }
+    memset(page, 0, PAGE_SIZE);
+        
+    if (copy_from_user(page, buf, count))
+        goto out;
+
+    length = -EINVAL;
+    if (sscanf(page, "%d", &i) != 1)
+        goto out;
+
+    cur_enforcing = security_get_bool_value(i);
+    if (cur_enforcing < 0) {
+        length = cur_enforcing;
+        goto out;
+    }
+    
+    length = snprintf(page, PAGE_SIZE, "%d %d", cur_enforcing,
+                bool_pending_values[i]);
+    if (length < 0)
+        goto out;
+
+    if ( copy_to_user(buf, page, length) )
+        length = -EFAULT;
+
+out:
+    spin_unlock(&sel_sem);
+    if (page)
+        xfree(page);
+    return length;
+}
+
+static int flask_security_make_bools(void)
+{
+    int i, ret = 0;
+    char **names = NULL;
+    int num;
+    int *values = NULL;
+    
+    xfree(bool_pending_values);
+    
+    ret = security_get_bools(&num, &names, &values);
+    if (ret != 0)
+        goto out;
+        
+    bool_num = num;
+    bool_pending_values = values;
+
+out:
+    if (names) {
+        for (i = 0; i < num; i++)
+            xfree(names[i]);
+        xfree(names);
+    }    
+    return ret;
+}
+
+#ifdef FLASK_AVC_STATS
+
+static int flask_security_avc_cachestats(char *buf, int count) {
+
+    char *page = NULL;
+    int len = 0;
+    int length = 0;
+    long long idx = 0;
+    int cpu;
+    struct avc_cache_stats *st;
+    
+    page = (char *)xmalloc_bytes(PAGE_SIZE);
+    if (!page)
+        return -ENOMEM;
+    memset(page, 0, PAGE_SIZE);
+    
+    len = snprintf(page, PAGE_SIZE, "lookups hits misses allocations reclaims "
+           "frees\n");
+    memcpy(buf, page, len);
+    buf += len;
+    length += len;
+    
+    for (cpu = idx; cpu < NR_CPUS; ++cpu) {
+        if (!cpu_possible(cpu))
+            continue;
+        idx = cpu + 1;
+        st = &per_cpu(avc_cache_stats, cpu);
+
+        len = snprintf(page, PAGE_SIZE, "%u %u %u %u %u %u\n", st->lookups,
+               st->hits, st->misses, st->allocations,
+               st->reclaims, st->frees);
+        memcpy(buf, page, len);
+        buf += len;
+        length += len;
+    }
+    
+    xfree(page);    
+    return length;
+}
+
+#endif
+
+static int flask_security_load(char *buf, int count)
+{
+    int ret;
+    int length;
+    void *data = NULL;
+
+    spin_lock(&sel_sem);
+        
+    length = domain_has_security(current->domain, SECURITY__LOAD_POLICY);
+    if (length)
+        goto out;
+            
+    if ((count < 0) || (count > 64 * 1024 * 1024) 
+        || (data = xmalloc_array(char, count)) == NULL) {
+        length = -ENOMEM;
+        goto out;
+    }
+        
+    length = -EFAULT;
+    if (copy_from_user(data, buf, count) != 0)
+        goto out;
+            
+    length = security_load_policy(data, count);
+    if (length)
+        goto out;
+    
+    ret = flask_security_make_bools();
+    if (ret)
+        length = ret;
+    else
+        length = count;
+                        
+out:
+    spin_unlock(&sel_sem);
+    xfree(data);
+    return length;
+}
+
+long do_flask_op(int cmd, XEN_GUEST_HANDLE(xsm_op_t) u_flask_op)
+{
+
+    flask_op_t curop, *op = &curop;
+    int rc = 0;
+    int length = 0;
+    char *page = NULL;
+    
+    if ( copy_from_guest(op, u_flask_op, 1) )
+        return -EFAULT;
+        
+    switch ( cmd )
+    {
+
+    case FLASK_LOAD:
+    {
+        length = flask_security_load(op->buf, op->size);
+    }
+    break;
+    
+    case FLASK_GETENFORCE:
+    {
+        page = (char *)xmalloc_bytes(PAGE_SIZE);
+        if (!page)
+            return -ENOMEM;
+        memset(page, 0, PAGE_SIZE);
+        
+        length = snprintf(page, PAGE_SIZE, "%d", flask_enforcing);
+        
+        if( copy_to_user(op->buf, page, length) ) {
+            rc = -EFAULT;
+            goto out;
+        }
+    }
+    break;    
+    
+    case FLASK_SETENFORCE:
+    {
+        length = flask_security_setenforce(op->buf, op->size);
+    }
+    break;    
+
+    case FLASK_CONTEXT_TO_SID:
+    {
+        length = flask_security_context(op->buf, op->size);
+    }
+    break;    
+
+    case FLASK_SID_TO_CONTEXT:
+    {
+        length = flask_security_sid(op->buf, op->size);
+    }
+    break; 
+         
+    case FLASK_ACCESS:
+    {
+        length = flask_security_access(op->buf, op->size);
+    }
+    break;    
+    
+    case FLASK_CREATE:
+    {
+        length = flask_security_create(op->buf, op->size);
+    }
+    break;    
+    
+    case FLASK_RELABEL:
+    {
+        length = flask_security_relabel(op->buf, op->size);
+    }
+    break;
+    
+    case FLASK_USER:
+    {
+        length = flask_security_user(op->buf, op->size);
+    }
+    break;    
+    
+    case FLASK_POLICYVERS:
+    {
+        page = (char *)xmalloc_bytes(PAGE_SIZE);
+        if (!page)
+            return -ENOMEM;
+        memset(page, 0, PAGE_SIZE);
+
+        length = snprintf(page, PAGE_SIZE, "%d", POLICYDB_VERSION_MAX);
+
+        if ( copy_to_user(op->buf, page, length) ) {
+            rc = -EFAULT;
+            goto out;
+        }
+    }
+    break;    
+    
+    case FLASK_GETBOOL:
+    {
+        length = flask_security_get_bool(op->buf, op->size);
+    }
+    break;
+    
+    case FLASK_SETBOOL:
+    {
+        length = flask_security_set_bool(op->buf, op->size);
+    }
+    break;
+    
+    case FLASK_COMMITBOOLS:
+    {
+        length = flask_security_commit_bools(op->buf, op->size);
+    }
+    break;
+    
+    case FLASK_MLS:
+    {
+        page = (char *)xmalloc_bytes(PAGE_SIZE);
+        if (!page)
+            return -ENOMEM;
+        memset(page, 0, PAGE_SIZE);
+    
+        length = snprintf(page, PAGE_SIZE, "%d", flask_mls_enabled);
+
+        if ( copy_to_user(op->buf, page, length) ) {
+            rc = -EFAULT;
+            goto out;
+        }
+    }
+    break;    
+    
+    case FLASK_DISABLE:
+    {
+        length = flask_security_disable(op->buf, op->size);
+    }
+    break;    
+
+    case FLASK_GETAVC_THRESHOLD:
+    {
+        page = (char *)xmalloc_bytes(PAGE_SIZE);
+        if (!page)
+            return -ENOMEM;
+        memset(page, 0, PAGE_SIZE);
+    
+        length = snprintf(page, PAGE_SIZE, "%d", avc_cache_threshold);
+
+        if ( copy_to_user(op->buf, page, length) ) {
+            rc = -EFAULT;
+            goto out;
+        }
+    }
+    break;
+        
+    case FLASK_SETAVC_THRESHOLD:
+    {
+        length = flask_security_setavc_threshold(op->buf, op->size);
+    }
+    break;
+    
+    case FLASK_AVC_HASHSTATS:
+    {
+        page = (char *)xmalloc_bytes(PAGE_SIZE);
+        if (!page)
+            return -ENOMEM;
+        memset(page, 0, PAGE_SIZE);
+            
+        length = avc_get_hash_stats(page);
+
+        if ( copy_to_user(op->buf, page, length) ) {
+            rc = -EFAULT;
+            goto out;
+        }
+    }
+    break;
+#ifdef FLASK_AVC_STATS    
+    case FLASK_AVC_CACHESTATS:
+    {
+        length = flask_security_avc_cachestats(op->buf, op->size);
+    }
+    break;
+#endif    
+    case FLASK_MEMBER:
+    {
+        length = flask_security_member(op->buf, op->size);
+    }
+    break;    
+
+    default:
+    {
+        length = -ENOSYS;
+        break;
+    }
+    
+    }
+
+    if (length < 0) {
+        rc = length;
+        goto out;
+    }
+    op->size = length;
+    if ( copy_to_guest(u_flask_op, op, 1) )
+        rc = -EFAULT;
+
+out:
+    if (page)
+        xfree(page);
+    return rc;
+}
+
diff -r 62b752969edf -r 2b79cd115561 xen/xsm/flask/hooks.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/hooks.c	Mon May 07 14:51:17 2007 -0400
@@ -0,0 +1,1155 @@
+ /*
+ *  This file contains the Flask hook function implementations for Xen.
+ *
+ *  Author:  George Coker, <gscoker@alpha.ncsc.mil>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License version 2,
+ *      as published by the Free Software Foundation.
+ */
+
+#include <xen/init.h>
+#include <xen/lib.h>
+#include <xen/sched.h>
+#include <xen/xmalloc.h>
+#include <xsm/xsm.h>
+#include <xen/spinlock.h>
+#include <xen/cpumask.h>
+#include <xen/errno.h>
+#include <xen/guest_access.h>
+#include <public/xen.h>
+#include <public/physdev.h>
+#include <public/platform.h>
+
+#include <public/flask_op.h>
+
+#include <avc.h>
+#include <avc_ss.h>
+#include <objsec.h>
+#include <conditional.h>
+
+struct xsm_operations *original_ops = NULL;
+
+static int domain_has_perm(struct domain *dom1, struct domain *dom2, 
+                                                        u16 class, u32 perms)
+{
+    struct domain_security_struct *dsec1, *dsec2;
+
+    dsec1 = dom1->ssid;
+    dsec2 = dom2->ssid;
+
+    return avc_has_perm(dsec1->sid, dsec2->sid, class, perms, NULL);
+}
+
+static int domain_has_evtchn(struct domain *d, struct evtchn *chn, u32 perms)
+{
+    struct domain_security_struct *dsec;
+    struct evtchn_security_struct *esec;
+    
+    dsec = d->ssid;
+    esec = chn->ssid;
+    
+    return avc_has_perm(dsec->sid, esec->sid, SECCLASS_EVENT, perms, NULL);
+}
+
+static int domain_has_xen(struct domain *d, u32 perms)
+{
+    struct domain_security_struct *dsec;
+    dsec = d->ssid;
+    
+    return avc_has_perm(dsec->sid, SECINITSID_XEN, SECCLASS_XEN, perms, NULL);
+}
+
+static int flask_domain_alloc_security(struct domain *d)
+{
+    struct domain_security_struct *dsec;
+    
+    dsec = xmalloc(struct domain_security_struct);
+    
+    if (!dsec)
+        return -ENOMEM;
+        
+    memset(dsec, 0, sizeof(struct domain_security_struct));
+    
+    dsec->d = d;
+    
+    if (d->domain_id == IDLE_DOMAIN_ID) {
+        dsec->sid = SECINITSID_XEN;
+        dsec->create_sid = SECINITSID_DOM0;
+    } else {
+        dsec->sid = SECINITSID_UNLABELED;
+        dsec->create_sid = SECSID_NULL;
+    }
+    
+    d->ssid = dsec;
+    
+    return 0;
+}
+
+static void flask_domain_free_security(struct domain *d)
+{
+    struct domain_security_struct *dsec = d->ssid;
+    
+    if (!dsec)
+        return;
+        
+    d->ssid = NULL;
+    xfree(dsec);
+}
+
+static int flask_evtchn_unbound(struct domain *d1, struct evtchn *chn, 
+                                                                    domid_t id2)
+{
+    u32 newsid;
+    int rc;
+    domid_t id;
+    struct domain *d2;
+    struct domain_security_struct *dsec, *dsec1, *dsec2;
+    struct evtchn_security_struct *esec;
+    
+    dsec = current->domain->ssid;
+    dsec1 = d1->ssid;
+    esec = chn->ssid;
+    
+    if (id2 == DOMID_SELF)
+        id = current->domain->domain_id;
+    else
+        id = id2;
+
+    d2 = get_domain_by_id(id);
+    if (d2 == NULL)
+        return -EPERM;
+    
+    dsec2 = d2->ssid;
+    rc = security_transition_sid(dsec1->sid, dsec2->sid, SECCLASS_EVENT, 
+                                                                    &newsid);
+    if (rc)
+        goto out;
+
+    rc = avc_has_perm(dsec->sid, newsid, SECCLASS_EVENT,
+                                            EVENT__CREATE|EVENT__ALLOC, NULL);
+    if (rc)
+        goto out;
+        
+    rc = avc_has_perm(newsid, dsec2->sid, SECCLASS_EVENT, EVENT__BIND, NULL);
+    if (rc)
+        goto out;
+    else
+        esec->sid = newsid;
+            
+out:
+    put_domain(d2);
+    return rc;
+}
+
+static int flask_evtchn_interdomain(struct domain *d1, struct evtchn *chn1, 
+                                        struct domain *d2, struct evtchn *chn2)
+{
+    u32 newsid1;
+    u32 newsid2;
+    int rc;
+    struct domain_security_struct *dsec1, *dsec2;
+    struct evtchn_security_struct *esec1, *esec2;
+
+    dsec1 = d1->ssid;
+    dsec2 = d2->ssid;
+    
+    esec1 = chn1->ssid;
+    esec2 = chn2->ssid;
+
+    rc = security_transition_sid(dsec1->sid, dsec2->sid, 
+                                        SECCLASS_EVENT, &newsid1);
+    if (rc) {
+        printk("%s: security_transition_sid failed, rc=%d (domain=%d)\n",
+                                            __FUNCTION__, -rc, d2->domain_id);
+        return rc;
+    }
+
+    rc = avc_has_perm(dsec1->sid, newsid1, SECCLASS_EVENT, EVENT__CREATE, NULL);
+    if (rc)
+        return rc;
+
+    rc = security_transition_sid(dsec2->sid, dsec1->sid, 
+                                        SECCLASS_EVENT, &newsid2);
+    if (rc) {
+        printk("%s: security_transition_sid failed, rc=%d (domain=%d)\n",
+                                            __FUNCTION__, -rc, d1->domain_id);
+        return rc;
+    }
+
+    rc = avc_has_perm(dsec2->sid, newsid2, SECCLASS_EVENT, EVENT__CREATE, NULL);
+    if (rc)
+        return rc;
+        
+    rc = avc_has_perm(newsid1, dsec2->sid, SECCLASS_EVENT, EVENT__BIND, NULL);
+    if (rc)
+        return rc;
+    
+    rc = avc_has_perm(newsid2, dsec1->sid, SECCLASS_EVENT, EVENT__BIND, NULL);
+    if (rc)
+        return rc;    
+        
+    esec1->sid = newsid1;
+    esec2->sid = newsid2;
+    
+    return rc;
+}
+
+static void flask_evtchn_close_post(struct evtchn *chn)
+{
+    struct evtchn_security_struct *esec;
+    esec = chn->ssid;
+    
+    esec->sid = SECINITSID_UNLABELED;
+}
+
+static int flask_evtchn_send(struct domain *d, struct evtchn *chn)
+{
+    return domain_has_evtchn(d, chn, EVENT__SEND);
+}
+
+static int flask_evtchn_status(struct domain *d, struct evtchn *chn)
+{
+    return domain_has_evtchn(d, chn, EVENT__STATUS);
+}
+
+static int flask_evtchn_reset(struct domain *d1, struct domain *d2)
+{
+    return domain_has_perm(d1, d2, SECCLASS_EVENT, EVENT__RESET);
+}
+
+static int flask_alloc_security_evtchn(struct evtchn *chn)
+{
+    int i;
+    struct evtchn_security_struct *esec;
+
+    for ( i = 0; i < EVTCHNS_PER_BUCKET; i++ ) {
+        esec = xmalloc(struct evtchn_security_struct);
+    
+        if (!esec)
+            return -ENOMEM;
+        
+        memset(esec, 0, sizeof(struct evtchn_security_struct));
+    
+        esec->chn = &chn[i];
+        esec->sid = SECINITSID_UNLABELED;
+
+        (&chn[i])->ssid = esec;
+    }
+    
+    return 0;    
+}
+
+static void flask_free_security_evtchn(struct evtchn *chn)
+{
+    int i;
+    struct evtchn_security_struct *esec;
+
+    if (!chn)
+        return;
+            
+    for ( i = 0; i < EVTCHNS_PER_BUCKET; i++ ) {
+        esec = (&chn[i])->ssid;
+    
+        if (!esec)
+            continue;
+        
+        (&chn[i])->ssid = NULL;
+        xfree(esec);
+    }
+
+}
+
+static int flask_grant_mapref(struct domain *d1, struct domain *d2, 
+                                                                uint32_t flags)
+{
+    u32 perms = GRANT__MAP_READ;
+    
+    if (flags & GTF_writing)
+        perms |= GRANT__MAP_WRITE;
+        
+    return domain_has_perm(d1, d2, SECCLASS_GRANT, perms);
+}
+
+static int flask_grant_unmapref(struct domain *d1, struct domain *d2)
+{
+    return domain_has_perm(d1, d2, SECCLASS_GRANT, GRANT__UNMAP);
+}
+
+static int flask_grant_setup(struct domain *d1, struct domain *d2)
+{
+    return domain_has_perm(d1, d2, SECCLASS_GRANT, GRANT__SETUP);
+}
+
+static int flask_grant_transfer(struct domain *d1, struct domain *d2)
+{
+    return domain_has_perm(d1, d2, SECCLASS_GRANT, GRANT__TRANSFER);
+}
+
+static int flask_grant_copy(struct domain *d1, struct domain *d2)
+{
+    return domain_has_perm(d1, d2, SECCLASS_GRANT, GRANT__COPY);
+}
+
+static int flask_grant_query_size(struct domain *d1, struct domain *d2)
+{
+    return domain_has_perm(d1, d2, SECCLASS_GRANT, GRANT__QUERY);
+}
+
+static int get_page_sid(unsigned long mfn, u32 *sid)
+{
+    int rc = 0;
+    struct domain *d;
+    struct page_info *page;
+    struct domain_security_struct *dsec;
+   
+    if (mfn_valid(mfn)) {
+        /*mfn is valid if this is a page that Xen is tracking!*/
+        page = mfn_to_page(mfn);        
+        d = page_get_owner(page);
+
+        if (d == NULL) {
+            rc = security_iomem_sid(mfn, sid);
+            goto out;
+        }
+        
+        switch ( d->domain_id )
+        {
+            case DOMID_IO:
+                /*A tracked IO page?*/
+                *sid = SECINITSID_DOMIO;
+                break;
+        
+            case DOMID_XEN:
+                /*A page from Xen's private heap?*/
+                *sid = SECINITSID_DOMXEN;
+                break;
+        
+            default:
+                /*Pages are implicitly labeled by domain ownership!*/
+                dsec = d->ssid;
+                *sid = dsec->sid;
+                break;
+        }
+
+    } else {
+        /*Possibly an untracked IO page?*/
+        rc = security_iomem_sid(mfn, sid);
+    }
+
+out:
+    return rc;    
+}
+
+static int flask_translate_gpfn_list(struct domain *d, unsigned long mfn)
+{
+    int rc = 0;
+    u32 sid;
+    struct domain_security_struct *dsec;
+    dsec = d->ssid;
+
+    rc = get_page_sid(mfn, &sid);
+    if (rc)
+        return rc;
+        
+    return avc_has_perm(dsec->sid, sid, SECCLASS_MMU, MMU__TRANSLATEGP, NULL);
+}
+
+static int flask_memory_adjust_reservation(struct domain *d1, struct domain *d2)
+{
+    return domain_has_perm(d1, d2, SECCLASS_MMU, MMU__ADJUST);
+}
+
+static int flask_memory_stat_reservation(struct domain *d1, struct domain *d2)
+{
+    return domain_has_perm(d1, d2, SECCLASS_MMU, MMU__STAT);
+}
+
+static int flask_memory_pin_page(struct domain *d, unsigned long mfn)
+{
+    int rc = 0;
+    u32 sid;
+    struct domain_security_struct *dsec;
+    dsec = d->ssid;
+
+    rc = get_page_sid(mfn, &sid);
+    if (rc)
+        return rc;
+    
+    return avc_has_perm(dsec->sid, sid, SECCLASS_MMU, MMU__PINPAGE, NULL);
+}
+
+static int flask_update_va_mapping(struct domain *d, intpte_t pte)
+{
+    int rc = 0;
+    u32 psid;
+    u32 map_perms = MMU__MAP_READ;
+    unsigned long mfn;
+    struct domain_security_struct *dsec;
+
+    dsec = d->ssid;
+    
+    mfn = ((unsigned long)(((pte) & (PADDR_MASK&PAGE_MASK)) >> PAGE_SHIFT));        
+    rc = get_page_sid(mfn, &psid);
+    if (rc)
+        return rc;
+
+    if ( get_pte_flags(pte) & _PAGE_RW )
+        map_perms |= MMU__MAP_WRITE;
+
+    return avc_has_perm(dsec->sid, psid, SECCLASS_MMU, map_perms, NULL);
+}
+
+static int flask_console_io(struct domain *d, int cmd)
+{
+    u32 perm;
+    
+    switch (cmd) {
+        case CONSOLEIO_read:
+            perm = XEN__READCONSOLE;
+            break;
+        case CONSOLEIO_write:
+            perm = XEN__WRITECONSOLE;
+            break;
+        default:
+            return -EPERM;
+    }
+        
+    return domain_has_xen(d, perm);
+}
+
+static int flask_profile(struct domain *d, int op)
+{
+    u32 perm;
+    
+    switch (op) {
+        case XENOPROF_init:
+        case XENOPROF_enable_virq:
+        case XENOPROF_disable_virq:
+        case XENOPROF_get_buffer:
+            perm = XEN__NONPRIVPROFILE;
+            break;
+        case XENOPROF_reset_active_list:
+        case XENOPROF_reset_passive_list:
+        case XENOPROF_set_active:
+        case XENOPROF_set_passive:
+        case XENOPROF_reserve_counters:
+        case XENOPROF_counter:
+        case XENOPROF_setup_events:
+        case XENOPROF_start:
+        case XENOPROF_stop:
+        case XENOPROF_release_counters:
+        case XENOPROF_shutdown:
+            perm = XEN__PRIVPROFILE;
+            break;
+        default:
+            return -EPERM;
+    }
+    
+    return domain_has_xen(d, perm);
+}
+
+static int flask_kexec(void)
+{
+    return domain_has_xen(current->domain, XEN__KEXEC);
+}
+
+static int flask_schedop_shutdown(struct domain *d1, struct domain *d2)
+{
+    return domain_has_perm(d1, d2, SECCLASS_DOMAIN, DOMAIN__SHUTDOWN);
+}
+
+static void flask_security_domaininfo(struct domain *d, 
+                                        struct xen_domctl_getdomaininfo *info)
+{
+    struct domain_security_struct *dsec;
+    
+    dsec = d->ssid;
+    info->ssidref = dsec->sid;
+}
+
+static int flask_setvcpucontext(struct domain *d)
+{
+    return domain_has_perm(current->domain, d, SECCLASS_DOMAIN, 
+                                                        DOMAIN__SETVCPUCONTEXT);
+}
+
+static int flask_pausedomain(struct domain *d)
+{
+    return domain_has_perm(current->domain, d, SECCLASS_DOMAIN, DOMAIN__PAUSE);
+}
+
+static int flask_unpausedomain(struct domain *d)
+{
+    return domain_has_perm(current->domain, d, SECCLASS_DOMAIN, DOMAIN__UNPAUSE);
+}
+
+static int flask_resumedomain(struct domain *d)
+{
+    return domain_has_perm(current->domain, d, SECCLASS_DOMAIN, DOMAIN__RESUME);
+}
+
+static int flask_domain_create(struct domain *d, u32 ssidref)
+{
+    int rc;
+    struct domain_security_struct *dsec1;
+    struct domain_security_struct *dsec2;
+    
+    dsec1 = current->domain->ssid;
+
+    if (dsec1->create_sid == SECSID_NULL)
+        dsec1->create_sid = ssidref;
+        
+    rc = avc_has_perm(dsec1->sid, dsec1->create_sid, SECCLASS_DOMAIN, 
+                                                        DOMAIN__CREATE, NULL);
+    if (rc) {
+        dsec1->create_sid = SECSID_NULL;
+        return rc;
+    }
+    
+    dsec2 = d->ssid;
+    dsec2->sid = dsec1->create_sid;
+
+    dsec1->create_sid = SECSID_NULL;
+    dsec2->create_sid = SECSID_NULL;
+    
+    return rc;
+}
+
+static int flask_max_vcpus(struct domain *d)
+{
+    return domain_has_perm(current->domain, d, SECCLASS_DOMAIN, 
+                                                            DOMAIN__MAX_VCPUS);
+}
+
+static int flask_destroydomain(struct domain *d)
+{
+    return domain_has_perm(current->domain, d, SECCLASS_DOMAIN, 
+                                                            DOMAIN__DESTROY);
+}
+
+static int flask_vcpuaffinity(int cmd, struct domain *d)
+{
+
+    u32 perm;
+    
+    switch (cmd)
+    {
+        case XEN_DOMCTL_setvcpuaffinity:
+            perm = DOMAIN__SETVCPUAFFINITY;
+            break;
+        case XEN_DOMCTL_getvcpuaffinity:
+            perm = DOMAIN__GETVCPUAFFINITY;
+            break;
+        default:
+            return -EPERM;
+    }
+               
+    return domain_has_perm(current->domain, d, SECCLASS_DOMAIN, perm );
+}
+
+static int flask_scheduler(struct domain *d)
+{
+    int rc = 0;
+    
+    rc = domain_has_xen(current->domain, XEN__SCHEDULER);
+    if (rc)
+        return rc;
+        
+    return domain_has_perm(current->domain, d, SECCLASS_DOMAIN, 
+                                                            DOMAIN__SCHEDULER);
+}
+
+static int flask_getdomaininfo(struct domain *d)
+{
+    return domain_has_perm(current->domain, d, SECCLASS_DOMAIN,
+                                                        DOMAIN__GETDOMAININFO);
+}
+
+static int flask_getvcpucontext(struct domain *d)
+{
+    return domain_has_perm(current->domain, d, SECCLASS_DOMAIN, 
+                                                        DOMAIN__GETVCPUCONTEXT);
+}
+
+static int flask_getvcpuinfo(struct domain *d)
+{
+    return domain_has_perm(current->domain, d, SECCLASS_DOMAIN,
+                                                        DOMAIN__GETVCPUINFO);
+}
+
+static int flask_domain_settime(struct domain *d)
+{
+    return domain_has_perm(current->domain, d, SECCLASS_DOMAIN, DOMAIN__SETTIME);
+}
+
+static int flask_tbufcontrol(void)
+{
+    return domain_has_xen(current->domain, SECCLASS_XEN);
+}
+
+static int flask_readconsole(uint32_t clear)
+{
+    u32 perms = XEN__READCONSOLE;
+    
+    if (clear)
+        perms |= XEN__CLEARCONSOLE;
+            
+    return domain_has_xen(current->domain, perms);
+}
+
+static int flask_sched_id(void)
+{
+    return domain_has_xen(current->domain, XEN__SCHEDULER);
+}
+
+static int flask_setdomainmaxmem(struct domain *d)
+{
+    return domain_has_perm(current->domain, d, SECCLASS_DOMAIN,
+                                                    DOMAIN__SETDOMAINMAXMEM);
+}
+
+static int flask_setdomainhandle(struct domain *d)
+{
+    return domain_has_perm(current->domain, d, SECCLASS_DOMAIN,
+                                                    DOMAIN__SETDOMAINHANDLE);
+}
+
+static int flask_setdebugging(struct domain *d)
+{
+    return domain_has_perm(current->domain, d, SECCLASS_DOMAIN,
+                                                        DOMAIN__SETDEBUGGING);
+}
+
+static inline u32 resource_to_perm(uint8_t access)
+{
+    if (access)
+        return RESOURCE__ADD;
+    else
+        return RESOURCE__REMOVE;
+}
+
+static int flask_irq_permission(struct domain *d, uint8_t pirq, uint8_t access)
+{
+    u32 perm;
+    u32 rsid;
+    int rc = -EPERM;
+    
+    struct domain_security_struct *ssec, *tsec;
+
+    rc = domain_has_perm(current->domain, d, SECCLASS_RESOURCE,
+                                                    resource_to_perm(access));
+    
+    if (rc)
+        return rc;
+        
+    if (access)
+        perm = RESOURCE__ADD_IRQ;
+    else
+        perm = RESOURCE__REMOVE_IRQ;
+
+    ssec = current->domain->ssid;
+    tsec = d->ssid;
+    
+    rc = security_pirq_sid(pirq, &rsid);
+    if (rc)
+        return rc;
+    
+    rc = avc_has_perm(ssec->sid, rsid, SECCLASS_RESOURCE, perm, NULL);
+    
+    if (rc)
+        return rc;
+        
+    return avc_has_perm(tsec->sid, rsid, SECCLASS_RESOURCE, 
+                                                        RESOURCE__USE, NULL);
+}
+
+static int flask_iomem_permission(struct domain *d, unsigned long mfn, 
+                                                                uint8_t access)
+{
+    u32 perm;
+    u32 rsid;
+    int rc = -EPERM;
+
+    struct domain_security_struct *ssec, *tsec;
+    
+    rc = domain_has_perm(current->domain, d, SECCLASS_RESOURCE,
+                                                    resource_to_perm(access));
+    
+    if (rc)
+        return rc;
+        
+    if (access)
+        perm = RESOURCE__ADD_IOMEM;
+    else
+        perm = RESOURCE__REMOVE_IOMEM;
+
+    ssec = current->domain->ssid;
+    tsec = d->ssid;
+    
+    rc = security_iomem_sid(mfn, &rsid);
+    if (rc)
+        return rc;
+
+    rc = avc_has_perm(ssec->sid, rsid, SECCLASS_RESOURCE, perm, NULL);
+    
+    if (rc)
+        return rc;
+        
+    return avc_has_perm(tsec->sid, rsid, SECCLASS_RESOURCE, 
+                                                        RESOURCE__USE, NULL);
+}
+
+static int flask_perfcontrol(void)
+{
+    return domain_has_xen(current->domain, XEN__PERFCONTROL);
+}
+
+void flask_complete_init(struct domain *d)
+{
+    struct domain_security_struct *dsec;
+    
+    /* Set the security state for the Dom0 domain. */
+    dsec = d->ssid;
+    dsec->sid = SECINITSID_DOM0;
+    dsec->create_sid = SECINITSID_UNLABELED;
+    
+    printk("Flask:  Completed initialization.\n");
+}
+
+#ifdef CONFIG_X86
+static int flask_shadow_control(struct domain *d, uint32_t op)
+{
+    u32 perm;
+    
+    switch (op) {
+        case XEN_DOMCTL_SHADOW_OP_OFF:
+            perm = SHADOW__DISABLE;
+            break;
+        case XEN_DOMCTL_SHADOW_OP_ENABLE:
+        case XEN_DOMCTL_SHADOW_OP_ENABLE_TEST:
+        case XEN_DOMCTL_SHADOW_OP_ENABLE_TRANSLATE:
+        case XEN_DOMCTL_SHADOW_OP_GET_ALLOCATION:
+        case XEN_DOMCTL_SHADOW_OP_SET_ALLOCATION:
+            perm = SHADOW__ENABLE;
+            break;
+        case XEN_DOMCTL_SHADOW_OP_ENABLE_LOGDIRTY:
+        case XEN_DOMCTL_SHADOW_OP_PEEK:
+        case XEN_DOMCTL_SHADOW_OP_CLEAN:
+            perm = SHADOW__LOGDIRTY;
+        default:
+            return -EPERM;
+    }
+    
+    return domain_has_perm(current->domain, d, SECCLASS_SHADOW, perm);
+}
+
+static int flask_ioport_permission(struct domain *d, uint32_t ioport, 
+                                                                uint8_t access)
+{
+    u32 perm;
+    u32 rsid;
+    int rc = -EPERM;
+    
+    struct domain_security_struct *ssec, *tsec;
+
+    rc = domain_has_perm(current->domain, d, SECCLASS_RESOURCE,
+                                                    resource_to_perm(access));
+    
+    if (rc)
+        return rc;
+        
+    if (access)
+        perm = RESOURCE__ADD_IOPORT;
+    else
+        perm = RESOURCE__REMOVE_IOPORT;
+
+    ssec = current->domain->ssid;
+    tsec = d->ssid;
+    
+    rc = security_ioport_sid(ioport, &rsid);
+    if (rc)
+        return rc;
+
+    rc = avc_has_perm(ssec->sid, rsid, SECCLASS_RESOURCE, perm, NULL);
+    if (rc)
+        return rc;
+        
+    return avc_has_perm(tsec->sid, rsid, SECCLASS_RESOURCE, 
+                                                        RESOURCE__USE, NULL);    
+}
+
+static int flask_getpageframeinfo(unsigned long mfn)
+{
+    struct page_info *page;
+    struct domain *d;
+    struct domain_security_struct *ssec, *tsec;
+
+    ssec = current->domain->ssid;
+
+    if (mfn_valid(mfn))
+        page = mfn_to_page(mfn);
+    else
+        return -EPERM;
+        
+    d = page_get_owner(page);
+    
+    tsec = d->ssid;
+    
+    return avc_has_perm(ssec->sid, tsec->sid, SECCLASS_MMU, 
+                                                        MMU__PAGEINFO, NULL);    
+}
+
+static int flask_getmemlist(struct domain *d)
+{
+    return domain_has_perm(current->domain, d, SECCLASS_MMU, MMU__PAGELIST);
+}
+
+static int flask_hypercall_init(struct domain *d)
+{
+    return domain_has_perm(current->domain, d, SECCLASS_DOMAIN,
+                                                            DOMAIN__HYPERCALL);
+}
+
+static int flask_hvmcontext(struct domain *d, uint32_t cmd)
+{
+    u32 perm;
+
+    switch (cmd) {
+        case XEN_DOMCTL_sethvmcontext:
+            perm = HVM__SETHVMC;
+        break;
+        case XEN_DOMCTL_gethvmcontext:
+            perm = HVM__GETHVMC;
+        break;
+        default:
+            return -EPERM;
+    }
+
+    return domain_has_perm(current->domain, d, SECCLASS_HVM, perm);
+}
+
+static int flask_address_size(struct domain *d, uint32_t cmd)
+{
+    u32 perm;
+
+    switch (cmd) {
+        case XEN_DOMCTL_set_address_size:
+            perm = DOMAIN__SETADDRSIZE;
+        break;
+        case XEN_DOMCTL_get_address_size:
+            perm = DOMAIN__GETADDRSIZE;
+        break;
+        default:
+            return -EPERM;
+    }
+
+    return domain_has_perm(current->domain, d, SECCLASS_DOMAIN, perm);
+}
+
+static int flask_hvm_param(struct domain *d, unsigned long op)
+{
+    u32 perm;
+    
+    switch (op) {
+        case HVMOP_set_param:
+            perm = HVM__SETPARAM;
+            break;
+        case HVMOP_get_param:
+            perm = HVM__GETPARAM;
+            break;
+        default:
+            return -EPERM;
+    }
+
+    return domain_has_perm(current->domain, d, SECCLASS_HVM, perm);
+}
+
+static int flask_hvm_set_pci_intx_level(struct domain *d)
+{
+    return domain_has_perm(current->domain, d, SECCLASS_HVM, HVM__PCILEVEL);
+}
+
+static int flask_hvm_set_isa_irq_level(struct domain *d)
+{
+    return domain_has_perm(current->domain, d, SECCLASS_HVM, HVM__IRQLEVEL);
+}
+
+static int flask_hvm_set_pci_link_route(struct domain *d)
+{
+    return domain_has_perm(current->domain, d, SECCLASS_HVM, HVM__PCIROUTE);
+}
+
+static int flask_pirq_unmask(struct domain *d, int pirq)
+{
+    u32 psid;
+    struct domain_security_struct *dsec;
+    dsec = d->ssid;
+    
+    if (security_pirq_sid(pirq, &psid))
+        return -EPERM;
+        
+    return avc_has_perm(dsec->sid, psid, SECCLASS_EVENT, EVENT__UNMASK, NULL);
+}
+
+static int flask_pirq_status(struct domain *d, int pirq)
+{
+    u32 psid;
+    struct domain_security_struct *dsec;
+    dsec = d->ssid;
+    
+    if (security_pirq_sid(pirq, &psid))
+        return -EPERM;
+        
+    return avc_has_perm(dsec->sid, psid, SECCLASS_EVENT, EVENT__STATUS, NULL);
+}
+
+static int flask_apic(struct domain *d, int cmd)
+{
+    u32 perm;
+    
+    switch (cmd) {
+        case PHYSDEVOP_APIC_READ:
+            perm = XEN__READAPIC;
+            break;
+        case PHYSDEVOP_APIC_WRITE:
+            perm = XEN__WRITEAPIC;
+            break;
+        default:
+            return -EPERM;
+    }
+        
+    return domain_has_xen(d, perm);
+}
+
+static int flask_assign_vector(struct domain *d, uint32_t pirq)
+{
+    u32 psid;
+    struct domain_security_struct *dsec;
+    dsec = d->ssid;
+    
+    if (security_pirq_sid(pirq, &psid))
+        return -EPERM;
+    
+    return avc_has_perm(dsec->sid, psid, SECCLASS_EVENT, EVENT__VECTOR, NULL);
+}
+
+static int flask_xen_settime(void)
+{
+    return domain_has_xen(current->domain, XEN__SETTIME);
+}
+
+static int flask_memtype(uint32_t access)
+{
+    u32 perm;
+    
+    switch (access) {
+        case XENPF_add_memtype:
+            perm = XEN__MTRR_ADD;
+        break;
+        case XENPF_del_memtype:
+            perm = XEN__MTRR_DEL;
+        break;
+        case XENPF_read_memtype:
+            perm = XEN__MTRR_READ;
+        break;
+        default:
+            return -EPERM;
+    }
+    
+    return domain_has_xen(current->domain, perm);
+}
+
+static int flask_microcode(void)
+{
+    return domain_has_xen(current->domain, XEN__MICROCODE);
+}
+
+static int flask_physinfo(void)
+{
+    return domain_has_xen(current->domain, XEN__PHYSINFO);
+}
+
+static int flask_platform_quirk(uint32_t quirk)
+{
+    struct domain_security_struct *dsec;
+    dsec = current->domain->ssid;
+    
+    return avc_has_perm(dsec->sid, SECINITSID_XEN, SECCLASS_XEN, 
+                                                            XEN__QUIRK, NULL);
+}
+
+static int flask_machine_memory_map(void)
+{
+    struct domain_security_struct *dsec;
+    dsec = current->domain->ssid;
+    
+    return avc_has_perm(dsec->sid, SECINITSID_XEN, SECCLASS_MMU, 
+                                                          MMU__MEMORYMAP, NULL);
+}
+
+static int flask_domain_memory_map(struct domain *d1, struct domain *d2)
+{
+    return domain_has_perm(d1, d2, SECCLASS_MMU, MMU__MEMORYMAP);
+}
+
+static int flask_mmu_normal_update(struct domain *d, intpte_t fpte)
+{
+    int rc = 0;
+    u32 map_perms = MMU__MAP_READ;
+    unsigned long fmfn;
+    struct domain_security_struct *dsec;
+    u32 fsid;
+
+    dsec = d->ssid;
+    
+    if ( get_pte_flags(fpte) & _PAGE_RW )
+        map_perms |= MMU__MAP_WRITE;
+
+    fmfn = ((unsigned long)(((fpte) & (PADDR_MASK&PAGE_MASK)) >> PAGE_SHIFT));
+
+    rc = get_page_sid(fmfn, &fsid);
+    if (rc)
+        return rc;
+
+    return avc_has_perm(dsec->sid, fsid, SECCLASS_MMU, map_perms, NULL);
+}
+
+static int flask_mmu_machphys_update(struct domain *d, unsigned long mfn)
+{
+    int rc = 0;
+    u32 psid;
+    struct domain_security_struct *dsec;
+    dsec = d->ssid;
+
+    rc = get_page_sid(mfn, &psid);
+    if (rc)
+        return rc;
+            
+    return avc_has_perm(dsec->sid, psid, SECCLASS_MMU, MMU__UPDATEMP, NULL);
+}
+
+static int flask_add_to_physmap(struct domain *d1, struct domain *d2)
+{
+    return domain_has_perm(d1, d2, SECCLASS_MMU, MMU__PHYSMAP);
+}
+#endif
+
+static struct xsm_operations flask_ops = {
+    .security_domaininfo = flask_security_domaininfo,
+    .setvcpucontext = flask_setvcpucontext,
+    .pausedomain = flask_pausedomain,
+    .unpausedomain = flask_unpausedomain,    
+    .resumedomain = flask_resumedomain,    
+    .domain_create = flask_domain_create,
+    .max_vcpus = flask_max_vcpus,
+    .destroydomain = flask_destroydomain,
+    .vcpuaffinity = flask_vcpuaffinity,
+    .scheduler = flask_scheduler,
+    .getdomaininfo = flask_getdomaininfo,
+    .getvcpucontext = flask_getvcpucontext,
+    .getvcpuinfo = flask_getvcpuinfo,
+    .domain_settime = flask_domain_settime,
+    .tbufcontrol = flask_tbufcontrol,
+    .readconsole = flask_readconsole,
+    .sched_id = flask_sched_id,
+    .setdomainmaxmem = flask_setdomainmaxmem,
+    .setdomainhandle = flask_setdomainhandle,
+    .setdebugging = flask_setdebugging,
+    .irq_permission = flask_irq_permission,
+    .iomem_permission = flask_iomem_permission,
+    .perfcontrol = flask_perfcontrol,
+    
+    .evtchn_unbound = flask_evtchn_unbound,
+    .evtchn_interdomain = flask_evtchn_interdomain,
+    .evtchn_close_post = flask_evtchn_close_post,
+    .evtchn_send = flask_evtchn_send,
+    .evtchn_status = flask_evtchn_status,
+    .evtchn_reset = flask_evtchn_reset,
+    
+    .grant_mapref = flask_grant_mapref,
+    .grant_unmapref = flask_grant_unmapref,
+    .grant_setup = flask_grant_setup,
+    .grant_transfer = flask_grant_transfer,
+    .grant_copy = flask_grant_copy,
+    .grant_query_size = flask_grant_query_size,
+            
+    .alloc_security_domain = flask_domain_alloc_security,
+    .free_security_domain = flask_domain_free_security,
+    .alloc_security_evtchn = flask_alloc_security_evtchn,
+    .free_security_evtchn = flask_free_security_evtchn,
+    
+    .translate_gpfn_list = flask_translate_gpfn_list,
+    .memory_adjust_reservation = flask_memory_adjust_reservation,
+    .memory_stat_reservation = flask_memory_stat_reservation,
+    .memory_pin_page = flask_memory_pin_page,
+    .update_va_mapping = flask_update_va_mapping,
+
+    .console_io = flask_console_io,
+    
+    .profile = flask_profile,
+
+    .kexec = flask_kexec,
+    .schedop_shutdown = flask_schedop_shutdown,
+    
+    .__do_xsm_op = do_flask_op,
+    .complete_init = flask_complete_init,    
+
+#ifdef CONFIG_X86
+    .shadow_control = flask_shadow_control,
+    .ioport_permission = flask_ioport_permission,
+    .getpageframeinfo = flask_getpageframeinfo,
+    .getmemlist = flask_getmemlist,
+    .hypercall_init = flask_hypercall_init,
+    .hvmcontext = flask_hvmcontext,
+    .address_size = flask_address_size,
+    .hvm_param = flask_hvm_param,
+    .hvm_set_pci_intx_level = flask_hvm_set_pci_intx_level,
+    .hvm_set_isa_irq_level = flask_hvm_set_isa_irq_level,
+    .hvm_set_pci_link_route = flask_hvm_set_pci_link_route,
+    .pirq_unmask = flask_pirq_unmask,
+    .pirq_status = flask_pirq_status,
+    .apic = flask_apic,
+    .assign_vector = flask_assign_vector,
+    .xen_settime = flask_xen_settime,
+    .memtype = flask_memtype,
+    .microcode = flask_microcode,
+    .physinfo = flask_physinfo,
+    .platform_quirk = flask_platform_quirk,
+    .machine_memory_map = flask_machine_memory_map,
+    .domain_memory_map = flask_domain_memory_map,
+    .mmu_normal_update = flask_mmu_normal_update,
+    .mmu_machphys_update = flask_mmu_machphys_update,
+    .add_to_physmap = flask_add_to_physmap,
+#endif
+};
+
+static __init int flask_init(void)
+{
+    int ret = 0;
+    
+    if (!flask_enabled) {
+        printk("Flask:  Disabled at boot.\n");
+        return 0;
+    }
+
+    printk("Flask:  Initializing.\n");
+
+    avc_init();
+
+    original_ops = xsm_ops;
+    if (register_xsm(&flask_ops))
+        panic("Flask: Unable to register with XSM.\n");
+
+    ret = security_load_policy(policy_buffer, policy_size);
+    
+    if (flask_enforcing) {
+        printk("Flask:  Starting in enforcing mode.\n");
+    } else {
+        printk("Flask:  Starting in permissive mode.\n");
+    }
+    
+    return ret;
+}
+
+xsm_initcall(flask_init);
diff -r 62b752969edf -r 2b79cd115561 xen/xsm/flask/include/av_inherit.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/include/av_inherit.h	Mon May 07 14:51:17 2007 -0400
@@ -0,0 +1,1 @@
+/* This file is automatically generated.  Do not edit. */
diff -r 62b752969edf -r 2b79cd115561 xen/xsm/flask/include/av_perm_to_string.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/include/av_perm_to_string.h	Mon May 07 14:51:17 2007 -0400
@@ -0,0 +1,99 @@
+/* This file is automatically generated.  Do not edit. */
+   S_(SECCLASS_XEN, XEN__SCHEDULER, "scheduler")
+   S_(SECCLASS_XEN, XEN__SETTIME, "settime")
+   S_(SECCLASS_XEN, XEN__TBUFCONTROL, "tbufcontrol")
+   S_(SECCLASS_XEN, XEN__READCONSOLE, "readconsole")
+   S_(SECCLASS_XEN, XEN__CLEARCONSOLE, "clearconsole")
+   S_(SECCLASS_XEN, XEN__PERFCONTROL, "perfcontrol")
+   S_(SECCLASS_XEN, XEN__MTRR_ADD, "mtrr_add")
+   S_(SECCLASS_XEN, XEN__MTRR_DEL, "mtrr_del")
+   S_(SECCLASS_XEN, XEN__MTRR_READ, "mtrr_read")
+   S_(SECCLASS_XEN, XEN__MICROCODE, "microcode")
+   S_(SECCLASS_XEN, XEN__PHYSINFO, "physinfo")
+   S_(SECCLASS_XEN, XEN__QUIRK, "quirk")
+   S_(SECCLASS_XEN, XEN__WRITECONSOLE, "writeconsole")
+   S_(SECCLASS_XEN, XEN__READAPIC, "readapic")
+   S_(SECCLASS_XEN, XEN__WRITEAPIC, "writeapic")
+   S_(SECCLASS_XEN, XEN__PRIVPROFILE, "privprofile")
+   S_(SECCLASS_XEN, XEN__NONPRIVPROFILE, "nonprivprofile")
+   S_(SECCLASS_XEN, XEN__KEXEC, "kexec")
+   S_(SECCLASS_DOMAIN, DOMAIN__SETVCPUCONTEXT, "setvcpucontext")
+   S_(SECCLASS_DOMAIN, DOMAIN__PAUSE, "pause")
+   S_(SECCLASS_DOMAIN, DOMAIN__UNPAUSE, "unpause")
+   S_(SECCLASS_DOMAIN, DOMAIN__RESUME, "resume")
+   S_(SECCLASS_DOMAIN, DOMAIN__CREATE, "create")
+   S_(SECCLASS_DOMAIN, DOMAIN__MAX_VCPUS, "max_vcpus")
+   S_(SECCLASS_DOMAIN, DOMAIN__DESTROY, "destroy")
+   S_(SECCLASS_DOMAIN, DOMAIN__SETVCPUAFFINITY, "setvcpuaffinity")
+   S_(SECCLASS_DOMAIN, DOMAIN__GETVCPUAFFINITY, "getvcpuaffinity")
+   S_(SECCLASS_DOMAIN, DOMAIN__SCHEDULER, "scheduler")
+   S_(SECCLASS_DOMAIN, DOMAIN__GETDOMAININFO, "getdomaininfo")
+   S_(SECCLASS_DOMAIN, DOMAIN__GETVCPUINFO, "getvcpuinfo")
+   S_(SECCLASS_DOMAIN, DOMAIN__GETVCPUCONTEXT, "getvcpucontext")
+   S_(SECCLASS_DOMAIN, DOMAIN__SETDOMAINMAXMEM, "setdomainmaxmem")
+   S_(SECCLASS_DOMAIN, DOMAIN__SETDOMAINHANDLE, "setdomainhandle")
+   S_(SECCLASS_DOMAIN, DOMAIN__SETDEBUGGING, "setdebugging")
+   S_(SECCLASS_DOMAIN, DOMAIN__HYPERCALL, "hypercall")
+   S_(SECCLASS_DOMAIN, DOMAIN__TRANSITION, "transition")
+   S_(SECCLASS_DOMAIN, DOMAIN__SETTIME, "settime")
+   S_(SECCLASS_DOMAIN, DOMAIN__SHUTDOWN, "shutdown")
+   S_(SECCLASS_DOMAIN, DOMAIN__SETADDRSIZE, "setaddrsize")
+   S_(SECCLASS_DOMAIN, DOMAIN__GETADDRSIZE, "getaddrsize")
+   S_(SECCLASS_HVM, HVM__SETHVMC, "sethvmc")
+   S_(SECCLASS_HVM, HVM__GETHVMC, "gethvmc")
+   S_(SECCLASS_HVM, HVM__SETPARAM, "setparam")
+   S_(SECCLASS_HVM, HVM__GETPARAM, "getparam")
+   S_(SECCLASS_HVM, HVM__PCILEVEL, "pcilevel")
+   S_(SECCLASS_HVM, HVM__IRQLEVEL, "irqlevel")
+   S_(SECCLASS_HVM, HVM__PCIROUTE, "pciroute")
+   S_(SECCLASS_EVENT, EVENT__BIND, "bind")
+   S_(SECCLASS_EVENT, EVENT__CLOSE, "close")
+   S_(SECCLASS_EVENT, EVENT__SEND, "send")
+   S_(SECCLASS_EVENT, EVENT__STATUS, "status")
+   S_(SECCLASS_EVENT, EVENT__UNMASK, "unmask")
+   S_(SECCLASS_EVENT, EVENT__NOTIFY, "notify")
+   S_(SECCLASS_EVENT, EVENT__CREATE, "create")
+   S_(SECCLASS_EVENT, EVENT__ALLOC, "alloc")
+   S_(SECCLASS_EVENT, EVENT__VECTOR, "vector")
+   S_(SECCLASS_EVENT, EVENT__RESET, "reset")
+   S_(SECCLASS_GRANT, GRANT__MAP_READ, "map_read")
+   S_(SECCLASS_GRANT, GRANT__MAP_WRITE, "map_write")
+   S_(SECCLASS_GRANT, GRANT__UNMAP, "unmap")
+   S_(SECCLASS_GRANT, GRANT__TRANSFER, "transfer")
+   S_(SECCLASS_GRANT, GRANT__SETUP, "setup")
+   S_(SECCLASS_GRANT, GRANT__COPY, "copy")
+   S_(SECCLASS_GRANT, GRANT__QUERY, "query")
+   S_(SECCLASS_MMU, MMU__MAP_READ, "map_read")
+   S_(SECCLASS_MMU, MMU__MAP_WRITE, "map_write")
+   S_(SECCLASS_MMU, MMU__PAGEINFO, "pageinfo")
+   S_(SECCLASS_MMU, MMU__PAGELIST, "pagelist")
+   S_(SECCLASS_MMU, MMU__ADJUST, "adjust")
+   S_(SECCLASS_MMU, MMU__STAT, "stat")
+   S_(SECCLASS_MMU, MMU__TRANSLATEGP, "translategp")
+   S_(SECCLASS_MMU, MMU__UPDATEMP, "updatemp")
+   S_(SECCLASS_MMU, MMU__PHYSMAP, "physmap")
+   S_(SECCLASS_MMU, MMU__PINPAGE, "pinpage")
+   S_(SECCLASS_MMU, MMU__MFNLIST, "mfnlist")
+   S_(SECCLASS_MMU, MMU__MEMORYMAP, "memorymap")
+   S_(SECCLASS_SHADOW, SHADOW__DISABLE, "disable")
+   S_(SECCLASS_SHADOW, SHADOW__ENABLE, "enable")
+   S_(SECCLASS_SHADOW, SHADOW__LOGDIRTY, "logdirty")
+   S_(SECCLASS_RESOURCE, RESOURCE__ADD, "add")
+   S_(SECCLASS_RESOURCE, RESOURCE__REMOVE, "remove")
+   S_(SECCLASS_RESOURCE, RESOURCE__USE, "use")
+   S_(SECCLASS_RESOURCE, RESOURCE__ADD_IRQ, "add_irq")
+   S_(SECCLASS_RESOURCE, RESOURCE__REMOVE_IRQ, "remove_irq")
+   S_(SECCLASS_RESOURCE, RESOURCE__ADD_IOPORT, "add_ioport")
+   S_(SECCLASS_RESOURCE, RESOURCE__REMOVE_IOPORT, "remove_ioport")
+   S_(SECCLASS_RESOURCE, RESOURCE__ADD_IOMEM, "add_iomem")
+   S_(SECCLASS_RESOURCE, RESOURCE__REMOVE_IOMEM, "remove_iomem")
+   S_(SECCLASS_SECURITY, SECURITY__COMPUTE_AV, "compute_av")
+   S_(SECCLASS_SECURITY, SECURITY__COMPUTE_CREATE, "compute_create")
+   S_(SECCLASS_SECURITY, SECURITY__COMPUTE_MEMBER, "compute_member")
+   S_(SECCLASS_SECURITY, SECURITY__CHECK_CONTEXT, "check_context")
+   S_(SECCLASS_SECURITY, SECURITY__LOAD_POLICY, "load_policy")
+   S_(SECCLASS_SECURITY, SECURITY__COMPUTE_RELABEL, "compute_relabel")
+   S_(SECCLASS_SECURITY, SECURITY__COMPUTE_USER, "compute_user")
+   S_(SECCLASS_SECURITY, SECURITY__SETENFORCE, "setenforce")
+   S_(SECCLASS_SECURITY, SECURITY__SETBOOL, "setbool")
+   S_(SECCLASS_SECURITY, SECURITY__SETSECPARAM, "setsecparam")
diff -r 62b752969edf -r 2b79cd115561 xen/xsm/flask/include/av_permissions.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/include/av_permissions.h	Mon May 07 14:51:17 2007 -0400
@@ -0,0 +1,108 @@
+/* This file is automatically generated.  Do not edit. */
+#define XEN__SCHEDULER                            0x00000001UL
+#define XEN__SETTIME                              0x00000002UL
+#define XEN__TBUFCONTROL                          0x00000004UL
+#define XEN__READCONSOLE                          0x00000008UL
+#define XEN__CLEARCONSOLE                         0x00000010UL
+#define XEN__PERFCONTROL                          0x00000020UL
+#define XEN__MTRR_ADD                             0x00000040UL
+#define XEN__MTRR_DEL                             0x00000080UL
+#define XEN__MTRR_READ                            0x00000100UL
+#define XEN__MICROCODE                            0x00000200UL
+#define XEN__PHYSINFO                             0x00000400UL
+#define XEN__QUIRK                                0x00000800UL
+#define XEN__WRITECONSOLE                         0x00001000UL
+#define XEN__READAPIC                             0x00002000UL
+#define XEN__WRITEAPIC                            0x00004000UL
+#define XEN__PRIVPROFILE                          0x00008000UL
+#define XEN__NONPRIVPROFILE                       0x00010000UL
+#define XEN__KEXEC                                0x00020000UL
+
+#define DOMAIN__SETVCPUCONTEXT                    0x00000001UL
+#define DOMAIN__PAUSE                             0x00000002UL
+#define DOMAIN__UNPAUSE                           0x00000004UL
+#define DOMAIN__RESUME                            0x00000008UL
+#define DOMAIN__CREATE                            0x00000010UL
+#define DOMAIN__MAX_VCPUS                         0x00000020UL
+#define DOMAIN__DESTROY                           0x00000040UL
+#define DOMAIN__SETVCPUAFFINITY                   0x00000080UL
+#define DOMAIN__GETVCPUAFFINITY                   0x00000100UL
+#define DOMAIN__SCHEDULER                         0x00000200UL
+#define DOMAIN__GETDOMAININFO                     0x00000400UL
+#define DOMAIN__GETVCPUINFO                       0x00000800UL
+#define DOMAIN__GETVCPUCONTEXT                    0x00001000UL
+#define DOMAIN__SETDOMAINMAXMEM                   0x00002000UL
+#define DOMAIN__SETDOMAINHANDLE                   0x00004000UL
+#define DOMAIN__SETDEBUGGING                      0x00008000UL
+#define DOMAIN__HYPERCALL                         0x00010000UL
+#define DOMAIN__TRANSITION                        0x00020000UL
+#define DOMAIN__SETTIME                           0x00040000UL
+#define DOMAIN__SHUTDOWN                          0x00080000UL
+#define DOMAIN__SETADDRSIZE                       0x00100000UL
+#define DOMAIN__GETADDRSIZE                       0x00200000UL
+
+#define HVM__SETHVMC                              0x00000001UL
+#define HVM__GETHVMC                              0x00000002UL
+#define HVM__SETPARAM                             0x00000004UL
+#define HVM__GETPARAM                             0x00000008UL
+#define HVM__PCILEVEL                             0x00000010UL
+#define HVM__IRQLEVEL                             0x00000020UL
+#define HVM__PCIROUTE                             0x00000040UL
+
+#define EVENT__BIND                               0x00000001UL
+#define EVENT__CLOSE                              0x00000002UL
+#define EVENT__SEND                               0x00000004UL
+#define EVENT__STATUS                             0x00000008UL
+#define EVENT__UNMASK                             0x00000010UL
+#define EVENT__NOTIFY                             0x00000020UL
+#define EVENT__CREATE                             0x00000040UL
+#define EVENT__ALLOC                              0x00000080UL
+#define EVENT__VECTOR                             0x00000100UL
+#define EVENT__RESET                              0x00000200UL
+
+#define GRANT__MAP_READ                           0x00000001UL
+#define GRANT__MAP_WRITE                          0x00000002UL
+#define GRANT__UNMAP                              0x00000004UL
+#define GRANT__TRANSFER                           0x00000008UL
+#define GRANT__SETUP                              0x00000010UL
+#define GRANT__COPY                               0x00000020UL
+#define GRANT__QUERY                              0x00000040UL
+
+#define MMU__MAP_READ                             0x00000001UL
+#define MMU__MAP_WRITE                            0x00000002UL
+#define MMU__PAGEINFO                             0x00000004UL
+#define MMU__PAGELIST                             0x00000008UL
+#define MMU__ADJUST                               0x00000010UL
+#define MMU__STAT                                 0x00000020UL
+#define MMU__TRANSLATEGP                          0x00000040UL
+#define MMU__UPDATEMP                             0x00000080UL
+#define MMU__PHYSMAP                              0x00000100UL
+#define MMU__PINPAGE                              0x00000200UL
+#define MMU__MFNLIST                              0x00000400UL
+#define MMU__MEMORYMAP                            0x00000800UL
+
+#define SHADOW__DISABLE                           0x00000001UL
+#define SHADOW__ENABLE                            0x00000002UL
+#define SHADOW__LOGDIRTY                          0x00000004UL
+
+#define RESOURCE__ADD                             0x00000001UL
+#define RESOURCE__REMOVE                          0x00000002UL
+#define RESOURCE__USE                             0x00000004UL
+#define RESOURCE__ADD_IRQ                         0x00000008UL
+#define RESOURCE__REMOVE_IRQ                      0x00000010UL
+#define RESOURCE__ADD_IOPORT                      0x00000020UL
+#define RESOURCE__REMOVE_IOPORT                   0x00000040UL
+#define RESOURCE__ADD_IOMEM                       0x00000080UL
+#define RESOURCE__REMOVE_IOMEM                    0x00000100UL
+
+#define SECURITY__COMPUTE_AV                      0x00000001UL
+#define SECURITY__COMPUTE_CREATE                  0x00000002UL
+#define SECURITY__COMPUTE_MEMBER                  0x00000004UL
+#define SECURITY__CHECK_CONTEXT                   0x00000008UL
+#define SECURITY__LOAD_POLICY                     0x00000010UL
+#define SECURITY__COMPUTE_RELABEL                 0x00000020UL
+#define SECURITY__COMPUTE_USER                    0x00000040UL
+#define SECURITY__SETENFORCE                      0x00000080UL
+#define SECURITY__SETBOOL                         0x00000100UL
+#define SECURITY__SETSECPARAM                     0x00000200UL
+
diff -r 62b752969edf -r 2b79cd115561 xen/xsm/flask/include/avc.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/include/avc.h	Mon May 07 14:51:17 2007 -0400
@@ -0,0 +1,110 @@
+/*
+ * Access vector cache interface for object managers.
+ *
+ * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
+ */
+ 
+/* Ported to Xen 3.0, George Coker, <gscoker@alpha.ncsc.mil> */
+
+#ifndef _FLASK_AVC_H_
+#define _FLASK_AVC_H_
+
+#include <xen/errno.h>
+#include <xen/lib.h>
+#include <xen/spinlock.h>
+#include <asm/percpu.h>
+#include "flask.h"
+#include "av_permissions.h"
+#include "security.h"
+
+#ifdef FLASK_DEVELOP
+extern int flask_enforcing;
+#else
+#define flask_enforcing 1
+#endif
+
+/*
+ * An entry in the AVC.
+ */
+struct avc_entry;
+
+struct task_struct;
+struct vfsmount;
+struct dentry;
+struct inode;
+struct sock;
+struct sk_buff;
+
+/* Auxiliary data to use in generating the audit record. */
+struct avc_audit_data {
+    char    type;
+#define AVC_AUDIT_DATA_FS   1
+#define AVC_AUDIT_DATA_NET  2
+#define AVC_AUDIT_DATA_CAP  3
+#define AVC_AUDIT_DATA_IPC  4
+    struct domain *d;
+};
+
+#define v4info fam.v4
+#define v6info fam.v6
+
+/* Initialize an AVC audit data structure. */
+#define AVC_AUDIT_DATA_INIT(_d,_t) \
+        { memset((_d), 0, sizeof(struct avc_audit_data)); (_d)->type = AVC_AUDIT_DATA_##_t; }
+
+/*
+ * AVC statistics
+ */
+struct avc_cache_stats
+{
+    unsigned int lookups;
+    unsigned int hits;
+    unsigned int misses;
+    unsigned int allocations;
+    unsigned int reclaims;
+    unsigned int frees;
+};
+
+/*
+ * AVC operations
+ */
+
+void avc_init(void);
+
+void avc_audit(u32 ssid, u32 tsid,
+               u16 tclass, u32 requested,
+               struct av_decision *avd, int result, struct avc_audit_data *auditdata);
+
+int avc_has_perm_noaudit(u32 ssid, u32 tsid,
+                         u16 tclass, u32 requested,
+                         struct av_decision *avd);
+
+int avc_has_perm(u32 ssid, u32 tsid,
+                 u16 tclass, u32 requested,
+                 struct avc_audit_data *auditdata);
+
+#define AVC_CALLBACK_GRANT        1
+#define AVC_CALLBACK_TRY_REVOKE        2
+#define AVC_CALLBACK_REVOKE        4
+#define AVC_CALLBACK_RESET        8
+#define AVC_CALLBACK_AUDITALLOW_ENABLE    16
+#define AVC_CALLBACK_AUDITALLOW_DISABLE    32
+#define AVC_CALLBACK_AUDITDENY_ENABLE    64
+#define AVC_CALLBACK_AUDITDENY_DISABLE    128
+
+int avc_add_callback(int (*callback)(u32 event, u32 ssid, u32 tsid,
+                                     u16 tclass, u32 perms,
+                                     u32 *out_retained),
+                     u32 events, u32 ssid, u32 tsid,
+                     u16 tclass, u32 perms);
+
+/* Exported to selinuxfs */
+int avc_get_hash_stats(char *page);
+extern unsigned int avc_cache_threshold;
+
+#ifdef FLASK_AVC_STATS
+DECLARE_PER_CPU(struct avc_cache_stats, avc_cache_stats);
+#endif
+
+#endif /* _FLASK_AVC_H_ */
+
diff -r 62b752969edf -r 2b79cd115561 xen/xsm/flask/include/avc_ss.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/include/avc_ss.h	Mon May 07 14:51:17 2007 -0400
@@ -0,0 +1,14 @@
+/*
+ * Access vector cache interface for the security server.
+ *
+ * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
+ */
+#ifndef _FLASK_AVC_SS_H_
+#define _FLASK_AVC_SS_H_
+
+#include "flask.h"
+
+int avc_ss_reset(u32 seqno);
+
+#endif /* _FLASK_AVC_SS_H_ */
+
diff -r 62b752969edf -r 2b79cd115561 xen/xsm/flask/include/class_to_string.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/include/class_to_string.h	Mon May 07 14:51:17 2007 -0400
@@ -0,0 +1,14 @@
+/* This file is automatically generated.  Do not edit. */
+/*
+ * Security object class definitions
+ */
+    S_("null")
+    S_("xen")
+    S_("domain")
+    S_("hvm")
+    S_("mmu")
+    S_("resource")
+    S_("shadow")
+    S_("event")
+    S_("grant")
+    S_("security")
diff -r 62b752969edf -r 2b79cd115561 xen/xsm/flask/include/common_perm_to_string.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/include/common_perm_to_string.h	Mon May 07 14:51:17 2007 -0400
@@ -0,0 +1,1 @@
+/* This file is automatically generated.  Do not edit. */
diff -r 62b752969edf -r 2b79cd115561 xen/xsm/flask/include/conditional.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/include/conditional.h	Mon May 07 14:51:17 2007 -0400
@@ -0,0 +1,22 @@
+/*
+ * Interface to booleans in the security server. This is exported
+ * for the selinuxfs.
+ *
+ * Author: Karl MacMillan <kmacmillan@tresys.com>
+ *
+ * Copyright (C) 2003 - 2004 Tresys Technology, LLC
+ *    This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation, version 2.
+ */
+
+#ifndef _FLASK_CONDITIONAL_H_
+#define _FLASK_CONDITIONAL_H_
+
+int security_get_bools(int *len, char ***names, int **values);
+
+int security_set_bools(int len, int *values);
+
+int security_get_bool_value(int bool);
+
+#endif
diff -r 62b752969edf -r 2b79cd115561 xen/xsm/flask/include/flask.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/include/flask.h	Mon May 07 14:51:17 2007 -0400
@@ -0,0 +1,36 @@
+/* This file is automatically generated.  Do not edit. */
+#ifndef _FLASK_FLASK_H_
+#define _FLASK_FLASK_H_
+
+/*
+ * Security object class definitions
+ */
+#define SECCLASS_XEN                                     1
+#define SECCLASS_DOMAIN                                  2
+#define SECCLASS_HVM                                     3
+#define SECCLASS_MMU                                     4
+#define SECCLASS_RESOURCE                                5
+#define SECCLASS_SHADOW                                  6
+#define SECCLASS_EVENT                                   7
+#define SECCLASS_GRANT                                   8
+#define SECCLASS_SECURITY                                9
+
+/*
+ * Security identifier indices for initial entities
+ */
+#define SECINITSID_XEN                                  1
+#define SECINITSID_DOM0                                 2
+#define SECINITSID_DOMU                                 3
+#define SECINITSID_DOMIO                                4
+#define SECINITSID_DOMXEN                               5
+#define SECINITSID_UNLABELED                            6
+#define SECINITSID_SECURITY                             7
+#define SECINITSID_IOPORT                               8
+#define SECINITSID_IOMEM                                9
+#define SECINITSID_VCPU                                 10
+#define SECINITSID_VIRQ                                 11
+#define SECINITSID_PIRQ                                 12
+
+#define SECINITSID_NUM                                  12
+
+#endif
diff -r 62b752969edf -r 2b79cd115561 xen/xsm/flask/include/initial_sid_to_string.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/include/initial_sid_to_string.h	Mon May 07 14:51:17 2007 -0400
@@ -0,0 +1,18 @@
+/* This file is automatically generated.  Do not edit. */
+static char *initial_sid_to_string[] =
+{
+    "null",
+    "xen",
+    "dom0",
+    "domU",
+    "domio",
+    "domxen",
+    "unlabeled",
+    "security",
+    "ioport",
+    "iomem",
+    "vcpu",
+    "virq",
+    "pirq",
+};
+
diff -r 62b752969edf -r 2b79cd115561 xen/xsm/flask/include/objsec.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/include/objsec.h	Mon May 07 14:51:17 2007 -0400
@@ -0,0 +1,33 @@
+/*
+ *  NSA Security-Enhanced Linux (SELinux) security module
+ *
+ *  This file contains the Flask security data structures for xen objects.
+ *
+ *  Author(s):  George Coker, <gscoker@alpha.ncsc.mil>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License version 2,
+ *      as published by the Free Software Foundation.
+ */
+
+#ifndef _FLASK_OBJSEC_H_
+#define _FLASK_OBJSEC_H_
+
+#include <xen/sched.h>
+#include "flask.h"
+#include "avc.h"
+
+struct domain_security_struct {
+    struct domain *d;      /* back pointer to domain object */
+    u32 sid;               /* current SID */
+    u32 create_sid;
+};
+
+struct evtchn_security_struct {
+    struct evtchn *chn;      /* back pointer to evtchn object */
+    u32 sid;                 /* current SID */
+};
+
+extern unsigned int selinux_checkreqprot;
+
+#endif /* _FLASK_OBJSEC_H_ */
diff -r 62b752969edf -r 2b79cd115561 xen/xsm/flask/include/security.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/include/security.h	Mon May 07 14:51:17 2007 -0400
@@ -0,0 +1,84 @@
+/*
+ * Security server interface.
+ *
+ * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
+ *
+ */
+
+/* Ported to Xen 3.0, George Coker, <gscoker@alpha.ncsc.mil> */
+
+#ifndef _FLASK_SECURITY_H_
+#define _FLASK_SECURITY_H_
+
+#include "flask.h"
+
+#define SECSID_NULL            0x00000000 /* unspecified SID */
+#define SECSID_WILD            0xffffffff /* wildcard SID */
+#define SECCLASS_NULL            0x0000 /* no class */
+
+#define SELINUX_MAGIC 0xf97cff8c
+
+/* Identify specific policy version changes */
+#define POLICYDB_VERSION_BASE        15
+#define POLICYDB_VERSION_BOOL        16
+#define POLICYDB_VERSION_IPV6        17
+#define POLICYDB_VERSION_NLCLASS    18
+#define POLICYDB_VERSION_VALIDATETRANS    19
+#define POLICYDB_VERSION_MLS        19
+#define POLICYDB_VERSION_AVTAB        20
+
+/* Range of policy versions we understand*/
+#define POLICYDB_VERSION_MIN   POLICYDB_VERSION_BASE
+#define POLICYDB_VERSION_MAX   POLICYDB_VERSION_AVTAB
+
+#ifdef FLASK_BOOTPARAM
+extern int flask_enabled;
+#else
+#define flask_enabled 1
+#endif
+
+extern int flask_mls_enabled;
+
+int security_load_policy(void * data, size_t len);
+
+struct av_decision {
+    u32 allowed;
+    u32 decided;
+    u32 auditallow;
+    u32 auditdeny;
+    u32 seqno;
+};
+
+int security_compute_av(u32 ssid, u32 tsid, u16 tclass, u32 requested,
+                        struct av_decision *avd);
+
+int security_transition_sid(u32 ssid, u32 tsid, u16 tclass, u32 *out_sid);
+
+int security_member_sid(u32 ssid, u32 tsid, u16 tclass, u32 *out_sid);
+
+int security_change_sid(u32 ssid, u32 tsid, u16 tclass, u32 *out_sid);
+
+int security_sid_to_context(u32 sid, char **scontext, u32 *scontext_len);
+
+int security_context_to_sid(char *scontext, u32 scontext_len, u32 *out_sid);
+
+int security_context_to_sid_default(char *scontext, u32 scontext_len, 
+                                    u32 *out_sid, u32 def_sid);
+
+int security_get_user_sids(u32 callsid, char *username, u32 **sids, u32 *nel);
+
+int security_pirq_sid(int pirq, u32 *out_sid);
+
+int security_virq_sid(int virq, u32 *out_sid);
+
+int security_vcpu_sid(int vcpu, u32 *out_sid);
+
+int security_iomem_sid(unsigned long, u32 *out_sid);
+
+int security_ioport_sid(u32 ioport, u32 *out_sid);
+
+int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid,
+                                 u16 tclass);
+
+#endif /* _FLASK_SECURITY_H_ */
+
diff -r 62b752969edf -r 2b79cd115561 xen/xsm/flask/ss/Makefile
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/ss/Makefile	Mon May 07 14:51:17 2007 -0400
@@ -0,0 +1,11 @@
+obj-y += ebitmap.o
+obj-y += hashtab.o
+obj-y += symtab.o
+obj-y += sidtab.o
+obj-y += avtab.o
+obj-y += policydb.o
+obj-y += services.o
+obj-y += conditional.o
+obj-y += mls.o
+
+CFLAGS += -I../include
diff -r 62b752969edf -r 2b79cd115561 xen/xsm/flask/ss/avtab.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/ss/avtab.c	Mon May 07 14:51:17 2007 -0400
@@ -0,0 +1,445 @@
+/*
+ * Implementation of the access vector table type.
+ *
+ * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
+ */
+
+/* Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com>
+ *
+ *     Added conditional policy language extensions
+ *
+ * Copyright (C) 2003 Tresys Technology, LLC
+ *    This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation, version 2.
+ */
+
+/* Ported to Xen 3.0, George Coker, <gscoker@alpha.ncsc.mil> */
+
+#include <xen/lib.h>
+#include <asm/byteorder.h>
+#include <xen/types.h>
+#include <xen/xmalloc.h>
+#include <xen/errno.h>
+
+#include "avtab.h"
+#include "policydb.h"
+
+#define AVTAB_HASH(keyp) \
+((keyp->target_class + \
+ (keyp->target_type << 2) + \
+ (keyp->source_type << 9)) & \
+ AVTAB_HASH_MASK)
+
+static struct avtab_node*
+avtab_insert_node(struct avtab *h, int hvalue,
+          struct avtab_node * prev, struct avtab_node * cur,
+          struct avtab_key *key, struct avtab_datum *datum)
+{
+    struct avtab_node * newnode;
+    newnode = xmalloc(struct avtab_node);
+    if (newnode == NULL)
+        return NULL;
+    memset(newnode, 0, sizeof(struct avtab_node));
+    newnode->key = *key;
+    newnode->datum = *datum;
+    if (prev) {
+        newnode->next = prev->next;
+        prev->next = newnode;
+    } else {
+        newnode->next = h->htable[hvalue];
+        h->htable[hvalue] = newnode;
+    }
+
+    h->nel++;
+    return newnode;
+}
+
+static int avtab_insert(struct avtab *h, struct avtab_key *key, struct avtab_datum *datum)
+{
+    int hvalue;
+    struct avtab_node *prev, *cur, *newnode;
+    u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD);
+
+    if (!h)
+        return -EINVAL;
+
+    hvalue = AVTAB_HASH(key);
+    for (prev = NULL, cur = h->htable[hvalue];
+         cur;
+         prev = cur, cur = cur->next) {
+        if (key->source_type == cur->key.source_type &&
+            key->target_type == cur->key.target_type &&
+            key->target_class == cur->key.target_class &&
+            (specified & cur->key.specified))
+            return -EEXIST;
+        if (key->source_type < cur->key.source_type)
+            break;
+        if (key->source_type == cur->key.source_type &&
+            key->target_type < cur->key.target_type)
+            break;
+        if (key->source_type == cur->key.source_type &&
+            key->target_type == cur->key.target_type &&
+            key->target_class < cur->key.target_class)
+            break;
+    }
+
+    newnode = avtab_insert_node(h, hvalue, prev, cur, key, datum);
+    if(!newnode)
+        return -ENOMEM;
+
+    return 0;
+}
+
+/* Unlike avtab_insert(), this function allow multiple insertions of the same
+ * key/specified mask into the table, as needed by the conditional avtab.
+ * It also returns a pointer to the node inserted.
+ */
+struct avtab_node *
+avtab_insert_nonunique(struct avtab * h, struct avtab_key * key, struct avtab_datum * datum)
+{
+    int hvalue;
+    struct avtab_node *prev, *cur, *newnode;
+    u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD);
+
+    if (!h)
+        return NULL;
+    hvalue = AVTAB_HASH(key);
+    for (prev = NULL, cur = h->htable[hvalue];
+         cur;
+         prev = cur, cur = cur->next) {
+        if (key->source_type == cur->key.source_type &&
+            key->target_type == cur->key.target_type &&
+            key->target_class == cur->key.target_class &&
+            (specified & cur->key.specified))
+            break;
+        if (key->source_type < cur->key.source_type)
+            break;
+        if (key->source_type == cur->key.source_type &&
+            key->target_type < cur->key.target_type)
+            break;
+        if (key->source_type == cur->key.source_type &&
+            key->target_type == cur->key.target_type &&
+            key->target_class < cur->key.target_class)
+            break;
+    }
+    newnode = avtab_insert_node(h, hvalue, prev, cur, key, datum);
+
+    return newnode;
+}
+
+struct avtab_datum *avtab_search(struct avtab *h, struct avtab_key *key)
+{
+    int hvalue;
+    struct avtab_node *cur;
+    u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD);
+
+    if (!h)
+        return NULL;
+
+    hvalue = AVTAB_HASH(key);
+    for (cur = h->htable[hvalue]; cur; cur = cur->next) {
+        if (key->source_type == cur->key.source_type &&
+            key->target_type == cur->key.target_type &&
+            key->target_class == cur->key.target_class &&
+            (specified & cur->key.specified))
+            return &cur->datum;
+
+        if (key->source_type < cur->key.source_type)
+            break;
+        if (key->source_type == cur->key.source_type &&
+            key->target_type < cur->key.target_type)
+            break;
+        if (key->source_type == cur->key.source_type &&
+            key->target_type == cur->key.target_type &&
+            key->target_class < cur->key.target_class)
+            break;
+    }
+
+    return NULL;
+}
+
+/* This search function returns a node pointer, and can be used in
+ * conjunction with avtab_search_next_node()
+ */
+struct avtab_node*
+avtab_search_node(struct avtab *h, struct avtab_key *key)
+{
+    int hvalue;
+    struct avtab_node *cur;
+    u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD);
+
+    if (!h)
+        return NULL;
+
+    hvalue = AVTAB_HASH(key);
+    for (cur = h->htable[hvalue]; cur; cur = cur->next) {
+        if (key->source_type == cur->key.source_type &&
+            key->target_type == cur->key.target_type &&
+            key->target_class == cur->key.target_class &&
+            (specified & cur->key.specified))
+            return cur;
+
+        if (key->source_type < cur->key.source_type)
+            break;
+        if (key->source_type == cur->key.source_type &&
+            key->target_type < cur->key.target_type)
+            break;
+        if (key->source_type == cur->key.source_type &&
+            key->target_type == cur->key.target_type &&
+            key->target_class < cur->key.target_class)
+            break;
+    }
+    return NULL;
+}
+
+struct avtab_node*
+avtab_search_node_next(struct avtab_node *node, int specified)
+{
+    struct avtab_node *cur;
+
+    if (!node)
+        return NULL;
+
+    specified &= ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD);
+    for (cur = node->next; cur; cur = cur->next) {
+        if (node->key.source_type == cur->key.source_type &&
+            node->key.target_type == cur->key.target_type &&
+            node->key.target_class == cur->key.target_class &&
+            (specified & cur->key.specified))
+            return cur;
+
+        if (node->key.source_type < cur->key.source_type)
+            break;
+        if (node->key.source_type == cur->key.source_type &&
+            node->key.target_type < cur->key.target_type)
+            break;
+        if (node->key.source_type == cur->key.source_type &&
+            node->key.target_type == cur->key.target_type &&
+            node->key.target_class < cur->key.target_class)
+            break;
+    }
+    return NULL;
+}
+
+void avtab_destroy(struct avtab *h)
+{
+    int i;
+    struct avtab_node *cur, *temp;
+
+    if (!h || !h->htable)
+        return;
+
+    for (i = 0; i < AVTAB_SIZE; i++) {
+        cur = h->htable[i];
+        while (cur != NULL) {
+            temp = cur;
+            cur = cur->next;
+            xfree(temp);
+        }
+        h->htable[i] = NULL;
+    }
+    xfree(h->htable);
+    h->htable = NULL;
+}
+
+
+int avtab_init(struct avtab *h)
+{
+    int i;
+
+    h->htable = (void *)xmalloc_array(struct avtab_node, AVTAB_SIZE);
+    if (!h->htable)
+        return -ENOMEM;
+    for (i = 0; i < AVTAB_SIZE; i++)
+        h->htable[i] = NULL;
+    h->nel = 0;
+    return 0;
+}
+
+void avtab_hash_eval(struct avtab *h, char *tag)
+{
+    int i, chain_len, slots_used, max_chain_len;
+    struct avtab_node *cur;
+
+    slots_used = 0;
+    max_chain_len = 0;
+    for (i = 0; i < AVTAB_SIZE; i++) {
+        cur = h->htable[i];
+        if (cur) {
+            slots_used++;
+            chain_len = 0;
+            while (cur) {
+                chain_len++;
+                cur = cur->next;
+            }
+
+            if (chain_len > max_chain_len)
+                max_chain_len = chain_len;
+        }
+    }
+
+    printk(KERN_INFO "%s:  %d entries and %d/%d buckets used, longest "
+           "chain length %d\n", tag, h->nel, slots_used, AVTAB_SIZE,
+           max_chain_len);
+}
+
+static uint16_t spec_order[] = {
+    AVTAB_ALLOWED,
+    AVTAB_AUDITDENY,
+    AVTAB_AUDITALLOW,
+    AVTAB_TRANSITION,
+    AVTAB_CHANGE,
+    AVTAB_MEMBER
+};
+
+int avtab_read_item(void *fp, u32 vers, struct avtab *a,
+                int (*insertf)(struct avtab *a, struct avtab_key *k,
+                   struct avtab_datum *d, void *p),
+            void *p)
+{
+    __le16 buf16[4];
+    u16 enabled;
+    __le32 buf32[7];
+    u32 items, items2, val;
+    struct avtab_key key;
+    struct avtab_datum datum;
+    int i, rc;
+
+    memset(&key, 0, sizeof(struct avtab_key));
+    memset(&datum, 0, sizeof(struct avtab_datum));
+
+    if (vers < POLICYDB_VERSION_AVTAB) {
+        rc = next_entry(buf32, fp, sizeof(u32));
+        if (rc < 0) {
+            printk(KERN_ERR "security: avtab: truncated entry\n");
+            return -1;
+        }
+        items2 = le32_to_cpu(buf32[0]);
+        if (items2 > ARRAY_SIZE(buf32)) {
+            printk(KERN_ERR "security: avtab: entry overflow\n");
+            return -1;
+
+        }
+        rc = next_entry(buf32, fp, sizeof(u32)*items2);
+        if (rc < 0) {
+            printk(KERN_ERR "security: avtab: truncated entry\n");
+            return -1;
+        }
+        items = 0;
+
+        val = le32_to_cpu(buf32[items++]);
+        key.source_type = (u16)val;
+        if (key.source_type != val) {
+            printk("security: avtab: truncated source type\n");
+            return -1;
+        }
+        val = le32_to_cpu(buf32[items++]);
+        key.target_type = (u16)val;
+        if (key.target_type != val) {
+            printk("security: avtab: truncated target type\n");
+            return -1;
+        }
+        val = le32_to_cpu(buf32[items++]);
+        key.target_class = (u16)val;
+        if (key.target_class != val) {
+            printk("security: avtab: truncated target class\n");
+            return -1;
+        }
+
+        val = le32_to_cpu(buf32[items++]);
+        enabled = (val & AVTAB_ENABLED_OLD) ? AVTAB_ENABLED : 0;
+
+        if (!(val & (AVTAB_AV | AVTAB_TYPE))) {
+            printk("security: avtab: null entry\n");
+            return -1;
+        }
+        if ((val & AVTAB_AV) &&
+            (val & AVTAB_TYPE)) {
+            printk("security: avtab: entry has both access vectors and types\n");
+            return -1;
+        }
+
+        for (i = 0; i < sizeof(spec_order)/sizeof(u16); i++) {
+            if (val & spec_order[i]) {
+                key.specified = spec_order[i] | enabled;
+                datum.data = le32_to_cpu(buf32[items++]);
+                rc = insertf(a, &key, &datum, p);
+                if (rc) return rc;
+            }
+        }
+
+        if (items != items2) {
+            printk("security: avtab: entry only had %d items, expected %d\n", items2, items);
+            return -1;
+        }
+        return 0;
+    }
+
+    rc = next_entry(buf16, fp, sizeof(u16)*4);
+    if (rc < 0) {
+        printk("security: avtab: truncated entry\n");
+        return -1;
+    }
+
+    items = 0;
+    key.source_type = le16_to_cpu(buf16[items++]);
+    key.target_type = le16_to_cpu(buf16[items++]);
+    key.target_class = le16_to_cpu(buf16[items++]);
+    key.specified = le16_to_cpu(buf16[items++]);
+
+    rc = next_entry(buf32, fp, sizeof(u32));
+    if (rc < 0) {
+        printk("security: avtab: truncated entry\n");
+        return -1;
+    }
+    datum.data = le32_to_cpu(*buf32);
+    return insertf(a, &key, &datum, p);
+}
+
+static int avtab_insertf(struct avtab *a, struct avtab_key *k,
+             struct avtab_datum *d, void *p)
+{
+    return avtab_insert(a, k, d);
+}
+
+int avtab_read(struct avtab *a, void *fp, u32 vers)
+{
+    int rc;
+    __le32 buf[1];
+    u32 nel, i;
+
+
+    rc = next_entry(buf, fp, sizeof(u32));
+    if (rc < 0) {
+        printk(KERN_ERR "security: avtab: truncated table\n");
+        goto bad;
+    }
+    nel = le32_to_cpu(buf[0]);
+    if (!nel) {
+        printk(KERN_ERR "security: avtab: table is empty\n");
+        rc = -EINVAL;
+        goto bad;
+    }
+    for (i = 0; i < nel; i++) {
+        rc = avtab_read_item(fp,vers, a, avtab_insertf, NULL);
+        if (rc) {
+            if (rc == -ENOMEM)
+                printk(KERN_ERR "security: avtab: out of memory\n");
+            else if (rc == -EEXIST)
+                printk(KERN_ERR "security: avtab: duplicate entry\n");
+            else
+                rc = -EINVAL;
+            goto bad;
+        }
+    }
+
+    rc = 0;
+out:
+    return rc;
+
+bad:
+    avtab_destroy(a);
+    goto out;
+}
+
diff -r 62b752969edf -r 2b79cd115561 xen/xsm/flask/ss/avtab.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/ss/avtab.h	Mon May 07 14:51:17 2007 -0400
@@ -0,0 +1,84 @@
+/*
+ * An access vector table (avtab) is a hash table
+ * of access vectors and transition types indexed
+ * by a type pair and a class.  An access vector
+ * table is used to represent the type enforcement
+ * tables.
+ *
+ *  Author : Stephen Smalley, <sds@epoch.ncsc.mil>
+ */
+
+/* Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com>
+ *
+ *     Added conditional policy language extensions
+ *
+ * Copyright (C) 2003 Tresys Technology, LLC
+ *    This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation, version 2.
+ */
+ 
+/* Ported to Xen 3.0, George Coker, <gscoker@alpha.ncsc.mil> */
+
+#ifndef _SS_AVTAB_H_
+#define _SS_AVTAB_H_
+
+struct avtab_key {
+    u16 source_type;    /* source type */
+    u16 target_type;    /* target type */
+    u16 target_class;    /* target object class */
+#define AVTAB_ALLOWED     1
+#define AVTAB_AUDITALLOW  2
+#define AVTAB_AUDITDENY   4
+#define AVTAB_AV         (AVTAB_ALLOWED | AVTAB_AUDITALLOW | AVTAB_AUDITDENY)
+#define AVTAB_TRANSITION 16
+#define AVTAB_MEMBER     32
+#define AVTAB_CHANGE     64
+#define AVTAB_TYPE       (AVTAB_TRANSITION | AVTAB_MEMBER | AVTAB_CHANGE)
+#define AVTAB_ENABLED_OLD    0x80000000 /* reserved for used in cond_avtab */
+#define AVTAB_ENABLED    0x8000 /* reserved for used in cond_avtab */
+    u16 specified;    /* what field is specified */
+};
+
+struct avtab_datum {
+    u32 data; /* access vector or type value */
+};
+
+struct avtab_node {
+    struct avtab_key key;
+    struct avtab_datum datum;
+    struct avtab_node *next;
+};
+
+struct avtab {
+    struct avtab_node **htable;
+    u32 nel;    /* number of elements */
+};
+
+int avtab_init(struct avtab *);
+struct avtab_datum *avtab_search(struct avtab *h, struct avtab_key *k);
+void avtab_destroy(struct avtab *h);
+void avtab_hash_eval(struct avtab *h, char *tag);
+
+int avtab_read_item(void *fp, uint32_t vers, struct avtab *a,
+            int (*insert)(struct avtab *a, struct avtab_key *k,
+                  struct avtab_datum *d, void *p),
+            void *p);
+
+int avtab_read(struct avtab *a, void *fp, u32 vers);
+
+struct avtab_node *avtab_insert_nonunique(struct avtab *h, struct avtab_key *key,
+                      struct avtab_datum *datum);
+
+struct avtab_node *avtab_search_node(struct avtab *h, struct avtab_key *key);
+
+struct avtab_node *avtab_search_node_next(struct avtab_node *node, int specified);
+
+#define AVTAB_HASH_BITS 15
+#define AVTAB_HASH_BUCKETS (1 << AVTAB_HASH_BITS)
+#define AVTAB_HASH_MASK (AVTAB_HASH_BUCKETS-1)
+
+#define AVTAB_SIZE AVTAB_HASH_BUCKETS
+
+#endif    /* _SS_AVTAB_H_ */
+
diff -r 62b752969edf -r 2b79cd115561 xen/xsm/flask/ss/conditional.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/ss/conditional.c	Mon May 07 14:51:17 2007 -0400
@@ -0,0 +1,516 @@
+/* Authors: Karl MacMillan <kmacmillan@tresys.com>
+ *          Frank Mayer <mayerf@tresys.com>
+ *
+ * Copyright (C) 2003 - 2004 Tresys Technology, LLC
+ *    This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation, version 2.
+ */
+
+/* Ported to Xen 3.0, George Coker, <gscoker@alpha.ncsc.mil> */
+
+#include <asm/byteorder.h>
+#include <xen/lib.h>
+#include <xen/types.h>
+#include <xen/errno.h>
+#include <xen/string.h>
+#include <xen/spinlock.h>
+#include <xen/xmalloc.h>
+
+#include "security.h"
+#include "conditional.h"
+
+/*
+ * cond_evaluate_expr evaluates a conditional expr
+ * in reverse polish notation. It returns true (1), false (0),
+ * or undefined (-1). Undefined occurs when the expression
+ * exceeds the stack depth of COND_EXPR_MAXDEPTH.
+ */
+static int cond_evaluate_expr(struct policydb *p, struct cond_expr *expr)
+{
+
+    struct cond_expr *cur;
+    int s[COND_EXPR_MAXDEPTH];
+    int sp = -1;
+
+    for (cur = expr; cur != NULL; cur = cur->next) {
+        switch (cur->expr_type) {
+        case COND_BOOL:
+            if (sp == (COND_EXPR_MAXDEPTH - 1))
+                return -1;
+            sp++;
+            s[sp] = p->bool_val_to_struct[cur->bool - 1]->state;
+            break;
+        case COND_NOT:
+            if (sp < 0)
+                return -1;
+            s[sp] = !s[sp];
+            break;
+        case COND_OR:
+            if (sp < 1)
+                return -1;
+            sp--;
+            s[sp] |= s[sp + 1];
+            break;
+        case COND_AND:
+            if (sp < 1)
+                return -1;
+            sp--;
+            s[sp] &= s[sp + 1];
+            break;
+        case COND_XOR:
+            if (sp < 1)
+                return -1;
+            sp--;
+            s[sp] ^= s[sp + 1];
+            break;
+        case COND_EQ:
+            if (sp < 1)
+                return -1;
+            sp--;
+            s[sp] = (s[sp] == s[sp + 1]);
+            break;
+        case COND_NEQ:
+            if (sp < 1)
+                return -1;
+            sp--;
+            s[sp] = (s[sp] != s[sp + 1]);
+            break;
+        default:
+            return -1;
+        }
+    }
+    return s[0];
+}
+
+/*
+ * evaluate_cond_node evaluates the conditional stored in
+ * a struct cond_node and if the result is different than the
+ * current state of the node it sets the rules in the true/false
+ * list appropriately. If the result of the expression is undefined
+ * all of the rules are disabled for safety.
+ */
+int evaluate_cond_node(struct policydb *p, struct cond_node *node)
+{
+    int new_state;
+    struct cond_av_list* cur;
+
+    new_state = cond_evaluate_expr(p, node->expr);
+    if (new_state != node->cur_state) {
+        node->cur_state = new_state;
+        if (new_state == -1)
+            printk(KERN_ERR "security: expression result was undefined - disabling all rules.\n");
+        /* turn the rules on or off */
+        for (cur = node->true_list; cur != NULL; cur = cur->next) {
+            if (new_state <= 0) {
+                cur->node->key.specified &= ~AVTAB_ENABLED;
+            } else {
+                cur->node->key.specified |= AVTAB_ENABLED;
+            }
+        }
+
+        for (cur = node->false_list; cur != NULL; cur = cur->next) {
+            /* -1 or 1 */
+            if (new_state) {
+                cur->node->key.specified &= ~AVTAB_ENABLED;
+            } else {
+                cur->node->key.specified |= AVTAB_ENABLED;
+            }
+        }
+    }
+    return 0;
+}
+
+int cond_policydb_init(struct policydb *p)
+{
+    p->bool_val_to_struct = NULL;
+    p->cond_list = NULL;
+    if (avtab_init(&p->te_cond_avtab))
+        return -1;
+
+    return 0;
+}
+
+static void cond_av_list_destroy(struct cond_av_list *list)
+{
+    struct cond_av_list *cur, *next;
+    for (cur = list; cur != NULL; cur = next) {
+        next = cur->next;
+        /* the avtab_ptr_t node is destroy by the avtab */
+        xfree(cur);
+    }
+}
+
+static void cond_node_destroy(struct cond_node *node)
+{
+    struct cond_expr *cur_expr, *next_expr;
+
+    for (cur_expr = node->expr; cur_expr != NULL; cur_expr = next_expr) {
+        next_expr = cur_expr->next;
+        xfree(cur_expr);
+    }
+    cond_av_list_destroy(node->true_list);
+    cond_av_list_destroy(node->false_list);
+    xfree(node);
+}
+
+static void cond_list_destroy(struct cond_node *list)
+{
+    struct cond_node *next, *cur;
+
+    if (list == NULL)
+        return;
+
+    for (cur = list; cur != NULL; cur = next) {
+        next = cur->next;
+        cond_node_destroy(cur);
+    }
+}
+
+void cond_policydb_destroy(struct policydb *p)
+{
+    xfree(p->bool_val_to_struct);
+    avtab_destroy(&p->te_cond_avtab);
+    cond_list_destroy(p->cond_list);
+}
+
+int cond_init_bool_indexes(struct policydb *p)
+{
+    xfree(p->bool_val_to_struct);
+    p->bool_val_to_struct = (struct cond_bool_datum**)
+        xmalloc_array(struct cond_bool_datum*, p->p_bools.nprim);
+    if (!p->bool_val_to_struct)
+        return -1;
+    return 0;
+}
+
+int cond_destroy_bool(void *key, void *datum, void *p)
+{
+    xfree(key);
+    xfree(datum);
+    return 0;
+}
+
+int cond_index_bool(void *key, void *datum, void *datap)
+{
+    struct policydb *p;
+    struct cond_bool_datum *booldatum;
+
+    booldatum = datum;
+    p = datap;
+
+    if (!booldatum->value || booldatum->value > p->p_bools.nprim)
+        return -EINVAL;
+
+    p->p_bool_val_to_name[booldatum->value - 1] = key;
+    p->bool_val_to_struct[booldatum->value -1] = booldatum;
+
+    return 0;
+}
+
+static int bool_isvalid(struct cond_bool_datum *b)
+{
+    if (!(b->state == 0 || b->state == 1))
+        return 0;
+    return 1;
+}
+
+int cond_read_bool(struct policydb *p, struct hashtab *h, void *fp)
+{
+    char *key = NULL;
+    struct cond_bool_datum *booldatum;
+    __le32 buf[3];
+    u32 len;
+    int rc;
+
+    booldatum = xmalloc(struct cond_bool_datum);
+    if (!booldatum)
+        return -1;
+    memset(booldatum, 0, sizeof(struct cond_bool_datum));
+
+    rc = next_entry(buf, fp, sizeof buf);
+    if (rc < 0)
+        goto err;
+
+    booldatum->value = le32_to_cpu(buf[0]);
+    booldatum->state = le32_to_cpu(buf[1]);
+
+    if (!bool_isvalid(booldatum))
+        goto err;
+
+    len = le32_to_cpu(buf[2]);
+
+    key = xmalloc_array(char, len + 1);
+    if (!key)
+        goto err;
+    rc = next_entry(key, fp, len);
+    if (rc < 0)
+        goto err;
+    key[len] = 0;
+    if (hashtab_insert(h, key, booldatum))
+        goto err;
+
+    return 0;
+err:
+    cond_destroy_bool(key, booldatum, NULL);
+    return -1;
+}
+
+struct cond_insertf_data
+{
+    struct policydb *p;
+    struct cond_av_list *other;
+    struct cond_av_list *head;
+    struct cond_av_list *tail;
+};
+
+static int cond_insertf(struct avtab *a, struct avtab_key *k, struct avtab_datum *d, void *ptr)
+{
+    struct cond_insertf_data *data = ptr;
+    struct policydb *p = data->p;
+    struct cond_av_list *other = data->other, *list, *cur;
+    struct avtab_node *node_ptr;
+    u8 found;
+
+
+    /*
+     * For type rules we have to make certain there aren't any
+     * conflicting rules by searching the te_avtab and the
+     * cond_te_avtab.
+     */
+    if (k->specified & AVTAB_TYPE) {
+        if (avtab_search(&p->te_avtab, k)) {
+            printk("security: type rule already exists outside of a conditional.");
+            goto err;
+        }
+        /*
+         * If we are reading the false list other will be a pointer to
+         * the true list. We can have duplicate entries if there is only
+         * 1 other entry and it is in our true list.
+         *
+         * If we are reading the true list (other == NULL) there shouldn't
+         * be any other entries.
+         */
+        if (other) {
+            node_ptr = avtab_search_node(&p->te_cond_avtab, k);
+            if (node_ptr) {
+                if (avtab_search_node_next(node_ptr, k->specified)) {
+                    printk("security: too many conflicting type rules.");
+                    goto err;
+                }
+                found = 0;
+                for (cur = other; cur != NULL; cur = cur->next) {
+                    if (cur->node == node_ptr) {
+                        found = 1;
+                        break;
+                    }
+                }
+                if (!found) {
+                    printk("security: conflicting type rules.\n");
+                    goto err;
+                }
+            }
+        } else {
+            if (avtab_search(&p->te_cond_avtab, k)) {
+                printk("security: conflicting type rules when adding type rule for true.\n");
+                goto err;
+            }
+        }
+    }
+
+    node_ptr = avtab_insert_nonunique(&p->te_cond_avtab, k, d);
+    if (!node_ptr) {
+        printk("security: could not insert rule.");
+        goto err;
+    }
+
+    list = xmalloc(struct cond_av_list);
+    if (!list)
+        goto err;
+    memset(list, 0, sizeof(*list));
+
+    list->node = node_ptr;
+    if (!data->head)
+        data->head = list;
+    else
+        data->tail->next = list;
+    data->tail = list;
+    return 0;
+
+err:
+    cond_av_list_destroy(data->head);
+    data->head = NULL;
+    return -1;
+}
+
+static int cond_read_av_list(struct policydb *p, void *fp, struct cond_av_list **ret_list, struct cond_av_list *other)
+{
+    int i, rc;
+    __le32 buf[1];
+    u32 len;
+    struct cond_insertf_data data;
+
+    *ret_list = NULL;
+
+    len = 0;
+    rc = next_entry(buf, fp, sizeof(u32));
+    if (rc < 0)
+        return -1;
+
+    len = le32_to_cpu(buf[0]);
+    if (len == 0) {
+        return 0;
+    }
+
+    data.p = p;
+    data.other = other;
+    data.head = NULL;
+    data.tail = NULL;
+    for (i = 0; i < len; i++) {
+        rc = avtab_read_item(fp, p->policyvers, &p->te_cond_avtab, cond_insertf, &data);
+        if (rc)
+            return rc;
+
+    }
+
+    *ret_list = data.head;
+    return 0;
+}
+
+static int expr_isvalid(struct policydb *p, struct cond_expr *expr)
+{
+    if (expr->expr_type <= 0 || expr->expr_type > COND_LAST) {
+        printk("security: conditional expressions uses unknown operator.\n");
+        return 0;
+    }
+
+    if (expr->bool > p->p_bools.nprim) {
+        printk("security: conditional expressions uses unknown bool.\n");
+        return 0;
+    }
+    return 1;
+}
+
+static int cond_read_node(struct policydb *p, struct cond_node *node, void *fp)
+{
+    __le32 buf[2];
+    u32 len, i;
+    int rc;
+    struct cond_expr *expr = NULL, *last = NULL;
+
+    rc = next_entry(buf, fp, sizeof(u32));
+    if (rc < 0)
+        return -1;
+
+    node->cur_state = le32_to_cpu(buf[0]);
+
+    len = 0;
+    rc = next_entry(buf, fp, sizeof(u32));
+    if (rc < 0)
+        return -1;
+
+    /* expr */
+    len = le32_to_cpu(buf[0]);
+
+    for (i = 0; i < len; i++ ) {
+        rc = next_entry(buf, fp, sizeof(u32) * 2);
+        if (rc < 0)
+            goto err;
+
+        expr = xmalloc(struct cond_expr);
+        if (!expr) {
+            goto err;
+        }
+        memset(expr, 0, sizeof(struct cond_expr));
+
+        expr->expr_type = le32_to_cpu(buf[0]);
+        expr->bool = le32_to_cpu(buf[1]);
+
+        if (!expr_isvalid(p, expr)) {
+            xfree(expr);
+            goto err;
+        }
+
+        if (i == 0) {
+            node->expr = expr;
+        } else {
+            last->next = expr;
+        }
+        last = expr;
+    }
+
+    if (cond_read_av_list(p, fp, &node->true_list, NULL) != 0)
+        goto err;
+    if (cond_read_av_list(p, fp, &node->false_list, node->true_list) != 0)
+        goto err;
+    return 0;
+err:
+    cond_node_destroy(node);
+    return -1;
+}
+
+int cond_read_list(struct policydb *p, void *fp)
+{
+    struct cond_node *node, *last = NULL;
+    __le32 buf[1];
+    u32 i, len;
+    int rc;
+
+    rc = next_entry(buf, fp, sizeof buf);
+    if (rc < 0)
+        return -1;
+
+    len = le32_to_cpu(buf[0]);
+
+    for (i = 0; i < len; i++) {
+        node = xmalloc(struct cond_node);
+        if (!node)
+            goto err;
+        memset(node, 0, sizeof(struct cond_node));
+
+        if (cond_read_node(p, node, fp) != 0)
+            goto err;
+
+        if (i == 0) {
+            p->cond_list = node;
+        } else {
+            last->next = node;
+        }
+        last = node;
+    }
+    return 0;
+err:
+    cond_list_destroy(p->cond_list);
+    p->cond_list = NULL;
+    return -1;
+}
+
+/* Determine whether additional permissions are granted by the conditional
+ * av table, and if so, add them to the result
+ */
+void cond_compute_av(struct avtab *ctab, struct avtab_key *key, struct av_decision *avd)
+{
+    struct avtab_node *node;
+
+    if(!ctab || !key || !avd)
+        return;
+
+    for(node = avtab_search_node(ctab, key); node != NULL;
+                node = avtab_search_node_next(node, key->specified)) {
+        if ( (u16) (AVTAB_ALLOWED|AVTAB_ENABLED) ==
+             (node->key.specified & (AVTAB_ALLOWED|AVTAB_ENABLED)))
+            avd->allowed |= node->datum.data;
+        if ( (u16) (AVTAB_AUDITDENY|AVTAB_ENABLED) ==
+             (node->key.specified & (AVTAB_AUDITDENY|AVTAB_ENABLED)))
+            /* Since a '0' in an auditdeny mask represents a
+             * permission we do NOT want to audit (dontaudit), we use
+             * the '&' operand to ensure that all '0's in the mask
+             * are retained (much unlike the allow and auditallow cases).
+             */
+            avd->auditdeny &= node->datum.data;
+        if ( (u16) (AVTAB_AUDITALLOW|AVTAB_ENABLED) ==
+             (node->key.specified & (AVTAB_AUDITALLOW|AVTAB_ENABLED)))
+            avd->auditallow |= node->datum.data;
+    }
+    return;
+}
diff -r 62b752969edf -r 2b79cd115561 xen/xsm/flask/ss/conditional.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/ss/conditional.h	Mon May 07 14:51:17 2007 -0400
@@ -0,0 +1,77 @@
+/* Authors: Karl MacMillan <kmacmillan@tresys.com>
+ *          Frank Mayer <mayerf@tresys.com>
+ *
+ * Copyright (C) 2003 - 2004 Tresys Technology, LLC
+ *    This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation, version 2.
+ */
+
+#ifndef _CONDITIONAL_H_
+#define _CONDITIONAL_H_
+
+#include "avtab.h"
+#include "symtab.h"
+#include "policydb.h"
+
+#define COND_EXPR_MAXDEPTH 10
+
+/*
+ * A conditional expression is a list of operators and operands
+ * in reverse polish notation.
+ */
+struct cond_expr {
+#define COND_BOOL    1 /* plain bool */
+#define COND_NOT    2 /* !bool */
+#define COND_OR        3 /* bool || bool */
+#define COND_AND    4 /* bool && bool */
+#define COND_XOR    5 /* bool ^ bool */
+#define COND_EQ        6 /* bool == bool */
+#define COND_NEQ    7 /* bool != bool */
+#define COND_LAST    8
+    __u32 expr_type;
+    __u32 bool;
+    struct cond_expr *next;
+};
+
+/*
+ * Each cond_node contains a list of rules to be enabled/disabled
+ * depending on the current value of the conditional expression. This
+ * struct is for that list.
+ */
+struct cond_av_list {
+    struct avtab_node *node;
+    struct cond_av_list *next;
+};
+
+/*
+ * A cond node represents a conditional block in a policy. It
+ * contains a conditional expression, the current state of the expression,
+ * two lists of rules to enable/disable depending on the value of the
+ * expression (the true list corresponds to if and the false list corresponds
+ * to else)..
+ */
+struct cond_node {
+    int cur_state;
+    struct cond_expr *expr;
+    struct cond_av_list *true_list;
+    struct cond_av_list *false_list;
+    struct cond_node *next;
+};
+
+int cond_policydb_init(struct policydb* p);
+void cond_policydb_destroy(struct policydb* p);
+
+int cond_init_bool_indexes(struct policydb* p);
+int cond_destroy_bool(void *key, void *datum, void *p);
+
+int cond_index_bool(void *key, void *datum, void *datap);
+
+int cond_read_bool(struct policydb *p, struct hashtab *h, void *fp);
+int cond_read_list(struct policydb *p, void *fp);
+
+void cond_compute_av(struct avtab *ctab, struct avtab_key *key, struct av_decision *avd);
+
+int evaluate_cond_node(struct policydb *p, struct cond_node *node);
+
+#endif /* _CONDITIONAL_H_ */
diff -r 62b752969edf -r 2b79cd115561 xen/xsm/flask/ss/constraint.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/ss/constraint.h	Mon May 07 14:51:17 2007 -0400
@@ -0,0 +1,61 @@
+/*
+ * A constraint is a condition that must be satisfied in
+ * order for one or more permissions to be granted.
+ * Constraints are used to impose additional restrictions
+ * beyond the type-based rules in `te' or the role-based
+ * transition rules in `rbac'.  Constraints are typically
+ * used to prevent a process from transitioning to a new user
+ * identity or role unless it is in a privileged type.
+ * Constraints are likewise typically used to prevent a
+ * process from labeling an object with a different user
+ * identity.
+ *
+ * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
+ */
+#ifndef _SS_CONSTRAINT_H_
+#define _SS_CONSTRAINT_H_
+
+#include "ebitmap.h"
+
+#define CEXPR_MAXDEPTH 5
+
+struct constraint_expr {
+#define CEXPR_NOT        1 /* not expr */
+#define CEXPR_AND        2 /* expr and expr */
+#define CEXPR_OR        3 /* expr or expr */
+#define CEXPR_ATTR        4 /* attr op attr */
+#define CEXPR_NAMES        5 /* attr op names */
+    u32 expr_type;        /* expression type */
+
+#define CEXPR_USER 1        /* user */
+#define CEXPR_ROLE 2        /* role */
+#define CEXPR_TYPE 4        /* type */
+#define CEXPR_TARGET 8        /* target if set, source otherwise */
+#define CEXPR_XTARGET 16    /* special 3rd target for validatetrans rule */
+#define CEXPR_L1L2 32        /* low level 1 vs. low level 2 */
+#define CEXPR_L1H2 64        /* low level 1 vs. high level 2 */
+#define CEXPR_H1L2 128        /* high level 1 vs. low level 2 */
+#define CEXPR_H1H2 256        /* high level 1 vs. high level 2 */
+#define CEXPR_L1H1 512        /* low level 1 vs. high level 1 */
+#define CEXPR_L2H2 1024        /* low level 2 vs. high level 2 */
+    u32 attr;        /* attribute */
+
+#define CEXPR_EQ     1        /* == or eq */
+#define CEXPR_NEQ    2        /* != */
+#define CEXPR_DOM    3        /* dom */
+#define CEXPR_DOMBY  4        /* domby  */
+#define CEXPR_INCOMP 5        /* incomp */
+    u32 op;            /* operator */
+
+    struct ebitmap names;    /* names */
+
+    struct constraint_expr *next;   /* next expression */
+};
+
+struct constraint_node {
+    u32 permissions;    /* constrained permissions */
+    struct constraint_expr *expr;    /* constraint on permissions */
+    struct constraint_node *next;    /* next constraint */
+};
+
+#endif    /* _SS_CONSTRAINT_H_ */
diff -r 62b752969edf -r 2b79cd115561 xen/xsm/flask/ss/context.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/ss/context.h	Mon May 07 14:51:17 2007 -0400
@@ -0,0 +1,110 @@
+/*
+ * A security context is a set of security attributes
+ * associated with each subject and object controlled
+ * by the security policy.  Security contexts are
+ * externally represented as variable-length strings
+ * that can be interpreted by a user or application
+ * with an understanding of the security policy.
+ * Internally, the security server uses a simple
+ * structure.  This structure is private to the
+ * security server and can be changed without affecting
+ * clients of the security server.
+ *
+ * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
+ */
+ 
+/* Ported to Xen 3.0, George Coker, <gscoker@alpha.ncsc.mil> */
+ 
+#ifndef _SS_CONTEXT_H_
+#define _SS_CONTEXT_H_
+
+#include "ebitmap.h"
+#include "mls_types.h"
+#include "security.h"
+
+/*
+ * A security context consists of an authenticated user
+ * identity, a role, a type and a MLS range.
+ */
+struct context {
+    u32 user;
+    u32 role;
+    u32 type;
+    struct mls_range range;
+};
+
+static inline void mls_context_init(struct context *c)
+{
+    memset(&c->range, 0, sizeof(c->range));
+}
+
+static inline int mls_context_cpy(struct context *dst, struct context *src)
+{
+    int rc;
+
+    if (!flask_mls_enabled)
+        return 0;
+
+    dst->range.level[0].sens = src->range.level[0].sens;
+    rc = ebitmap_cpy(&dst->range.level[0].cat, &src->range.level[0].cat);
+    if (rc)
+        goto out;
+
+    dst->range.level[1].sens = src->range.level[1].sens;
+    rc = ebitmap_cpy(&dst->range.level[1].cat, &src->range.level[1].cat);
+    if (rc)
+        ebitmap_destroy(&dst->range.level[0].cat);
+out:
+    return rc;
+}
+
+static inline int mls_context_cmp(struct context *c1, struct context *c2)
+{
+    if (!flask_mls_enabled)
+        return 1;
+
+    return ((c1->range.level[0].sens == c2->range.level[0].sens) &&
+        ebitmap_cmp(&c1->range.level[0].cat,&c2->range.level[0].cat) &&
+        (c1->range.level[1].sens == c2->range.level[1].sens) &&
+        ebitmap_cmp(&c1->range.level[1].cat,&c2->range.level[1].cat));
+}
+
+static inline void mls_context_destroy(struct context *c)
+{
+    if (!flask_mls_enabled)
+        return;
+
+    ebitmap_destroy(&c->range.level[0].cat);
+    ebitmap_destroy(&c->range.level[1].cat);
+    mls_context_init(c);
+}
+
+static inline void context_init(struct context *c)
+{
+    memset(c, 0, sizeof(*c));
+}
+
+static inline int context_cpy(struct context *dst, struct context *src)
+{
+    dst->user = src->user;
+    dst->role = src->role;
+    dst->type = src->type;
+    return mls_context_cpy(dst, src);
+}
+
+static inline void context_destroy(struct context *c)
+{
+    c->user = c->role = c->type = 0;
+    mls_context_destroy(c);
+}
+
+static inline int context_cmp(struct context *c1, struct context *c2)
+{
+    return ((c1->user == c2->user) &&
+        (c1->role == c2->role) &&
+        (c1->type == c2->type) &&
+        mls_context_cmp(c1, c2));
+}
+
+#endif    /* _SS_CONTEXT_H_ */
+
diff -r 62b752969edf -r 2b79cd115561 xen/xsm/flask/ss/ebitmap.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/ss/ebitmap.c	Mon May 07 14:51:17 2007 -0400
@@ -0,0 +1,299 @@
+/*
+ * Implementation of the extensible bitmap type.
+ *
+ * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
+ */
+
+/* Ported to Xen 3.0, George Coker, <gscoker@alpha.ncsc.mil> */
+
+#include <asm/byteorder.h>
+#include <xen/lib.h>
+#include <xen/xmalloc.h>
+#include <xen/errno.h>
+#include <xen/spinlock.h>
+#include "ebitmap.h"
+#include "policydb.h"
+
+int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2)
+{
+    struct ebitmap_node *n1, *n2;
+
+    if (e1->highbit != e2->highbit)
+        return 0;
+
+    n1 = e1->node;
+    n2 = e2->node;
+    while (n1 && n2 &&
+           (n1->startbit == n2->startbit) &&
+           (n1->map == n2->map)) {
+        n1 = n1->next;
+        n2 = n2->next;
+    }
+
+    if (n1 || n2)
+        return 0;
+
+    return 1;
+}
+
+int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src)
+{
+    struct ebitmap_node *n, *new, *prev;
+
+    ebitmap_init(dst);
+    n = src->node;
+    prev = NULL;
+    while (n) {
+        new = xmalloc(struct ebitmap_node);
+        if (!new) {
+            ebitmap_destroy(dst);
+            return -ENOMEM;
+        }
+        memset(new, 0, sizeof(*new));
+        new->startbit = n->startbit;
+        new->map = n->map;
+        new->next = NULL;
+        if (prev)
+            prev->next = new;
+        else
+            dst->node = new;
+        prev = new;
+        n = n->next;
+    }
+
+    dst->highbit = src->highbit;
+    return 0;
+}
+
+int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2)
+{
+    struct ebitmap_node *n1, *n2;
+
+    if (e1->highbit < e2->highbit)
+        return 0;
+
+    n1 = e1->node;
+    n2 = e2->node;
+    while (n1 && n2 && (n1->startbit <= n2->startbit)) {
+        if (n1->startbit < n2->startbit) {
+            n1 = n1->next;
+            continue;
+        }
+        if ((n1->map & n2->map) != n2->map)
+            return 0;
+
+        n1 = n1->next;
+        n2 = n2->next;
+    }
+
+    if (n2)
+        return 0;
+
+    return 1;
+}
+
+int ebitmap_get_bit(struct ebitmap *e, unsigned long bit)
+{
+    struct ebitmap_node *n;
+
+    if (e->highbit < bit)
+        return 0;
+
+    n = e->node;
+    while (n && (n->startbit <= bit)) {
+        if ((n->startbit + MAPSIZE) > bit) {
+            if (n->map & (MAPBIT << (bit - n->startbit)))
+                return 1;
+            else
+                return 0;
+        }
+        n = n->next;
+    }
+
+    return 0;
+}
+
+int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value)
+{
+    struct ebitmap_node *n, *prev, *new;
+
+    prev = NULL;
+    n = e->node;
+    while (n && n->startbit <= bit) {
+        if ((n->startbit + MAPSIZE) > bit) {
+            if (value) {
+                n->map |= (MAPBIT << (bit - n->startbit));
+            } else {
+                n->map &= ~(MAPBIT << (bit - n->startbit));
+                if (!n->map) {
+                    /* drop this node from the bitmap */
+
+                    if (!n->next) {
+                        /*
+                         * this was the highest map
+                         * within the bitmap
+                         */
+                        if (prev)
+                            e->highbit = prev->startbit + MAPSIZE;
+                        else
+                            e->highbit = 0;
+                    }
+                    if (prev)
+                        prev->next = n->next;
+                    else
+                        e->node = n->next;
+
+                    xfree(n);
+                }
+            }
+            return 0;
+        }
+        prev = n;
+        n = n->next;
+    }
+
+    if (!value)
+        return 0;
+
+    new = xmalloc(struct ebitmap_node);
+    if (!new)
+        return -ENOMEM;
+    memset(new, 0, sizeof(*new));
+
+    new->startbit = bit & ~(MAPSIZE - 1);
+    new->map = (MAPBIT << (bit - new->startbit));
+
+    if (!n)
+        /* this node will be the highest map within the bitmap */
+        e->highbit = new->startbit + MAPSIZE;
+
+    if (prev) {
+        new->next = prev->next;
+        prev->next = new;
+    } else {
+        new->next = e->node;
+        e->node = new;
+    }
+
+    return 0;
+}
+
+void ebitmap_destroy(struct ebitmap *e)
+{
+    struct ebitmap_node *n, *temp;
+
+    if (!e)
+        return;
+
+    n = e->node;
+    while (n) {
+        temp = n;
+        n = n->next;
+        xfree(temp);
+    }
+
+    e->highbit = 0;
+    e->node = NULL;
+    return;
+}
+
+int ebitmap_read(struct ebitmap *e, void *fp)
+{
+    int rc;
+    struct ebitmap_node *n, *l;
+    __le32 buf[3];
+    u32 mapsize, count, i;
+    __le64 map;
+
+    ebitmap_init(e);
+
+    rc = next_entry(buf, fp, sizeof buf);
+    if (rc < 0)
+        goto out;
+
+    mapsize = le32_to_cpu(buf[0]);
+    e->highbit = le32_to_cpu(buf[1]);
+    count = le32_to_cpu(buf[2]);
+
+    if (mapsize != MAPSIZE) {
+        printk(KERN_ERR "security: ebitmap: map size %u does not "
+               "match my size %Zd (high bit was %d)\n", mapsize,
+               MAPSIZE, e->highbit);
+        goto bad;
+    }
+    if (!e->highbit) {
+        e->node = NULL;
+        goto ok;
+    }
+    if (e->highbit & (MAPSIZE - 1)) {
+        printk(KERN_ERR "security: ebitmap: high bit (%d) is not a "
+               "multiple of the map size (%Zd)\n", e->highbit, MAPSIZE);
+        goto bad;
+    }
+    l = NULL;
+    for (i = 0; i < count; i++) {
+        rc = next_entry(buf, fp, sizeof(u32));
+        if (rc < 0) {
+            printk(KERN_ERR "security: ebitmap: truncated map\n");
+            goto bad;
+        }
+        n = xmalloc(struct ebitmap_node);
+        if (!n) {
+            printk(KERN_ERR "security: ebitmap: out of memory\n");
+            rc = -ENOMEM;
+            goto bad;
+        }
+        memset(n, 0, sizeof(*n));
+
+        n->startbit = le32_to_cpu(buf[0]);
+
+        if (n->startbit & (MAPSIZE - 1)) {
+            printk(KERN_ERR "security: ebitmap start bit (%d) is "
+                   "not a multiple of the map size (%Zd)\n",
+                   n->startbit, MAPSIZE);
+            goto bad_free;
+        }
+        if (n->startbit > (e->highbit - MAPSIZE)) {
+            printk(KERN_ERR "security: ebitmap start bit (%d) is "
+                   "beyond the end of the bitmap (%Zd)\n",
+                   n->startbit, (e->highbit - MAPSIZE));
+            goto bad_free;
+        }
+        rc = next_entry(&map, fp, sizeof(u64));
+        if (rc < 0) {
+            printk(KERN_ERR "security: ebitmap: truncated map\n");
+            goto bad_free;
+        }
+        n->map = le64_to_cpu(map);
+
+        if (!n->map) {
+            printk(KERN_ERR "security: ebitmap: null map in "
+                   "ebitmap (startbit %d)\n", n->startbit);
+            goto bad_free;
+        }
+        if (l) {
+            if (n->startbit <= l->startbit) {
+                printk(KERN_ERR "security: ebitmap: start "
+                       "bit %d comes after start bit %d\n",
+                       n->startbit, l->startbit);
+                goto bad_free;
+            }
+            l->next = n;
+        } else
+            e->node = n;
+
+        l = n;
+    }
+
+ok:
+    rc = 0;
+out:
+    return rc;
+bad_free:
+    xfree(n);
+bad:
+    if (!rc)
+        rc = -EINVAL;
+    ebitmap_destroy(e);
+    goto out;
+}
diff -r 62b752969edf -r 2b79cd115561 xen/xsm/flask/ss/ebitmap.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/ss/ebitmap.h	Mon May 07 14:51:17 2007 -0400
@@ -0,0 +1,78 @@
+/*
+ * An extensible bitmap is a bitmap that supports an
+ * arbitrary number of bits.  Extensible bitmaps are
+ * used to represent sets of values, such as types,
+ * roles, categories, and classes.
+ *
+ * Each extensible bitmap is implemented as a linked
+ * list of bitmap nodes, where each bitmap node has
+ * an explicitly specified starting bit position within
+ * the total bitmap.
+ *
+ * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
+ */
+#ifndef _SS_EBITMAP_H_
+#define _SS_EBITMAP_H_
+
+#define MAPTYPE u64            /* portion of bitmap in each node */
+#define MAPSIZE (sizeof(MAPTYPE) * 8)    /* number of bits in node bitmap */
+#define MAPBIT  1ULL            /* a bit in the node bitmap */
+
+struct ebitmap_node {
+    u32 startbit;        /* starting position in the total bitmap */
+    MAPTYPE map;        /* this node's portion of the bitmap */
+    struct ebitmap_node *next;
+};
+
+struct ebitmap {
+    struct ebitmap_node *node;    /* first node in the bitmap */
+    u32 highbit;    /* highest position in the total bitmap */
+};
+
+#define ebitmap_length(e) ((e)->highbit)
+#define ebitmap_startbit(e) ((e)->node ? (e)->node->startbit : 0)
+
+static inline unsigned int ebitmap_start(struct ebitmap *e,
+                     struct ebitmap_node **n)
+{
+    *n = e->node;
+    return ebitmap_startbit(e);
+}
+
+static inline void ebitmap_init(struct ebitmap *e)
+{
+    memset(e, 0, sizeof(*e));
+}
+
+static inline unsigned int ebitmap_next(struct ebitmap_node **n,
+                    unsigned int bit)
+{
+    if ((bit == ((*n)->startbit + MAPSIZE - 1)) &&
+        (*n)->next) {
+        *n = (*n)->next;
+        return (*n)->startbit;
+    }
+
+    return (bit+1);
+}
+
+static inline int ebitmap_node_get_bit(struct ebitmap_node * n,
+                       unsigned int bit)
+{
+    if (n->map & (MAPBIT << (bit - n->startbit)))
+        return 1;
+    return 0;
+}
+
+#define ebitmap_for_each_bit(e, n, bit) \
+    for (bit = ebitmap_start(e, &n); bit < ebitmap_length(e); bit = ebitmap_next(&n, bit)) \
+
+int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2);
+int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src);
+int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2);
+int ebitmap_get_bit(struct ebitmap *e, unsigned long bit);
+int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value);
+void ebitmap_destroy(struct ebitmap *e);
+int ebitmap_read(struct ebitmap *e, void *fp);
+
+#endif    /* _SS_EBITMAP_H_ */
diff -r 62b752969edf -r 2b79cd115561 xen/xsm/flask/ss/hashtab.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/ss/hashtab.c	Mon May 07 14:51:17 2007 -0400
@@ -0,0 +1,170 @@
+/*
+ * Implementation of the hash table type.
+ *
+ * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
+ */
+
+/* Ported to Xen 3.0, George Coker, <gscoker@alpha.ncsc.mil> */
+
+#include <xen/lib.h>
+#include <xen/xmalloc.h>
+#include <xen/errno.h>
+#include "hashtab.h"
+
+struct hashtab *hashtab_create(u32 (*hash_value)(struct hashtab *h, void *key),
+                               int (*keycmp)(struct hashtab *h, void *key1, void *key2),
+                               u32 size)
+{
+    struct hashtab *p;
+    u32 i;
+
+    p = xmalloc(struct hashtab);
+    if (p == NULL)
+        return p;
+
+    memset(p, 0, sizeof(*p));
+    p->size = size;
+    p->nel = 0;
+    p->hash_value = hash_value;
+    p->keycmp = keycmp;
+    p->htable = (void *)xmalloc_array(struct hashtab_node, size);
+    if (p->htable == NULL) {
+        xfree(p);
+        return NULL;
+    }
+
+    for (i = 0; i < size; i++)
+        p->htable[i] = NULL;
+
+    return p;
+}
+
+int hashtab_insert(struct hashtab *h, void *key, void *datum)
+{
+    u32 hvalue;
+    struct hashtab_node *prev, *cur, *newnode;
+
+    if (!h || h->nel == HASHTAB_MAX_NODES)
+        return -EINVAL;
+
+    hvalue = h->hash_value(h, key);
+    prev = NULL;
+    cur = h->htable[hvalue];
+    while (cur && h->keycmp(h, key, cur->key) > 0) {
+        prev = cur;
+        cur = cur->next;
+    }
+
+    if (cur && (h->keycmp(h, key, cur->key) == 0))
+        return -EEXIST;
+
+    newnode = xmalloc(struct hashtab_node);
+    if (newnode == NULL)
+        return -ENOMEM;
+    memset(newnode, 0, sizeof(*newnode));
+    newnode->key = key;
+    newnode->datum = datum;
+    if (prev) {
+        newnode->next = prev->next;
+        prev->next = newnode;
+    } else {
+        newnode->next = h->htable[hvalue];
+        h->htable[hvalue] = newnode;
+    }
+
+    h->nel++;
+    return 0;
+}
+
+void *hashtab_search(struct hashtab *h, void *key)
+{
+    u32 hvalue;
+    struct hashtab_node *cur;
+
+    if (!h)
+        return NULL;
+
+    hvalue = h->hash_value(h, key);
+    cur = h->htable[hvalue];
+    while (cur != NULL && h->keycmp(h, key, cur->key) > 0)
+        cur = cur->next;
+
+    if (cur == NULL || (h->keycmp(h, key, cur->key) != 0))
+        return NULL;
+
+    return cur->datum;
+}
+
+void hashtab_destroy(struct hashtab *h)
+{
+    u32 i;
+    struct hashtab_node *cur, *temp;
+
+    if (!h)
+        return;
+
+    for (i = 0; i < h->size; i++) {
+        cur = h->htable[i];
+        while (cur != NULL) {
+            temp = cur;
+            cur = cur->next;
+            xfree(temp);
+        }
+        h->htable[i] = NULL;
+    }
+
+    xfree(h->htable);
+    h->htable = NULL;
+
+    xfree(h);
+}
+
+int hashtab_map(struct hashtab *h,
+        int (*apply)(void *k, void *d, void *args),
+        void *args)
+{
+    u32 i;
+    int ret;
+    struct hashtab_node *cur;
+
+    if (!h)
+        return 0;
+
+    for (i = 0; i < h->size; i++) {
+        cur = h->htable[i];
+        while (cur != NULL) {
+            ret = apply(cur->key, cur->datum, args);
+            if (ret)
+                return ret;
+            cur = cur->next;
+        }
+    }
+    return 0;
+}
+
+
+void hashtab_stat(struct hashtab *h, struct hashtab_info *info)
+{
+    u32 i, chain_len, slots_used, max_chain_len;
+    struct hashtab_node *cur;
+
+    slots_used = 0;
+    max_chain_len = 0;
+    for (slots_used = max_chain_len = i = 0; i < h->size; i++) {
+        cur = h->htable[i];
+        if (cur) {
+            slots_used++;
+            chain_len = 0;
+            while (cur) {
+                chain_len++;
+                cur = cur->next;
+            }
+
+            if (chain_len > max_chain_len)
+                max_chain_len = chain_len;
+        }
+    }
+
+    info->slots_used = slots_used;
+    info->max_chain_len = max_chain_len;
+}
diff -r 62b752969edf -r 2b79cd115561 xen/xsm/flask/ss/hashtab.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/ss/hashtab.h	Mon May 07 14:51:17 2007 -0400
@@ -0,0 +1,87 @@
+/*
+ * A hash table (hashtab) maintains associations between
+ * key values and datum values.  The type of the key values
+ * and the type of the datum values is arbitrary.  The
+ * functions for hash computation and key comparison are
+ * provided by the creator of the table.
+ *
+ * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
+ */
+#ifndef _SS_HASHTAB_H_
+#define _SS_HASHTAB_H_
+
+#define HASHTAB_MAX_NODES    0xffffffff
+
+struct hashtab_node {
+    void *key;
+    void *datum;
+    struct hashtab_node *next;
+};
+
+struct hashtab {
+    struct hashtab_node **htable;    /* hash table */
+    u32 size;            /* number of slots in hash table */
+    u32 nel;            /* number of elements in hash table */
+    u32 (*hash_value)(struct hashtab *h, void *key);
+                    /* hash function */
+    int (*keycmp)(struct hashtab *h, void *key1, void *key2);
+                    /* key comparison function */
+};
+
+struct hashtab_info {
+    u32 slots_used;
+    u32 max_chain_len;
+};
+
+/*
+ * Creates a new hash table with the specified characteristics.
+ *
+ * Returns NULL if insufficent space is available or
+ * the new hash table otherwise.
+ */
+struct hashtab *hashtab_create(u32 (*hash_value)(struct hashtab *h, void *key),
+                               int (*keycmp)(struct hashtab *h, void *key1, void *key2),
+                               u32 size);
+
+/*
+ * Inserts the specified (key, datum) pair into the specified hash table.
+ *
+ * Returns -ENOMEM on memory allocation error,
+ * -EEXIST if there is already an entry with the same key,
+ * -EINVAL for general errors or
+ * 0 otherwise.
+ */
+int hashtab_insert(struct hashtab *h, void *k, void *d);
+
+/*
+ * Searches for the entry with the specified key in the hash table.
+ *
+ * Returns NULL if no entry has the specified key or
+ * the datum of the entry otherwise.
+ */
+void *hashtab_search(struct hashtab *h, void *k);
+
+/*
+ * Destroys the specified hash table.
+ */
+void hashtab_destroy(struct hashtab *h);
+
+/*
+ * Applies the specified apply function to (key,datum,args)
+ * for each entry in the specified hash table.
+ *
+ * The order in which the function is applied to the entries
+ * is dependent upon the internal structure of the hash table.
+ *
+ * If apply returns a non-zero status, then hashtab_map will cease
+ * iterating through the hash table and will propagate the error
+ * return to its caller.
+ */
+int hashtab_map(struct hashtab *h,
+        int (*apply)(void *k, void *d, void *args),
+        void *args);
+
+/* Fill info with some hash table statistics */
+void hashtab_stat(struct hashtab *h, struct hashtab_info *info);
+
+#endif    /* _SS_HASHTAB_H */
diff -r 62b752969edf -r 2b79cd115561 xen/xsm/flask/ss/mls.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/ss/mls.c	Mon May 07 14:51:17 2007 -0400
@@ -0,0 +1,562 @@
+/*
+ * Implementation of the multi-level security (MLS) policy.
+ *
+ * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
+ */
+/*
+ * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
+ *
+ *    Support for enhanced MLS infrastructure.
+ *
+ * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
+ */
+
+/* Ported to Xen 3.0, George Coker, <gscoker@alpha.ncsc.mil> */
+
+#include <xen/lib.h>
+#include <xen/xmalloc.h>
+#include <xen/string.h>
+#include <xen/errno.h>
+#include "sidtab.h"
+#include "mls.h"
+#include "policydb.h"
+#include "services.h"
+
+/*
+ * Return the length in bytes for the MLS fields of the
+ * security context string representation of `context'.
+ */
+int mls_compute_context_len(struct context * context)
+{
+    int i, l, len, range;
+    struct ebitmap_node *node;
+
+    if (!flask_mls_enabled)
+        return 0;
+
+    len = 1; /* for the beginning ":" */
+    for (l = 0; l < 2; l++) {
+        range = 0;
+        len += strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
+
+        ebitmap_for_each_bit(&context->range.level[l].cat, node, i) {
+            if (ebitmap_node_get_bit(node, i)) {
+                if (range) {
+                    range++;
+                    continue;
+                }
+
+                len += strlen(policydb.p_cat_val_to_name[i]) + 1;
+                range++;
+            } else {
+                if (range > 1)
+                    len += strlen(policydb.p_cat_val_to_name[i - 1]) + 1;
+                range = 0;
+            }
+        }
+        /* Handle case where last category is the end of range */
+        if (range > 1)
+            len += strlen(policydb.p_cat_val_to_name[i - 1]) + 1;
+
+        if (l == 0) {
+            if (mls_level_eq(&context->range.level[0],
+                             &context->range.level[1]))
+                break;
+            else
+                len++;
+        }
+    }
+
+    return len;
+}
+
+/*
+ * Write the security context string representation of
+ * the MLS fields of `context' into the string `*scontext'.
+ * Update `*scontext' to point to the end of the MLS fields.
+ */
+void mls_sid_to_context(struct context *context,
+                        char **scontext)
+{
+    char *scontextp;
+    int i, l, range, wrote_sep;
+    struct ebitmap_node *node;
+
+    if (!flask_mls_enabled)
+        return;
+
+    scontextp = *scontext;
+
+    *scontextp = ':';
+    scontextp++;
+
+    for (l = 0; l < 2; l++) {
+        range = 0;
+        wrote_sep = 0;
+        strlcpy(scontextp,
+                policydb.p_sens_val_to_name[context->range.level[l].sens - 1],
+                strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1]));
+        scontextp += strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
+
+        /* categories */
+        ebitmap_for_each_bit(&context->range.level[l].cat, node, i) {
+            if (ebitmap_node_get_bit(node, i)) {
+                if (range) {
+                    range++;
+                    continue;
+                }
+
+                if (!wrote_sep) {
+                    *scontextp++ = ':';
+                    wrote_sep = 1;
+                } else
+                    *scontextp++ = ',';
+                strlcpy(scontextp, policydb.p_cat_val_to_name[i], 
+                    strlen(policydb.p_cat_val_to_name[i]));
+                scontextp += strlen(policydb.p_cat_val_to_name[i]);
+                range++;
+            } else {
+                if (range > 1) {
+                    if (range > 2)
+                        *scontextp++ = '.';
+                    else
+                        *scontextp++ = ',';
+
+                    strlcpy(scontextp, policydb.p_cat_val_to_name[i - 1],
+                        strlen(policydb.p_cat_val_to_name[i - 1]));
+                    scontextp += strlen(policydb.p_cat_val_to_name[i - 1]);
+                }
+                range = 0;
+            }
+        }
+
+        /* Handle case where last category is the end of range */
+        if (range > 1) {
+            if (range > 2)
+                *scontextp++ = '.';
+            else
+                *scontextp++ = ',';
+
+            strlcpy(scontextp, policydb.p_cat_val_to_name[i - 1],
+                strlen(policydb.p_cat_val_to_name[i - 1]));
+            scontextp += strlen(policydb.p_cat_val_to_name[i - 1]);
+        }
+
+        if (l == 0) {
+            if (mls_level_eq(&context->range.level[0],
+                             &context->range.level[1]))
+                break;
+            else {
+                *scontextp = '-';
+                scontextp++;
+            }
+        }
+    }
+
+    *scontext = scontextp;
+    return;
+}
+
+/*
+ * Return 1 if the MLS fields in the security context
+ * structure `c' are valid.  Return 0 otherwise.
+ */
+int mls_context_isvalid(struct policydb *p, struct context *c)
+{
+    struct level_datum *levdatum;
+    struct user_datum *usrdatum;
+    struct ebitmap_node *node;
+    int i, l;
+
+    if (!flask_mls_enabled)
+        return 1;
+
+    /*
+     * MLS range validity checks: high must dominate low, low level must
+     * be valid (category set <-> sensitivity check), and high level must
+     * be valid (category set <-> sensitivity check)
+     */
+    if (!mls_level_dom(&c->range.level[1], &c->range.level[0]))
+        /* High does not dominate low. */
+        return 0;
+
+    for (l = 0; l < 2; l++) {
+        if (!c->range.level[l].sens || c->range.level[l].sens > p->p_levels.nprim)
+            return 0;
+        levdatum = hashtab_search(p->p_levels.table,
+            p->p_sens_val_to_name[c->range.level[l].sens - 1]);
+        if (!levdatum)
+            return 0;
+
+        ebitmap_for_each_bit(&c->range.level[l].cat, node, i) {
+            if (ebitmap_node_get_bit(node, i)) {
+                if (i > p->p_cats.nprim)
+                    return 0;
+                if (!ebitmap_get_bit(&levdatum->level->cat, i))
+                    /*
+                     * Category may not be associated with
+                     * sensitivity in low level.
+                     */
+                    return 0;
+            }
+        }
+    }
+
+    if (c->role == OBJECT_R_VAL)
+        return 1;
+
+    /*
+     * User must be authorized for the MLS range.
+     */
+    if (!c->user || c->user > p->p_users.nprim)
+        return 0;
+    usrdatum = p->user_val_to_struct[c->user - 1];
+    if (!mls_range_contains(usrdatum->range, c->range))
+        return 0; /* user may not be associated with range */
+
+    return 1;
+}
+
+/*
+ * Copies the MLS range from `src' into `dst'.
+ */
+static inline int mls_copy_context(struct context *dst,
+                   struct context *src)
+{
+    int l, rc = 0;
+
+    /* Copy the MLS range from the source context */
+    for (l = 0; l < 2; l++) {
+        dst->range.level[l].sens = src->range.level[l].sens;
+        rc = ebitmap_cpy(&dst->range.level[l].cat,
+                 &src->range.level[l].cat);
+        if (rc)
+            break;
+    }
+
+    return rc;
+}
+
+/*
+ * Set the MLS fields in the security context structure
+ * `context' based on the string representation in
+ * the string `*scontext'.  Update `*scontext' to
+ * point to the end of the string representation of
+ * the MLS fields.
+ *
+ * This function modifies the string in place, inserting
+ * NULL characters to terminate the MLS fields.
+ *
+ * If a def_sid is provided and no MLS field is present,
+ * copy the MLS field of the associated default context.
+ * Used for upgraded to MLS systems where objects may lack
+ * MLS fields.
+ *
+ * Policy read-lock must be held for sidtab lookup.
+ *
+ */
+int mls_context_to_sid(char oldc,
+               char **scontext,
+               struct context *context,
+               struct sidtab *s,
+               u32 def_sid)
+{
+
+    char delim;
+    char *scontextp, *p, *rngptr;
+    struct level_datum *levdatum;
+    struct cat_datum *catdatum, *rngdatum;
+    int l, rc = -EINVAL;
+
+    if (!flask_mls_enabled)
+        return 0;
+
+    /*
+     * No MLS component to the security context, try and map to
+     * default if provided.
+     */
+    if (!oldc) {
+        struct context *defcon;
+
+        if (def_sid == SECSID_NULL)
+            goto out;
+
+        defcon = sidtab_search(s, def_sid);
+        if (!defcon)
+            goto out;
+
+        rc = mls_copy_context(context, defcon);
+        goto out;
+    }
+
+    /* Extract low sensitivity. */
+    scontextp = p = *scontext;
+    while (*p && *p != ':' && *p != '-')
+        p++;
+
+    delim = *p;
+    if (delim != 0)
+        *p++ = 0;
+
+    for (l = 0; l < 2; l++) {
+        levdatum = hashtab_search(policydb.p_levels.table, scontextp);
+        if (!levdatum) {
+            rc = -EINVAL;
+            goto out;
+        }
+
+        context->range.level[l].sens = levdatum->level->sens;
+
+        if (delim == ':') {
+            /* Extract category set. */
+            while (1) {
+                scontextp = p;
+                while (*p && *p != ',' && *p != '-')
+                    p++;
+                delim = *p;
+                if (delim != 0)
+                    *p++ = 0;
+
+                /* Separate into range if exists */
+                if ((rngptr = strchr(scontextp, '.')) != NULL) {
+                    /* Remove '.' */
+                    *rngptr++ = 0;
+                }
+
+                catdatum = hashtab_search(policydb.p_cats.table,
+                                          scontextp);
+                if (!catdatum) {
+                    rc = -EINVAL;
+                    goto out;
+                }
+
+                rc = ebitmap_set_bit(&context->range.level[l].cat,
+                                     catdatum->value - 1, 1);
+                if (rc)
+                    goto out;
+
+                /* If range, set all categories in range */
+                if (rngptr) {
+                    int i;
+
+                    rngdatum = hashtab_search(policydb.p_cats.table, rngptr);
+                    if (!rngdatum) {
+                        rc = -EINVAL;
+                        goto out;
+                    }
+
+                    if (catdatum->value >= rngdatum->value) {
+                        rc = -EINVAL;
+                        goto out;
+                    }
+
+                    for (i = catdatum->value; i < rngdatum->value; i++) {
+                        rc = ebitmap_set_bit(&context->range.level[l].cat, i, 1);
+                        if (rc)
+                            goto out;
+                    }
+                }
+
+                if (delim != ',')
+                    break;
+            }
+        }
+        if (delim == '-') {
+            /* Extract high sensitivity. */
+            scontextp = p;
+            while (*p && *p != ':')
+                p++;
+
+            delim = *p;
+            if (delim != 0)
+                *p++ = 0;
+        } else
+            break;
+    }
+
+    if (l == 0) {
+        context->range.level[1].sens = context->range.level[0].sens;
+        rc = ebitmap_cpy(&context->range.level[1].cat,
+                 &context->range.level[0].cat);
+        if (rc)
+            goto out;
+    }
+    *scontext = ++p;
+    rc = 0;
+out:
+    return rc;
+}
+
+/*
+ * Copies the effective MLS range from `src' into `dst'.
+ */
+static inline int mls_scopy_context(struct context *dst,
+                                    struct context *src)
+{
+    int l, rc = 0;
+
+    /* Copy the MLS range from the source context */
+    for (l = 0; l < 2; l++) {
+        dst->range.level[l].sens = src->range.level[0].sens;
+        rc = ebitmap_cpy(&dst->range.level[l].cat,
+                 &src->range.level[0].cat);
+        if (rc)
+            break;
+    }
+
+    return rc;
+}
+
+/*
+ * Copies the MLS range `range' into `context'.
+ */
+static inline int mls_range_set(struct context *context,
+                                struct mls_range *range)
+{
+    int l, rc = 0;
+
+    /* Copy the MLS range into the  context */
+    for (l = 0; l < 2; l++) {
+        context->range.level[l].sens = range->level[l].sens;
+        rc = ebitmap_cpy(&context->range.level[l].cat,
+                 &range->level[l].cat);
+        if (rc)
+            break;
+    }
+
+    return rc;
+}
+
+int mls_setup_user_range(struct context *fromcon, struct user_datum *user,
+                         struct context *usercon)
+{
+    if (flask_mls_enabled) {
+        struct mls_level *fromcon_sen = &(fromcon->range.level[0]);
+        struct mls_level *fromcon_clr = &(fromcon->range.level[1]);
+        struct mls_level *user_low = &(user->range.level[0]);
+        struct mls_level *user_clr = &(user->range.level[1]);
+        struct mls_level *user_def = &(user->dfltlevel);
+        struct mls_level *usercon_sen = &(usercon->range.level[0]);
+        struct mls_level *usercon_clr = &(usercon->range.level[1]);
+
+        /* Honor the user's default level if we can */
+        if (mls_level_between(user_def, fromcon_sen, fromcon_clr)) {
+            *usercon_sen = *user_def;
+        } else if (mls_level_between(fromcon_sen, user_def, user_clr)) {
+            *usercon_sen = *fromcon_sen;
+        } else if (mls_level_between(fromcon_clr, user_low, user_def)) {
+            *usercon_sen = *user_low;
+        } else
+            return -EINVAL;
+
+        /* Lower the clearance of available contexts
+           if the clearance of "fromcon" is lower than
+           that of the user's default clearance (but
+           only if the "fromcon" clearance dominates
+           the user's computed sensitivity level) */
+        if (mls_level_dom(user_clr, fromcon_clr)) {
+            *usercon_clr = *fromcon_clr;
+        } else if (mls_level_dom(fromcon_clr, user_clr)) {
+            *usercon_clr = *user_clr;
+        } else
+            return -EINVAL;
+    }
+
+    return 0;
+}
+
+/*
+ * Convert the MLS fields in the security context
+ * structure `c' from the values specified in the
+ * policy `oldp' to the values specified in the policy `newp'.
+ */
+int mls_convert_context(struct policydb *oldp,
+            struct policydb *newp,
+            struct context *c)
+{
+    struct level_datum *levdatum;
+    struct cat_datum *catdatum;
+    struct ebitmap bitmap;
+    struct ebitmap_node *node;
+    int l, i;
+
+    if (!flask_mls_enabled)
+        return 0;
+
+    for (l = 0; l < 2; l++) {
+        levdatum = hashtab_search(newp->p_levels.table,
+            oldp->p_sens_val_to_name[c->range.level[l].sens - 1]);
+
+        if (!levdatum)
+            return -EINVAL;
+        c->range.level[l].sens = levdatum->level->sens;
+
+        ebitmap_init(&bitmap);
+        ebitmap_for_each_bit(&c->range.level[l].cat, node, i) {
+            if (ebitmap_node_get_bit(node, i)) {
+                int rc;
+
+                catdatum = hashtab_search(newp->p_cats.table,
+                             oldp->p_cat_val_to_name[i]);
+                if (!catdatum)
+                    return -EINVAL;
+                rc = ebitmap_set_bit(&bitmap, catdatum->value - 1, 1);
+                if (rc)
+                    return rc;
+            }
+        }
+        ebitmap_destroy(&c->range.level[l].cat);
+        c->range.level[l].cat = bitmap;
+    }
+
+    return 0;
+}
+
+int mls_compute_sid(struct context *scontext,
+            struct context *tcontext,
+            u16 tclass,
+            u32 specified,
+            struct context *newcontext)
+{
+    if (!flask_mls_enabled)
+        return 0;
+
+    switch (specified) {
+    case AVTAB_TRANSITION:
+        if (tclass == SECCLASS_DOMAIN) {
+            struct range_trans *rangetr;
+            /* Look for a range transition rule. */
+            for (rangetr = policydb.range_tr; rangetr;
+                 rangetr = rangetr->next) {
+                if (rangetr->dom == scontext->type &&
+                    rangetr->type == tcontext->type) {
+                    /* Set the range from the rule */
+                    return mls_range_set(newcontext,
+                                         &rangetr->range);
+                }
+            }
+        }
+        /* Fallthrough */
+    case AVTAB_CHANGE:
+        if (tclass == SECCLASS_DOMAIN)
+            /* Use the process MLS attributes. */
+            return mls_copy_context(newcontext, scontext);
+        else
+            /* Use the process effective MLS attributes. */
+            return mls_scopy_context(newcontext, scontext);
+    case AVTAB_MEMBER:
+        /* Only polyinstantiate the MLS attributes if
+           the type is being polyinstantiated */
+        if (newcontext->type != tcontext->type) {
+            /* Use the process effective MLS attributes. */
+            return mls_scopy_context(newcontext, scontext);
+        } else {
+            /* Use the related object MLS attributes. */
+            return mls_copy_context(newcontext, tcontext);
+        }
+    default:
+        return -EINVAL;
+    }
+    return -EINVAL;
+}
+
diff -r 62b752969edf -r 2b79cd115561 xen/xsm/flask/ss/mls.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/ss/mls.h	Mon May 07 14:51:17 2007 -0400
@@ -0,0 +1,44 @@
+/*
+ * Multi-level security (MLS) policy operations.
+ *
+ * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
+ */
+/*
+ * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
+ *
+ *    Support for enhanced MLS infrastructure.
+ *
+ * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
+ */
+
+#ifndef _SS_MLS_H_
+#define _SS_MLS_H_
+
+#include "context.h"
+#include "policydb.h"
+
+int mls_compute_context_len(struct context *context);
+void mls_sid_to_context(struct context *context, char **scontext);
+int mls_context_isvalid(struct policydb *p, struct context *c);
+
+int mls_context_to_sid(char oldc,
+                       char **scontext,
+                       struct context *context,
+                       struct sidtab *s,
+                       u32 def_sid);
+
+int mls_convert_context(struct policydb *oldp,
+                        struct policydb *newp,
+                        struct context *context);
+
+int mls_compute_sid(struct context *scontext,
+                    struct context *tcontext,
+                    u16 tclass,
+                    u32 specified,
+                    struct context *newcontext);
+
+int mls_setup_user_range(struct context *fromcon, struct user_datum *user,
+                         struct context *usercon);
+
+#endif    /* _SS_MLS_H */
+
diff -r 62b752969edf -r 2b79cd115561 xen/xsm/flask/ss/mls_types.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/ss/mls_types.h	Mon May 07 14:51:17 2007 -0400
@@ -0,0 +1,58 @@
+/*
+ * Type definitions for the multi-level security (MLS) policy.
+ *
+ * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
+ */
+/*
+ * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
+ *
+ *    Support for enhanced MLS infrastructure.
+ *
+ * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
+ */
+
+/* Ported to Xen 3.0, George Coker, <gscoker@alpha.ncsc.mil> */
+
+#ifndef _SS_MLS_TYPES_H_
+#define _SS_MLS_TYPES_H_
+
+#include "security.h"
+
+struct mls_level {
+    u32 sens;        /* sensitivity */
+    struct ebitmap cat;    /* category set */
+};
+
+struct mls_range {
+    struct mls_level level[2]; /* low == level[0], high == level[1] */
+};
+
+static inline int mls_level_eq(struct mls_level *l1, struct mls_level *l2)
+{
+    if (!flask_mls_enabled)
+        return 1;
+
+    return ((l1->sens == l2->sens) &&
+            ebitmap_cmp(&l1->cat, &l2->cat));
+}
+
+static inline int mls_level_dom(struct mls_level *l1, struct mls_level *l2)
+{
+    if (!flask_mls_enabled)
+        return 1;
+
+    return ((l1->sens >= l2->sens) &&
+            ebitmap_contains(&l1->cat, &l2->cat));
+}
+
+#define mls_level_incomp(l1, l2) \
+(!mls_level_dom((l1), (l2)) && !mls_level_dom((l2), (l1)))
+
+#define mls_level_between(l1, l2, l3) \
+(mls_level_dom((l1), (l2)) && mls_level_dom((l3), (l1)))
+
+#define mls_range_contains(r1, r2) \
+(mls_level_dom(&(r2).level[0], &(r1).level[0]) && \
+ mls_level_dom(&(r1).level[1], &(r2).level[1]))
+
+#endif    /* _SS_MLS_TYPES_H_ */
diff -r 62b752969edf -r 2b79cd115561 xen/xsm/flask/ss/policydb.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/ss/policydb.c	Mon May 07 14:51:17 2007 -0400
@@ -0,0 +1,1797 @@
+/*
+ * Implementation of the policy database.
+ *
+ * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
+ */
+
+/*
+ * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
+ *
+ *    Support for enhanced MLS infrastructure.
+ *
+ * Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com>
+ *
+ *     Added conditional policy language extensions
+ *
+ * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
+ * Copyright (C) 2003 - 2004 Tresys Technology, LLC
+ *    This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation, version 2.
+ */
+
+/* Ported to Xen 3.0, George Coker, <gscoker@alpha.ncsc.mil> */
+
+#include <asm/byteorder.h>
+#include <xen/lib.h>
+#include <xen/types.h>
+#include <xen/xmalloc.h>
+#include <xen/string.h>
+#include <xen/errno.h>
+#include "security.h"
+
+#include "policydb.h"
+#include "conditional.h"
+#include "mls.h"
+
+#define _DEBUG_HASHES
+
+#ifdef DEBUG_HASHES
+static char *symtab_name[SYM_NUM] = {
+    "common prefixes",
+    "classes",
+    "roles",
+    "types",
+    "users",
+    "bools",
+    "levels",
+    "categories",
+};
+#endif
+
+int flask_mls_enabled = 0;
+
+static unsigned int symtab_sizes[SYM_NUM] = {
+    2,
+    32,
+    16,
+    512,
+    128,
+    16,
+    16,
+    16,
+};
+
+struct policydb_compat_info {
+    int version;
+    int sym_num;
+    int ocon_num;
+};
+
+/* These need to be updated if SYM_NUM or OCON_NUM changes */
+static struct policydb_compat_info policydb_compat[] = {
+    {
+        .version        = POLICYDB_VERSION_BASE,
+        .sym_num        = SYM_NUM - 3,
+        .ocon_num       = OCON_NUM - 1,
+    },
+    {
+        .version        = POLICYDB_VERSION_BOOL,
+        .sym_num        = SYM_NUM - 2,
+        .ocon_num       = OCON_NUM - 1,
+    },
+    {
+        .version        = POLICYDB_VERSION_IPV6,
+        .sym_num        = SYM_NUM - 2,
+        .ocon_num       = OCON_NUM,
+    },
+    {
+        .version        = POLICYDB_VERSION_NLCLASS,
+        .sym_num        = SYM_NUM - 2,
+        .ocon_num       = OCON_NUM,
+    },
+    {
+        .version        = POLICYDB_VERSION_MLS,
+        .sym_num        = SYM_NUM,
+        .ocon_num       = OCON_NUM,
+    },
+    {
+        .version        = POLICYDB_VERSION_AVTAB,
+        .sym_num        = SYM_NUM,
+        .ocon_num       = OCON_NUM,
+    },
+};
+
+static struct policydb_compat_info *policydb_lookup_compat(int version)
+{
+    int i;
+    struct policydb_compat_info *info = NULL;
+
+    for (i = 0; i < sizeof(policydb_compat)/sizeof(*info); i++) {
+        if (policydb_compat[i].version == version) {
+            info = &policydb_compat[i];
+            break;
+        }
+    }
+    return info;
+}
+
+/*
+ * Initialize the role table.
+ */
+static int roles_init(struct policydb *p)
+{
+    char *key = NULL;
+    int rc;
+    struct role_datum *role;
+
+    role = xmalloc(struct role_datum);
+    if (!role) {
+        rc = -ENOMEM;
+        goto out;
+    }
+    memset(role, 0, sizeof(*role));
+    role->value = ++p->p_roles.nprim;
+    if (role->value != OBJECT_R_VAL) {
+        rc = -EINVAL;
+        goto out_free_role;
+    }
+    key = xmalloc_array(char, strlen(OBJECT_R)+1);
+    if (!key) {
+        rc = -ENOMEM;
+        goto out_free_role;
+    }
+    strlcpy(key, OBJECT_R, strlen(OBJECT_R)+1);
+    rc = hashtab_insert(p->p_roles.table, key, role);
+    if (rc)
+        goto out_free_key;
+out:
+    return rc;
+
+out_free_key:
+    xfree(key);
+out_free_role:
+    xfree(role);
+    goto out;
+}
+
+/*
+ * Initialize a policy database structure.
+ */
+static int policydb_init(struct policydb *p)
+{
+    int i, rc;
+
+    memset(p, 0, sizeof(*p));
+
+    for (i = 0; i < SYM_NUM; i++) {
+        rc = symtab_init(&p->symtab[i], symtab_sizes[i]);
+        if (rc)
+            goto out_free_symtab;
+    }
+
+    rc = avtab_init(&p->te_avtab);
+    if (rc)
+        goto out_free_symtab;
+
+    rc = roles_init(p);
+    if (rc)
+        goto out_free_avtab;
+
+    rc = cond_policydb_init(p);
+    if (rc)
+        goto out_free_avtab;
+
+out:
+    return rc;
+
+out_free_avtab:
+    avtab_destroy(&p->te_avtab);
+
+out_free_symtab:
+    for (i = 0; i < SYM_NUM; i++)
+        hashtab_destroy(p->symtab[i].table);
+    goto out;
+}
+
+/*
+ * The following *_index functions are used to
+ * define the val_to_name and val_to_struct arrays
+ * in a policy database structure.  The val_to_name
+ * arrays are used when converting security context
+ * structures into string representations.  The
+ * val_to_struct arrays are used when the attributes
+ * of a class, role, or user are needed.
+ */
+
+static int common_index(void *key, void *datum, void *datap)
+{
+    struct policydb *p;
+    struct common_datum *comdatum;
+
+    comdatum = datum;
+    p = datap;
+    if (!comdatum->value || comdatum->value > p->p_commons.nprim)
+        return -EINVAL;
+    p->p_common_val_to_name[comdatum->value - 1] = key;
+    return 0;
+}
+
+static int class_index(void *key, void *datum, void *datap)
+{
+    struct policydb *p;
+    struct class_datum *cladatum;
+
+    cladatum = datum;
+    p = datap;
+    if (!cladatum->value || cladatum->value > p->p_classes.nprim)
+        return -EINVAL;
+    p->p_class_val_to_name[cladatum->value - 1] = key;
+    p->class_val_to_struct[cladatum->value - 1] = cladatum;
+    return 0;
+}
+
+static int role_index(void *key, void *datum, void *datap)
+{
+    struct policydb *p;
+    struct role_datum *role;
+
+    role = datum;
+    p = datap;
+    if (!role->value || role->value > p->p_roles.nprim)
+        return -EINVAL;
+    p->p_role_val_to_name[role->value - 1] = key;
+    p->role_val_to_struct[role->value - 1] = role;
+    return 0;
+}
+
+static int type_index(void *key, void *datum, void *datap)
+{
+    struct policydb *p;
+    struct type_datum *typdatum;
+
+    typdatum = datum;
+    p = datap;
+
+    if (typdatum->primary) {
+        if (!typdatum->value || typdatum->value > p->p_types.nprim)
+            return -EINVAL;
+        p->p_type_val_to_name[typdatum->value - 1] = key;
+    }
+
+    return 0;
+}
+
+static int user_index(void *key, void *datum, void *datap)
+{
+    struct policydb *p;
+    struct user_datum *usrdatum;
+
+    usrdatum = datum;
+    p = datap;
+    if (!usrdatum->value || usrdatum->value > p->p_users.nprim)
+        return -EINVAL;
+    p->p_user_val_to_name[usrdatum->value - 1] = key;
+    p->user_val_to_struct[usrdatum->value - 1] = usrdatum;
+    return 0;
+}
+
+static int sens_index(void *key, void *datum, void *datap)
+{
+    struct policydb *p;
+    struct level_datum *levdatum;
+
+    levdatum = datum;
+    p = datap;
+
+    if (!levdatum->isalias) {
+        if (!levdatum->level->sens ||
+            levdatum->level->sens > p->p_levels.nprim)
+            return -EINVAL;
+        p->p_sens_val_to_name[levdatum->level->sens - 1] = key;
+    }
+
+    return 0;
+}
+
+static int cat_index(void *key, void *datum, void *datap)
+{
+    struct policydb *p;
+    struct cat_datum *catdatum;
+
+    catdatum = datum;
+    p = datap;
+
+    if (!catdatum->isalias) {
+        if (!catdatum->value || catdatum->value > p->p_cats.nprim)
+            return -EINVAL;
+        p->p_cat_val_to_name[catdatum->value - 1] = key;
+    }
+
+    return 0;
+}
+
+static int (*index_f[SYM_NUM]) (void *key, void *datum, void *datap) =
+{
+    common_index,
+    class_index,
+    role_index,
+    type_index,
+    user_index,
+    cond_index_bool,
+    sens_index,
+    cat_index,
+};
+
+/*
+ * Define the common val_to_name array and the class
+ * val_to_name and val_to_struct arrays in a policy
+ * database structure.
+ *
+ * Caller must clean up upon failure.
+ */
+static int policydb_index_classes(struct policydb *p)
+{
+    int rc;
+
+    p->p_common_val_to_name =
+        xmalloc_array(char *, p->p_commons.nprim);
+    if (!p->p_common_val_to_name) {
+        rc = -ENOMEM;
+        goto out;
+    }
+
+    rc = hashtab_map(p->p_commons.table, common_index, p);
+    if (rc)
+        goto out;
+
+    p->class_val_to_struct =
+        (void *)xmalloc_array(struct class_datum, p->p_classes.nprim);
+    if (!p->class_val_to_struct) {
+        rc = -ENOMEM;
+        goto out;
+    }
+
+    p->p_class_val_to_name =
+        xmalloc_array(char *, p->p_classes.nprim);
+    if (!p->p_class_val_to_name) {
+        rc = -ENOMEM;
+        goto out;
+    }
+
+    rc = hashtab_map(p->p_classes.table, class_index, p);
+out:
+    return rc;
+}
+
+#ifdef DEBUG_HASHES
+static void symtab_hash_eval(struct symtab *s)
+{
+    int i;
+
+    for (i = 0; i < SYM_NUM; i++) {
+        struct hashtab *h = s[i].table;
+        struct hashtab_info info;
+
+        hashtab_stat(h, &info);
+        printk(KERN_INFO "%s:  %d entries and %d/%d buckets used, "
+               "longest chain length %d\n", symtab_name[i], h->nel,
+               info.slots_used, h->size, info.max_chain_len);
+    }
+}
+#endif
+
+/*
+ * Define the other val_to_name and val_to_struct arrays
+ * in a policy database structure.
+ *
+ * Caller must clean up on failure.
+ */
+static int policydb_index_others(struct policydb *p)
+{
+    int i, rc = 0;
+
+    printk(KERN_INFO "security:  %d users, %d roles, %d types, %d bools",
+           p->p_users.nprim, p->p_roles.nprim, p->p_types.nprim, p->p_bools.nprim);
+    if (flask_mls_enabled)
+        printk(", %d sens, %d cats", p->p_levels.nprim,
+               p->p_cats.nprim);
+    printk("\n");
+
+    printk(KERN_INFO "security:  %d classes, %d rules\n",
+           p->p_classes.nprim, p->te_avtab.nel);
+
+#ifdef DEBUG_HASHES
+    avtab_hash_eval(&p->te_avtab, "rules");
+    symtab_hash_eval(p->symtab);
+#endif
+
+    p->role_val_to_struct =
+        (void *)xmalloc_array(struct role_datum, p->p_roles.nprim);
+    if (!p->role_val_to_struct) {
+        rc = -ENOMEM;
+        goto out;
+    }
+
+    p->user_val_to_struct =
+        (void *)xmalloc_array(struct user_datum, p->p_users.nprim);
+    if (!p->user_val_to_struct) {
+        rc = -ENOMEM;
+        goto out;
+    }
+
+    if (cond_init_bool_indexes(p)) {
+        rc = -ENOMEM;
+        goto out;
+    }
+
+    for (i = SYM_ROLES; i < SYM_NUM; i++) {
+        p->sym_val_to_name[i] =
+            xmalloc_array(char *, p->symtab[i].nprim);
+        if (!p->sym_val_to_name[i]) {
+            rc = -ENOMEM;
+            goto out;
+        }
+        rc = hashtab_map(p->symtab[i].table, index_f[i], p);
+        if (rc)
+            goto out;
+    }
+
+out:
+    return rc;
+}
+
+/*
+ * The following *_destroy functions are used to
+ * free any memory allocated for each kind of
+ * symbol data in the policy database.
+ */
+
+static int perm_destroy(void *key, void *datum, void *p)
+{
+    xfree(key);
+    xfree(datum);
+    return 0;
+}
+
+static int common_destroy(void *key, void *datum, void *p)
+{
+    struct common_datum *comdatum;
+
+    xfree(key);
+    comdatum = datum;
+    hashtab_map(comdatum->permissions.table, perm_destroy, NULL);
+    hashtab_destroy(comdatum->permissions.table);
+    xfree(datum);
+    return 0;
+}
+
+static int class_destroy(void *key, void *datum, void *p)
+{
+    struct class_datum *cladatum;
+    struct constraint_node *constraint, *ctemp;
+    struct constraint_expr *e, *etmp;
+
+    xfree(key);
+    cladatum = datum;
+    hashtab_map(cladatum->permissions.table, perm_destroy, NULL);
+    hashtab_destroy(cladatum->permissions.table);
+    constraint = cladatum->constraints;
+    while (constraint) {
+        e = constraint->expr;
+        while (e) {
+            ebitmap_destroy(&e->names);
+            etmp = e;
+            e = e->next;
+            xfree(etmp);
+        }
+        ctemp = constraint;
+        constraint = constraint->next;
+        xfree(ctemp);
+    }
+
+    constraint = cladatum->validatetrans;
+    while (constraint) {
+        e = constraint->expr;
+        while (e) {
+            ebitmap_destroy(&e->names);
+            etmp = e;
+            e = e->next;
+            xfree(etmp);
+        }
+        ctemp = constraint;
+        constraint = constraint->next;
+        xfree(ctemp);
+    }
+
+    xfree(cladatum->comkey);
+    xfree(datum);
+    return 0;
+}
+
+static int role_destroy(void *key, void *datum, void *p)
+{
+    struct role_datum *role;
+
+    xfree(key);
+    role = datum;
+    ebitmap_destroy(&role->dominates);
+    ebitmap_destroy(&role->types);
+    xfree(datum);
+    return 0;
+}
+
+static int type_destroy(void *key, void *datum, void *p)
+{
+    xfree(key);
+    xfree(datum);
+    return 0;
+}
+
+static int user_destroy(void *key, void *datum, void *p)
+{
+    struct user_datum *usrdatum;
+
+    xfree(key);
+    usrdatum = datum;
+    ebitmap_destroy(&usrdatum->roles);
+    ebitmap_destroy(&usrdatum->range.level[0].cat);
+    ebitmap_destroy(&usrdatum->range.level[1].cat);
+    ebitmap_destroy(&usrdatum->dfltlevel.cat);
+    xfree(datum);
+    return 0;
+}
+
+static int sens_destroy(void *key, void *datum, void *p)
+{
+    struct level_datum *levdatum;
+
+    xfree(key);
+    levdatum = datum;
+    ebitmap_destroy(&levdatum->level->cat);
+    xfree(levdatum->level);
+    xfree(datum);
+    return 0;
+}
+
+static int cat_destroy(void *key, void *datum, void *p)
+{
+    xfree(key);
+    xfree(datum);
+    return 0;
+}
+
+static int (*destroy_f[SYM_NUM]) (void *key, void *datum, void *datap) =
+{
+    common_destroy,
+    class_destroy,
+    role_destroy,
+    type_destroy,
+    user_destroy,
+    cond_destroy_bool,
+    sens_destroy,
+    cat_destroy,
+};
+
+static void ocontext_destroy(struct ocontext *c, int i)
+{
+    context_destroy(&c->context[0]);
+    context_destroy(&c->context[1]);
+    if (i == OCON_ISID)
+        xfree(c->u.name);
+    xfree(c);
+}
+
+/*
+ * Free any memory allocated by a policy database structure.
+ */
+void policydb_destroy(struct policydb *p)
+{
+    struct ocontext *c, *ctmp;
+    int i;
+    struct role_allow *ra, *lra = NULL;
+    struct role_trans *tr, *ltr = NULL;
+    struct range_trans *rt, *lrt = NULL;
+
+    for (i = 0; i < SYM_NUM; i++) {
+        hashtab_map(p->symtab[i].table, destroy_f[i], NULL);
+        hashtab_destroy(p->symtab[i].table);
+    }
+
+    for (i = 0; i < SYM_NUM; i++)
+        xfree(p->sym_val_to_name[i]);
+
+    xfree(p->class_val_to_struct);
+    xfree(p->role_val_to_struct);
+    xfree(p->user_val_to_struct);
+
+    avtab_destroy(&p->te_avtab);
+
+    for (i = 0; i < OCON_NUM; i++) {
+        c = p->ocontexts[i];
+        while (c) {
+            ctmp = c;
+            c = c->next;
+            ocontext_destroy(ctmp,i);
+        }
+    }
+
+    cond_policydb_destroy(p);
+
+    for (tr = p->role_tr; tr; tr = tr->next) {
+        if (ltr) xfree(ltr);
+        ltr = tr;
+    }
+    if (ltr) xfree(ltr);
+
+    for (ra = p->role_allow; ra; ra = ra -> next) {
+        if (lra) xfree(lra);
+        lra = ra;
+    }
+    if (lra) xfree(lra);
+
+    for (rt = p->range_tr; rt; rt = rt -> next) {
+        if (lrt) xfree(lrt);
+        lrt = rt;
+    }
+    if (lrt) xfree(lrt);
+
+    for (i = 0; i < p->p_types.nprim; i++)
+        ebitmap_destroy(&p->type_attr_map[i]);
+    xfree(p->type_attr_map);
+
+    return;
+}
+
+/*
+ * Load the initial SIDs specified in a policy database
+ * structure into a SID table.
+ */
+int policydb_load_isids(struct policydb *p, struct sidtab *s)
+{
+    struct ocontext *head, *c;
+    int rc;
+
+    rc = sidtab_init(s);
+    if (rc) {
+        printk(KERN_ERR "security:  out of memory on SID table init\n");
+        goto out;
+    }
+
+    head = p->ocontexts[OCON_ISID];
+    for (c = head; c; c = c->next) {
+        if (!c->context[0].user) {
+            printk(KERN_ERR "security:  SID %s was never "
+                   "defined.\n", c->u.name);
+            rc = -EINVAL;
+            goto out;
+        }
+        if (sidtab_insert(s, c->sid[0], &c->context[0])) {
+            printk(KERN_ERR "security:  unable to load initial "
+                   "SID %s.\n", c->u.name);
+            rc = -EINVAL;
+            goto out;
+        }
+    }
+out:
+    return rc;
+}
+
+/*
+ * Return 1 if the fields in the security context
+ * structure `c' are valid.  Return 0 otherwise.
+ */
+int policydb_context_isvalid(struct policydb *p, struct context *c)
+{
+    struct role_datum *role;
+    struct user_datum *usrdatum;
+
+    if (!c->role || c->role > p->p_roles.nprim)
+        return 0;
+
+    if (!c->user || c->user > p->p_users.nprim)
+        return 0;
+
+    if (!c->type || c->type > p->p_types.nprim)
+        return 0;
+
+    if (c->role != OBJECT_R_VAL) {
+        /*
+         * Role must be authorized for the type.
+         */
+        role = p->role_val_to_struct[c->role - 1];
+        if (!ebitmap_get_bit(&role->types,
+                     c->type - 1))
+            /* role may not be associated with type */
+            return 0;
+
+        /*
+         * User must be authorized for the role.
+         */
+        usrdatum = p->user_val_to_struct[c->user - 1];
+        if (!usrdatum)
+            return 0;
+
+        if (!ebitmap_get_bit(&usrdatum->roles,
+                     c->role - 1))
+            /* user may not be associated with role */
+            return 0;
+    }
+
+    if (!mls_context_isvalid(p, c))
+        return 0;
+
+    return 1;
+}
+
+/*
+ * Read a MLS range structure from a policydb binary
+ * representation file.
+ */
+static int mls_read_range_helper(struct mls_range *r, void *fp)
+{
+    __le32 buf[2];
+    u32 items;
+    int rc;
+
+    rc = next_entry(buf, fp, sizeof(u32));
+    if (rc < 0)
+        goto out;
+
+    items = le32_to_cpu(buf[0]);
+    if (items > ARRAY_SIZE(buf)) {
+        printk(KERN_ERR "security: mls:  range overflow\n");
+        rc = -EINVAL;
+        goto out;
+    }
+    rc = next_entry(buf, fp, sizeof(u32) * items);
+    if (rc < 0) {
+        printk(KERN_ERR "security: mls:  truncated range\n");
+        goto out;
+    }
+    r->level[0].sens = le32_to_cpu(buf[0]);
+    if (items > 1)
+        r->level[1].sens = le32_to_cpu(buf[1]);
+    else
+        r->level[1].sens = r->level[0].sens;
+
+    rc = ebitmap_read(&r->level[0].cat, fp);
+    if (rc) {
+        printk(KERN_ERR "security: mls:  error reading low "
+               "categories\n");
+        goto out;
+    }
+    if (items > 1) {
+        rc = ebitmap_read(&r->level[1].cat, fp);
+        if (rc) {
+            printk(KERN_ERR "security: mls:  error reading high "
+                   "categories\n");
+            goto bad_high;
+        }
+    } else {
+        rc = ebitmap_cpy(&r->level[1].cat, &r->level[0].cat);
+        if (rc) {
+            printk(KERN_ERR "security: mls:  out of memory\n");
+            goto bad_high;
+        }
+    }
+
+    rc = 0;
+out:
+    return rc;
+bad_high:
+    ebitmap_destroy(&r->level[0].cat);
+    goto out;
+}
+
+/*
+ * Read and validate a security context structure
+ * from a policydb binary representation file.
+ */
+static int context_read_and_validate(struct context *c,
+                     struct policydb *p,
+                     void *fp)
+{
+    __le32 buf[3];
+    int rc;
+
+    rc = next_entry(buf, fp, sizeof buf);
+    if (rc < 0) {
+        printk(KERN_ERR "security: context truncated\n");
+        goto out;
+    }
+    c->user = le32_to_cpu(buf[0]);
+    c->role = le32_to_cpu(buf[1]);
+    c->type = le32_to_cpu(buf[2]);
+    if (p->policyvers >= POLICYDB_VERSION_MLS) {
+        if (mls_read_range_helper(&c->range, fp)) {
+            printk(KERN_ERR "security: error reading MLS range of "
+                   "context\n");
+            rc = -EINVAL;
+            goto out;
+        }
+    }
+
+    if (!policydb_context_isvalid(p, c)) {
+        printk(KERN_ERR "security:  invalid security context\n");
+        context_destroy(c);
+        rc = -EINVAL;
+    }
+out:
+    return rc;
+}
+
+/*
+ * The following *_read functions are used to
+ * read the symbol data from a policy database
+ * binary representation file.
+ */
+
+static int perm_read(struct policydb *p, struct hashtab *h, void *fp)
+{
+    char *key = NULL;
+    struct perm_datum *perdatum;
+    int rc;
+    __le32 buf[2];
+    u32 len;
+
+    perdatum = xmalloc(struct perm_datum);
+    if (!perdatum) {
+        rc = -ENOMEM;
+        goto out;
+    }
+    memset(perdatum, 0, sizeof(*perdatum));
+
+    rc = next_entry(buf, fp, sizeof buf);
+    if (rc < 0)
+        goto bad;
+
+    len = le32_to_cpu(buf[0]);
+    perdatum->value = le32_to_cpu(buf[1]);
+
+    key = xmalloc_array(char, len + 1);
+    if (!key) {
+        rc = -ENOMEM;
+        goto bad;
+    }
+    rc = next_entry(key, fp, len);
+    if (rc < 0)
+        goto bad;
+    key[len] = 0;
+
+    rc = hashtab_insert(h, key, perdatum);
+    if (rc)
+        goto bad;
+out:
+    return rc;
+bad:
+    perm_destroy(key, perdatum, NULL);
+    goto out;
+}
+
+static int common_read(struct policydb *p, struct hashtab *h, void *fp)
+{
+    char *key = NULL;
+    struct common_datum *comdatum;
+    __le32 buf[4];
+    u32 len, nel;
+    int i, rc;
+
+    comdatum = xmalloc(struct common_datum);
+    if (!comdatum) {
+        rc = -ENOMEM;
+        goto out;
+    }
+    memset(comdatum, 0, sizeof(*comdatum));
+
+    rc = next_entry(buf, fp, sizeof buf);
+    if (rc < 0)
+        goto bad;
+
+    len = le32_to_cpu(buf[0]);
+    comdatum->value = le32_to_cpu(buf[1]);
+
+    rc = symtab_init(&comdatum->permissions, PERM_SYMTAB_SIZE);
+    if (rc)
+        goto bad;
+    comdatum->permissions.nprim = le32_to_cpu(buf[2]);
+    nel = le32_to_cpu(buf[3]);
+
+    key = xmalloc_array(char, len + 1);
+    if (!key) {
+        rc = -ENOMEM;
+        goto bad;
+    }
+    rc = next_entry(key, fp, len);
+    if (rc < 0)
+        goto bad;
+    key[len] = 0;
+
+    for (i = 0; i < nel; i++) {
+        rc = perm_read(p, comdatum->permissions.table, fp);
+        if (rc)
+            goto bad;
+    }
+
+    rc = hashtab_insert(h, key, comdatum);
+    if (rc)
+        goto bad;
+out:
+    return rc;
+bad:
+    common_destroy(key, comdatum, NULL);
+    goto out;
+}
+
+static int read_cons_helper(struct constraint_node **nodep, int ncons,
+                            int allowxtarget, void *fp)
+{
+    struct constraint_node *c, *lc;
+    struct constraint_expr *e, *le;
+    __le32 buf[3];
+    u32 nexpr;
+    int rc, i, j, depth;
+
+    lc = NULL;
+    for (i = 0; i < ncons; i++) {
+        c = xmalloc(struct constraint_node);
+        if (!c)
+            return -ENOMEM;
+        memset(c, 0, sizeof(*c));
+
+        if (lc) {
+            lc->next = c;
+        } else {
+            *nodep = c;
+        }
+
+        rc = next_entry(buf, fp, (sizeof(u32) * 2));
+        if (rc < 0)
+            return rc;
+        c->permissions = le32_to_cpu(buf[0]);
+        nexpr = le32_to_cpu(buf[1]);
+        le = NULL;
+        depth = -1;
+        for (j = 0; j < nexpr; j++) {
+            e = xmalloc(struct constraint_expr);
+            if (!e)
+                return -ENOMEM;
+            memset(e, 0, sizeof(*e));
+
+            if (le) {
+                le->next = e;
+            } else {
+                c->expr = e;
+            }
+
+            rc = next_entry(buf, fp, (sizeof(u32) * 3));
+            if (rc < 0)
+                return rc;
+            e->expr_type = le32_to_cpu(buf[0]);
+            e->attr = le32_to_cpu(buf[1]);
+            e->op = le32_to_cpu(buf[2]);
+
+            switch (e->expr_type) {
+            case CEXPR_NOT:
+                if (depth < 0)
+                    return -EINVAL;
+                break;
+            case CEXPR_AND:
+            case CEXPR_OR:
+                if (depth < 1)
+                    return -EINVAL;
+                depth--;
+                break;
+            case CEXPR_ATTR:
+                if (depth == (CEXPR_MAXDEPTH - 1))
+                    return -EINVAL;
+                depth++;
+                break;
+            case CEXPR_NAMES:
+                if (!allowxtarget && (e->attr & CEXPR_XTARGET))
+                    return -EINVAL;
+                if (depth == (CEXPR_MAXDEPTH - 1))
+                    return -EINVAL;
+                depth++;
+                if (ebitmap_read(&e->names, fp))
+                    return -EINVAL;
+                break;
+            default:
+                return -EINVAL;
+            }
+            le = e;
+        }
+        if (depth != 0)
+            return -EINVAL;
+        lc = c;
+    }
+
+    return 0;
+}
+
+static int class_read(struct policydb *p, struct hashtab *h, void *fp)
+{
+    char *key = NULL;
+    struct class_datum *cladatum;
+    __le32 buf[6];
+    u32 len, len2, ncons, nel;
+    int i, rc;
+
+    cladatum = xmalloc(struct class_datum);
+    if (!cladatum) {
+        rc = -ENOMEM;
+        goto out;
+    }
+    memset(cladatum, 0, sizeof(*cladatum));
+
+    rc = next_entry(buf, fp, sizeof(u32)*6);
+    if (rc < 0)
+        goto bad;
+
+    len = le32_to_cpu(buf[0]);
+    len2 = le32_to_cpu(buf[1]);
+    cladatum->value = le32_to_cpu(buf[2]);
+
+    rc = symtab_init(&cladatum->permissions, PERM_SYMTAB_SIZE);
+    if (rc)
+        goto bad;
+    cladatum->permissions.nprim = le32_to_cpu(buf[3]);
+    nel = le32_to_cpu(buf[4]);
+
+    ncons = le32_to_cpu(buf[5]);
+
+    key = xmalloc_array(char, len + 1);
+    if (!key) {
+        rc = -ENOMEM;
+        goto bad;
+    }
+    rc = next_entry(key, fp, len);
+    if (rc < 0)
+        goto bad;
+    key[len] = 0;
+
+    if (len2) {
+        cladatum->comkey = xmalloc_array(char, len2 + 1);
+        if (!cladatum->comkey) {
+            rc = -ENOMEM;
+            goto bad;
+        }
+        rc = next_entry(cladatum->comkey, fp, len2);
+        if (rc < 0)
+            goto bad;
+        cladatum->comkey[len2] = 0;
+
+        cladatum->comdatum = hashtab_search(p->p_commons.table,
+                            cladatum->comkey);
+        if (!cladatum->comdatum) {
+            printk(KERN_ERR "security:  unknown common %s\n",
+                   cladatum->comkey);
+            rc = -EINVAL;
+            goto bad;
+        }
+    }
+    for (i = 0; i < nel; i++) {
+        rc = perm_read(p, cladatum->permissions.table, fp);
+        if (rc)
+            goto bad;
+    }
+
+    rc = read_cons_helper(&cladatum->constraints, ncons, 0, fp);
+    if (rc)
+        goto bad;
+
+    if (p->policyvers >= POLICYDB_VERSION_VALIDATETRANS) {
+        /* grab the validatetrans rules */
+        rc = next_entry(buf, fp, sizeof(u32));
+        if (rc < 0)
+            goto bad;
+        ncons = le32_to_cpu(buf[0]);
+        rc = read_cons_helper(&cladatum->validatetrans, ncons, 1, fp);
+        if (rc)
+            goto bad;
+    }
+
+    rc = hashtab_insert(h, key, cladatum);
+    if (rc)
+        goto bad;
+
+    rc = 0;
+out:
+    return rc;
+bad:
+    class_destroy(key, cladatum, NULL);
+    goto out;
+}
+
+static int role_read(struct policydb *p, struct hashtab *h, void *fp)
+{
+    char *key = NULL;
+    struct role_datum *role;
+    int rc;
+    __le32 buf[2];
+    u32 len;
+
+    role = xmalloc(struct role_datum);
+    if (!role) {
+        rc = -ENOMEM;
+        goto out;
+    }
+    memset(role, 0, sizeof(*role));
+
+    rc = next_entry(buf, fp, sizeof buf);
+    if (rc < 0)
+        goto bad;
+
+    len = le32_to_cpu(buf[0]);
+    role->value = le32_to_cpu(buf[1]);
+
+    key = xmalloc_array(char, len + 1);
+    if (!key) {
+        rc = -ENOMEM;
+        goto bad;
+    }
+    rc = next_entry(key, fp, len);
+    if (rc < 0)
+        goto bad;
+    key[len] = 0;
+
+    rc = ebitmap_read(&role->dominates, fp);
+    if (rc)
+        goto bad;
+
+    rc = ebitmap_read(&role->types, fp);
+    if (rc)
+        goto bad;
+
+    if (strcmp(key, OBJECT_R) == 0) {
+        if (role->value != OBJECT_R_VAL) {
+            printk(KERN_ERR "Role %s has wrong value %d\n",
+                   OBJECT_R, role->value);
+            rc = -EINVAL;
+            goto bad;
+        }
+        rc = 0;
+        goto bad;
+    }
+
+    rc = hashtab_insert(h, key, role);
+    if (rc)
+        goto bad;
+out:
+    return rc;
+bad:
+    role_destroy(key, role, NULL);
+    goto out;
+}
+
+static int type_read(struct policydb *p, struct hashtab *h, void *fp)
+{
+    char *key = NULL;
+    struct type_datum *typdatum;
+    int rc;
+    __le32 buf[3];
+    u32 len;
+
+    typdatum = xmalloc(struct type_datum);
+    if (!typdatum) {
+        rc = -ENOMEM;
+        return rc;
+    }
+    memset(typdatum, 0, sizeof(*typdatum));
+
+    rc = next_entry(buf, fp, sizeof buf);
+    if (rc < 0)
+        goto bad;
+
+    len = le32_to_cpu(buf[0]);
+    typdatum->value = le32_to_cpu(buf[1]);
+    typdatum->primary = le32_to_cpu(buf[2]);
+
+    key = xmalloc_array(char, len + 1);
+    if (!key) {
+        rc = -ENOMEM;
+        goto bad;
+    }
+    rc = next_entry(key, fp, len);
+    if (rc < 0)
+        goto bad;
+    key[len] = 0;
+
+    rc = hashtab_insert(h, key, typdatum);
+    if (rc)
+        goto bad;
+out:
+    return rc;
+bad:
+    type_destroy(key, typdatum, NULL);
+    goto out;
+}
+
+
+/*
+ * Read a MLS level structure from a policydb binary
+ * representation file.
+ */
+static int mls_read_level(struct mls_level *lp, void *fp)
+{
+    __le32 buf[1];
+    int rc;
+
+    memset(lp, 0, sizeof(*lp));
+
+    rc = next_entry(buf, fp, sizeof buf);
+    if (rc < 0) {
+        printk(KERN_ERR "security: mls: truncated level\n");
+        goto bad;
+    }
+    lp->sens = le32_to_cpu(buf[0]);
+
+    if (ebitmap_read(&lp->cat, fp)) {
+        printk(KERN_ERR "security: mls:  error reading level "
+               "categories\n");
+        goto bad;
+    }
+    return 0;
+
+bad:
+    return -EINVAL;
+}
+
+static int user_read(struct policydb *p, struct hashtab *h, void *fp)
+{
+    char *key = NULL;
+    struct user_datum *usrdatum;
+    int rc;
+    __le32 buf[2];
+    u32 len;
+
+    usrdatum = xmalloc(struct user_datum);
+    if (!usrdatum) {
+        rc = -ENOMEM;
+        goto out;
+    }
+    memset(usrdatum, 0, sizeof(*usrdatum));
+
+    rc = next_entry(buf, fp, sizeof buf);
+    if (rc < 0)
+        goto bad;
+
+    len = le32_to_cpu(buf[0]);
+    usrdatum->value = le32_to_cpu(buf[1]);
+
+    key = xmalloc_array(char, len + 1);
+    if (!key) {
+        rc = -ENOMEM;
+        goto bad;
+    }
+    rc = next_entry(key, fp, len);
+    if (rc < 0)
+        goto bad;
+    key[len] = 0;
+
+    rc = ebitmap_read(&usrdatum->roles, fp);
+    if (rc)
+        goto bad;
+
+    if (p->policyvers >= POLICYDB_VERSION_MLS) {
+        rc = mls_read_range_helper(&usrdatum->range, fp);
+        if (rc)
+            goto bad;
+        rc = mls_read_level(&usrdatum->dfltlevel, fp);
+        if (rc)
+            goto bad;
+    }
+
+    rc = hashtab_insert(h, key, usrdatum);
+    if (rc)
+        goto bad;
+out:
+    return rc;
+bad:
+    user_destroy(key, usrdatum, NULL);
+    goto out;
+}
+
+static int sens_read(struct policydb *p, struct hashtab *h, void *fp)
+{
+    char *key = NULL;
+    struct level_datum *levdatum;
+    int rc;
+    __le32 buf[2];
+    u32 len;
+
+    levdatum = xmalloc(struct level_datum);
+    if (!levdatum) {
+        rc = -ENOMEM;
+        goto out;
+    }
+    memset(levdatum, 0, sizeof(*levdatum));
+
+    rc = next_entry(buf, fp, sizeof buf);
+    if (rc < 0)
+        goto bad;
+
+    len = le32_to_cpu(buf[0]);
+    levdatum->isalias = le32_to_cpu(buf[1]);
+
+    key = xmalloc_array(char, len + 1);
+    if (!key) {
+        rc = -ENOMEM;
+        goto bad;
+    }
+    rc = next_entry(key, fp, len);
+    if (rc < 0)
+        goto bad;
+    key[len] = 0;
+
+    levdatum->level = xmalloc(struct mls_level);
+    if (!levdatum->level) {
+        rc = -ENOMEM;
+        goto bad;
+    }
+    if (mls_read_level(levdatum->level, fp)) {
+        rc = -EINVAL;
+        goto bad;
+    }
+
+    rc = hashtab_insert(h, key, levdatum);
+    if (rc)
+        goto bad;
+out:
+    return rc;
+bad:
+    sens_destroy(key, levdatum, NULL);
+    goto out;
+}
+
+static int cat_read(struct policydb *p, struct hashtab *h, void *fp)
+{
+    char *key = NULL;
+    struct cat_datum *catdatum;
+    int rc;
+    __le32 buf[3];
+    u32 len;
+
+    catdatum = xmalloc(struct cat_datum);
+    if (!catdatum) {
+        rc = -ENOMEM;
+        goto out;
+    }
+    memset(catdatum, 0, sizeof(*catdatum));
+
+    rc = next_entry(buf, fp, sizeof buf);
+    if (rc < 0)
+        goto bad;
+
+    len = le32_to_cpu(buf[0]);
+    catdatum->value = le32_to_cpu(buf[1]);
+    catdatum->isalias = le32_to_cpu(buf[2]);
+
+    key = xmalloc_array(char, len + 1);
+    if (!key) {
+        rc = -ENOMEM;
+        goto bad;
+    }
+    rc = next_entry(key, fp, len);
+    if (rc < 0)
+        goto bad;
+    key[len] = 0;
+
+    rc = hashtab_insert(h, key, catdatum);
+    if (rc)
+        goto bad;
+out:
+    return rc;
+
+bad:
+    cat_destroy(key, catdatum, NULL);
+    goto out;
+}
+
+static int (*read_f[SYM_NUM]) (struct policydb *p, struct hashtab *h, void *fp) =
+{
+    common_read,
+    class_read,
+    role_read,
+    type_read,
+    user_read,
+    cond_read_bool,
+    sens_read,
+    cat_read,
+};
+
+extern int ss_initialized;
+
+/*
+ * Read the configuration data from a policy database binary
+ * representation file into a policy database structure.
+ */
+int policydb_read(struct policydb *p, void *fp)
+{
+    struct role_allow *ra, *lra;
+    struct role_trans *tr, *ltr;
+    struct ocontext *l, *c /*, *newc*/;
+    int i, j, rc;
+    __le32 buf[8];
+    u32 len, /*len2,*/ config, nprim, nel /*, nel2*/;
+    char *policydb_str;
+    struct policydb_compat_info *info;
+    struct range_trans *rt, *lrt;
+
+    config = 0;
+    rc = policydb_init(p);
+    if (rc)
+        goto out;
+
+    /* Read the magic number and string length. */
+    rc = next_entry(buf, fp, sizeof(u32)* 2);
+    if (rc < 0)
+        goto bad;
+
+    if (le32_to_cpu(buf[0]) != POLICYDB_MAGIC) {
+        printk(KERN_ERR "security:  policydb magic number 0x%x does "
+               "not match expected magic number 0x%x\n",
+               le32_to_cpu(buf[0]), POLICYDB_MAGIC);
+        goto bad;
+    }
+
+    len = le32_to_cpu(buf[1]);
+    if (len != strlen(POLICYDB_STRING)) {
+        printk(KERN_ERR "security:  policydb string length %d does not "
+               "match expected length %Zu\n",
+               len, (u32) strlen(POLICYDB_STRING));
+        goto bad;
+    }
+    policydb_str = xmalloc_array(char, len + 1);
+    if (!policydb_str) {
+        printk(KERN_ERR "security:  unable to allocate memory for policydb "
+               "string of length %d\n", len);
+        rc = -ENOMEM;
+        goto bad;
+    }
+    rc = next_entry(policydb_str, fp, len);
+    if (rc < 0) {
+        printk(KERN_ERR "security:  truncated policydb string identifier\n");
+        xfree(policydb_str);
+        goto bad;
+    }
+    policydb_str[len] = 0;
+    if (strcmp(policydb_str, POLICYDB_STRING)) {
+        printk(KERN_ERR "security:  policydb string %s does not match "
+               "my string %s\n", policydb_str, POLICYDB_STRING);
+        xfree(policydb_str);
+        goto bad;
+    }
+    /* Done with policydb_str. */
+    xfree(policydb_str);
+    policydb_str = NULL;
+
+    /* Read the version, config, and table sizes. */
+    rc = next_entry(buf, fp, sizeof(u32)*4);
+    if (rc < 0)
+        goto bad;
+
+    p->policyvers = le32_to_cpu(buf[0]);
+    if (p->policyvers < POLICYDB_VERSION_MIN ||
+        p->policyvers > POLICYDB_VERSION_MAX) {
+            printk(KERN_ERR "security:  policydb version %d does not match "
+                   "my version range %d-%d\n",
+                   le32_to_cpu(buf[0]), POLICYDB_VERSION_MIN, POLICYDB_VERSION_MAX);
+            goto bad;
+    }
+
+    if ((le32_to_cpu(buf[1]) & POLICYDB_CONFIG_MLS)) {
+        if (ss_initialized && !flask_mls_enabled) {
+            printk(KERN_ERR "Cannot switch between non-MLS and MLS "
+                   "policies\n");
+            goto bad;
+        }
+        flask_mls_enabled = 1;
+        config |= POLICYDB_CONFIG_MLS;
+
+        if (p->policyvers < POLICYDB_VERSION_MLS) {
+            printk(KERN_ERR "security policydb version %d (MLS) "
+                   "not backwards compatible\n", p->policyvers);
+            goto bad;
+        }
+    } else {
+        if (ss_initialized && flask_mls_enabled) {
+            printk(KERN_ERR "Cannot switch between MLS and non-MLS "
+                   "policies\n");
+            goto bad;
+        }
+    }
+
+    info = policydb_lookup_compat(p->policyvers);
+    if (!info) {
+        printk(KERN_ERR "security:  unable to find policy compat info "
+               "for version %d\n", p->policyvers);
+        goto bad;
+    }
+
+    if (le32_to_cpu(buf[2]) != info->sym_num ||
+        le32_to_cpu(buf[3]) != info->ocon_num) {
+        printk(KERN_ERR "security:  policydb table sizes (%d,%d) do "
+               "not match mine (%d,%d)\n", le32_to_cpu(buf[2]),
+            le32_to_cpu(buf[3]),
+               info->sym_num, info->ocon_num);
+        goto bad;
+    }
+
+    for (i = 0; i < info->sym_num; i++) {
+        rc = next_entry(buf, fp, sizeof(u32)*2);
+        if (rc < 0)
+            goto bad;
+        nprim = le32_to_cpu(buf[0]);
+        nel = le32_to_cpu(buf[1]);
+        for (j = 0; j < nel; j++) {
+            rc = read_f[i](p, p->symtab[i].table, fp);
+            if (rc)
+                goto bad;
+        }
+
+        p->symtab[i].nprim = nprim;
+    }
+
+    rc = avtab_read(&p->te_avtab, fp, p->policyvers);
+    if (rc)
+        goto bad;
+
+    if (p->policyvers >= POLICYDB_VERSION_BOOL) {
+        rc = cond_read_list(p, fp);
+        if (rc)
+            goto bad;
+    }
+
+    rc = next_entry(buf, fp, sizeof(u32));
+    if (rc < 0)
+        goto bad;
+    nel = le32_to_cpu(buf[0]);
+    ltr = NULL;
+    for (i = 0; i < nel; i++) {
+        tr = xmalloc(struct role_trans);
+        if (!tr) {
+            rc = -ENOMEM;
+            goto bad;
+        }
+        memset(tr, 0, sizeof(*tr));
+        if (ltr) {
+            ltr->next = tr;
+        } else {
+            p->role_tr = tr;
+        }
+        rc = next_entry(buf, fp, sizeof(u32)*3);
+        if (rc < 0)
+            goto bad;
+        tr->role = le32_to_cpu(buf[0]);
+        tr->type = le32_to_cpu(buf[1]);
+        tr->new_role = le32_to_cpu(buf[2]);
+        ltr = tr;
+    }
+
+    rc = next_entry(buf, fp, sizeof(u32));
+    if (rc < 0)
+        goto bad;
+    nel = le32_to_cpu(buf[0]);
+    lra = NULL;
+    for (i = 0; i < nel; i++) {
+        ra = xmalloc(struct role_allow);
+        if (!ra) {
+            rc = -ENOMEM;
+            goto bad;
+        }
+        memset(ra, 0, sizeof(*ra));
+        if (lra) {
+            lra->next = ra;
+        } else {
+            p->role_allow = ra;
+        }
+        rc = next_entry(buf, fp, sizeof(u32)*2);
+        if (rc < 0)
+            goto bad;
+        ra->role = le32_to_cpu(buf[0]);
+        ra->new_role = le32_to_cpu(buf[1]);
+        lra = ra;
+    }
+
+    rc = policydb_index_classes(p);
+    if (rc)
+        goto bad;
+
+    rc = policydb_index_others(p);
+    if (rc)
+        goto bad;
+
+    for (i = 0; i < info->ocon_num; i++) {
+        rc = next_entry(buf, fp, sizeof(u32));
+        if (rc < 0)
+            goto bad;
+        nel = le32_to_cpu(buf[0]);
+        l = NULL;
+        for (j = 0; j < nel; j++) {
+            c = xmalloc(struct ocontext);
+            if (!c) {
+                rc = -ENOMEM;
+                goto bad;
+            }
+            memset(c, 0, sizeof(*c));
+            if (l) {
+                l->next = c;
+            } else {
+                p->ocontexts[i] = c;
+            }
+            l = c;
+            rc = -EINVAL;
+            switch (i) {
+            case OCON_ISID:
+                rc = next_entry(buf, fp, sizeof(u32));
+                if (rc < 0)
+                    goto bad;
+                c->sid[0] = le32_to_cpu(buf[0]);
+                rc = context_read_and_validate(&c->context[0], p, fp);
+                if (rc)
+                    goto bad;
+                break;
+            }
+        }
+    }
+
+    rc = next_entry(buf, fp, sizeof(u32));
+    if (rc < 0)
+        goto bad;
+    nel = le32_to_cpu(buf[0]);
+/*    genfs_p = NULL;
+    rc = -EINVAL;
+    for (i = 0; i < nel; i++) {
+        rc = next_entry(buf, fp, sizeof(u32));
+        if (rc < 0)
+            goto bad;
+        len = le32_to_cpu(buf[0]);
+        newgenfs = xmalloc(struct genfs);
+        if (!newgenfs) {
+            rc = -ENOMEM;
+            goto bad;
+        }
+        memset(newgenfs, 0, sizeof(*newgenfs));
+
+        newgenfs->fstype = xmalloc_array(char, len + 1);
+        if (!newgenfs->fstype) {
+            rc = -ENOMEM;
+            xfree(newgenfs);
+            goto bad;
+        }
+        rc = next_entry(newgenfs->fstype, fp, len);
+        if (rc < 0) {
+            xfree(newgenfs->fstype);
+            xfree(newgenfs);
+            goto bad;
+        }
+        newgenfs->fstype[len] = 0;
+        for (genfs_p = NULL, genfs = p->genfs; genfs;
+             genfs_p = genfs, genfs = genfs->next) {
+            if (strcmp(newgenfs->fstype, genfs->fstype) == 0) {
+                printk(KERN_ERR "security:  dup genfs "
+                       "fstype %s\n", newgenfs->fstype);
+                xfree(newgenfs->fstype);
+                xfree(newgenfs);
+                goto bad;
+            }
+            if (strcmp(newgenfs->fstype, genfs->fstype) < 0)
+                break;
+        }
+        newgenfs->next = genfs;
+        if (genfs_p)
+            genfs_p->next = newgenfs;
+        else
+            p->genfs = newgenfs;
+        rc = next_entry(buf, fp, sizeof(u32));
+        if (rc < 0)
+            goto bad;
+        nel2 = le32_to_cpu(buf[0]);
+        for (j = 0; j < nel2; j++) {
+            rc = next_entry(buf, fp, sizeof(u32));
+            if (rc < 0)
+                goto bad;
+            len = le32_to_cpu(buf[0]);
+
+            newc = xmalloc(struct ocontext);
+            if (!newc) {
+                rc = -ENOMEM;
+                goto bad;
+            }
+            memset(newc, 0, sizeof(*newc));
+
+            newc->u.name = xmalloc_array(char, len + 1);
+            if (!newc->u.name) {
+                rc = -ENOMEM;
+                goto bad_newc;
+            }
+            rc = next_entry(newc->u.name, fp, len);
+            if (rc < 0)
+                goto bad_newc;
+            newc->u.name[len] = 0;
+            rc = next_entry(buf, fp, sizeof(u32));
+            if (rc < 0)
+                goto bad_newc;
+            newc->v.sclass = le32_to_cpu(buf[0]);
+            if (context_read_and_validate(&newc->context[0], p, fp))
+                goto bad_newc;
+            for (l = NULL, c = newgenfs->head; c;
+                 l = c, c = c->next) {
+                if (!strcmp(newc->u.name, c->u.name) &&
+                    (!c->v.sclass || !newc->v.sclass ||
+                     newc->v.sclass == c->v.sclass)) {
+                    printk(KERN_ERR "security:  dup genfs "
+                           "entry (%s,%s)\n",
+                           newgenfs->fstype, c->u.name);
+                    goto bad_newc;
+                }
+                len = strlen(newc->u.name);
+                len2 = strlen(c->u.name);
+                if (len > len2)
+                    break;
+            }
+
+            newc->next = c;
+            if (l)
+                l->next = newc;
+            else
+                newgenfs->head = newc;
+        }
+    }
+*/
+    if (p->policyvers >= POLICYDB_VERSION_MLS) {
+        rc = next_entry(buf, fp, sizeof(u32));
+        if (rc < 0)
+            goto bad;
+        nel = le32_to_cpu(buf[0]);
+        lrt = NULL;
+        for (i = 0; i < nel; i++) {
+            rt = xmalloc(struct range_trans);
+            if (!rt) {
+                rc = -ENOMEM;
+                goto bad;
+            }
+            memset(rt, 0, sizeof(*rt));
+            if (lrt)
+                lrt->next = rt;
+            else
+                p->range_tr = rt;
+            rc = next_entry(buf, fp, (sizeof(u32) * 2));
+            if (rc < 0)
+                goto bad;
+            rt->dom = le32_to_cpu(buf[0]);
+            rt->type = le32_to_cpu(buf[1]);
+            rc = mls_read_range_helper(&rt->range, fp);
+            if (rc)
+                goto bad;
+            lrt = rt;
+        }
+    }
+
+    p->type_attr_map = xmalloc_array(struct ebitmap, p->p_types.nprim);
+    if (!p->type_attr_map)
+        goto bad;
+
+    for (i = 0; i < p->p_types.nprim; i++) {
+        ebitmap_init(&p->type_attr_map[i]);
+        if (p->policyvers >= POLICYDB_VERSION_AVTAB) {
+            if (ebitmap_read(&p->type_attr_map[i], fp))
+                goto bad;
+        }
+        /* add the type itself as the degenerate case */
+        if (ebitmap_set_bit(&p->type_attr_map[i], i, 1))
+                goto bad;
+    }
+
+    rc = 0;
+out:
+    return rc;
+/*bad_newc:
+    ocontext_destroy(newc,OCON_FSUSE);*/
+bad:
+    if (!rc)
+        rc = -EINVAL;
+    policydb_destroy(p);
+    goto out;
+}
diff -r 62b752969edf -r 2b79cd115561 xen/xsm/flask/ss/policydb.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/ss/policydb.h	Mon May 07 14:51:17 2007 -0400
@@ -0,0 +1,257 @@
+/*
+ * A policy database (policydb) specifies the
+ * configuration data for the security policy.
+ *
+ * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
+ */
+
+/*
+ * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
+ *
+ *    Support for enhanced MLS infrastructure.
+ *
+ * Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com>
+ *
+ *     Added conditional policy language extensions
+ *
+ * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
+ * Copyright (C) 2003 - 2004 Tresys Technology, LLC
+ *    This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation, version 2.
+ */
+
+/* Ported to Xen 3.0, George Coker, <gscoker@alpha.ncsc.mil> */
+
+#ifndef _SS_POLICYDB_H_
+#define _SS_POLICYDB_H_
+
+#include "symtab.h"
+#include "avtab.h"
+#include "sidtab.h"
+#include "context.h"
+#include "constraint.h"
+
+/*
+ * A datum type is defined for each kind of symbol
+ * in the configuration data:  individual permissions,
+ * common prefixes for access vectors, classes,
+ * users, roles, types, sensitivities, categories, etc.
+ */
+
+/* Permission attributes */
+struct perm_datum {
+    u32 value;        /* permission bit + 1 */
+};
+
+/* Attributes of a common prefix for access vectors */
+struct common_datum {
+    u32 value;            /* internal common value */
+    struct symtab permissions;    /* common permissions */
+};
+
+/* Class attributes */
+struct class_datum {
+    u32 value;            /* class value */
+    char *comkey;            /* common name */
+    struct common_datum *comdatum;    /* common datum */
+    struct symtab permissions;    /* class-specific permission symbol table */
+    struct constraint_node *constraints;    /* constraints on class permissions */
+    struct constraint_node *validatetrans;    /* special transition rules */
+};
+
+/* Role attributes */
+struct role_datum {
+    u32 value;            /* internal role value */
+    struct ebitmap dominates;    /* set of roles dominated by this role */
+    struct ebitmap types;        /* set of authorized types for role */
+};
+
+struct role_trans {
+    u32 role;        /* current role */
+    u32 type;        /* program executable type */
+    u32 new_role;        /* new role */
+    struct role_trans *next;
+};
+
+struct role_allow {
+    u32 role;        /* current role */
+    u32 new_role;        /* new role */
+    struct role_allow *next;
+};
+
+/* Type attributes */
+struct type_datum {
+    u32 value;        /* internal type value */
+    unsigned char primary;    /* primary name? */
+};
+
+/* User attributes */
+struct user_datum {
+    u32 value;            /* internal user value */
+    struct ebitmap roles;        /* set of authorized roles for user */
+    struct mls_range range;        /* MLS range (min - max) for user */
+    struct mls_level dfltlevel;    /* default login MLS level for user */
+};
+
+
+/* Sensitivity attributes */
+struct level_datum {
+    struct mls_level *level;    /* sensitivity and associated categories */
+    unsigned char isalias;    /* is this sensitivity an alias for another? */
+};
+
+/* Category attributes */
+struct cat_datum {
+    u32 value;        /* internal category bit + 1 */
+    unsigned char isalias;  /* is this category an alias for another? */
+};
+
+struct range_trans {
+    u32 dom;            /* current process domain */
+    u32 type;            /* program executable type */
+    struct mls_range range;        /* new range */
+    struct range_trans *next;
+};
+
+/* Boolean data type */
+struct cond_bool_datum {
+    __u32 value;        /* internal type value */
+    int state;
+};
+
+struct cond_node;
+
+/*
+ * The configuration data includes security contexts for
+ * initial SIDs, unlabeled file systems, TCP and UDP port numbers,
+ * network interfaces, and nodes.  This structure stores the
+ * relevant data for one such entry.  Entries of the same kind
+ * (e.g. all initial SIDs) are linked together into a list.
+ */
+struct ocontext {
+    union {
+        char *name;    /* name of initial SID, fs, netif, fstype, path */
+        int pirq;
+        int virq;
+        int vcpu;
+        u32 ioport;
+        unsigned long iomem;
+    } u;
+    struct context context[2];    /* security context(s) */
+    u32 sid[2];    /* SID(s) */
+    struct ocontext *next;
+};
+
+/* symbol table array indices */
+#define SYM_COMMONS 0
+#define SYM_CLASSES 1
+#define SYM_ROLES   2
+#define SYM_TYPES   3
+#define SYM_USERS   4
+#define SYM_BOOLS   5
+#define SYM_LEVELS  6
+#define SYM_CATS    7
+#define SYM_NUM     8
+
+/* object context array indices */
+#define OCON_ISID    0    /* initial SIDs */
+#define OCON_PIRQ    1    /* physical irqs */
+#define OCON_VIRQ    2    /* virtual irqs */
+#define OCON_VCPU    3    /* virtual cpus */
+#define OCON_IOPORT  4    /* io ports */
+#define OCON_IOMEM   5    /* io memory */
+#define OCON_DUMMY   6
+#define OCON_NUM     7
+
+/* The policy database */
+struct policydb {
+    /* symbol tables */
+    struct symtab symtab[SYM_NUM];
+#define p_commons symtab[SYM_COMMONS]
+#define p_classes symtab[SYM_CLASSES]
+#define p_roles symtab[SYM_ROLES]
+#define p_types symtab[SYM_TYPES]
+#define p_users symtab[SYM_USERS]
+#define p_bools symtab[SYM_BOOLS]
+#define p_levels symtab[SYM_LEVELS]
+#define p_cats symtab[SYM_CATS]
+
+    /* symbol names indexed by (value - 1) */
+    char **sym_val_to_name[SYM_NUM];
+#define p_common_val_to_name sym_val_to_name[SYM_COMMONS]
+#define p_class_val_to_name sym_val_to_name[SYM_CLASSES]
+#define p_role_val_to_name sym_val_to_name[SYM_ROLES]
+#define p_type_val_to_name sym_val_to_name[SYM_TYPES]
+#define p_user_val_to_name sym_val_to_name[SYM_USERS]
+#define p_bool_val_to_name sym_val_to_name[SYM_BOOLS]
+#define p_sens_val_to_name sym_val_to_name[SYM_LEVELS]
+#define p_cat_val_to_name sym_val_to_name[SYM_CATS]
+
+    /* class, role, and user attributes indexed by (value - 1) */
+    struct class_datum **class_val_to_struct;
+    struct role_datum **role_val_to_struct;
+    struct user_datum **user_val_to_struct;
+
+    /* type enforcement access vectors and transitions */
+    struct avtab te_avtab;
+
+    /* role transitions */
+    struct role_trans *role_tr;
+
+    /* bools indexed by (value - 1) */
+    struct cond_bool_datum **bool_val_to_struct;
+    /* type enforcement conditional access vectors and transitions */
+    struct avtab te_cond_avtab;
+    /* linked list indexing te_cond_avtab by conditional */
+    struct cond_node* cond_list;
+
+    /* role allows */
+    struct role_allow *role_allow;
+
+    /* security contexts of initial SIDs, unlabeled file systems,
+       TCP or UDP port numbers, network interfaces and nodes */
+    struct ocontext *ocontexts[OCON_NUM];
+
+    /* range transitions */
+    struct range_trans *range_tr;
+
+    /* type -> attribute reverse mapping */
+    struct ebitmap *type_attr_map;
+
+    unsigned int policyvers;
+};
+
+extern void policydb_destroy(struct policydb *p);
+extern int policydb_load_isids(struct policydb *p, struct sidtab *s);
+extern int policydb_context_isvalid(struct policydb *p, struct context *c);
+extern int policydb_read(struct policydb *p, void *fp);
+
+#define PERM_SYMTAB_SIZE 32
+
+#define POLICYDB_CONFIG_MLS    1
+
+#define OBJECT_R "object_r"
+#define OBJECT_R_VAL 1
+
+#define POLICYDB_MAGIC SELINUX_MAGIC
+#define POLICYDB_STRING "SE Linux"
+
+struct policy_file {
+    char *data;
+    size_t len;
+};
+
+static inline int next_entry(void *buf, struct policy_file *fp, size_t bytes)
+{
+    if (bytes > fp->len)
+        return -EINVAL;
+
+    memcpy(buf, fp->data, bytes);
+    fp->data += bytes;
+    fp->len -= bytes;
+    return 0;
+}
+
+#endif    /* _SS_POLICYDB_H_ */
+
diff -r 62b752969edf -r 2b79cd115561 xen/xsm/flask/ss/services.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/ss/services.c	Mon May 07 14:51:17 2007 -0400
@@ -0,0 +1,1599 @@
+/*
+ * Implementation of the security services.
+ *
+ * Authors : Stephen Smalley, <sds@epoch.ncsc.mil>
+ *           James Morris <jmorris@redhat.com>
+ *
+ * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
+ *
+ *    Support for enhanced MLS infrastructure.
+ *
+ * Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com>
+ *
+ *     Added conditional policy language extensions
+ *
+ * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
+ * Copyright (C) 2003 - 2004 Tresys Technology, LLC
+ * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com>
+ *    This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation, version 2.
+ */
+ 
+/* Ported to Xen 3.0, George Coker, <gscoker@alpha.ncsc.mil> */
+
+#include <xen/lib.h>
+#include <xen/xmalloc.h>
+#include <xen/string.h>
+#include <xen/spinlock.h>
+#include <xen/errno.h>
+#include "flask.h"
+#include "avc.h"
+#include "avc_ss.h"
+#include "security.h"
+#include "context.h"
+#include "policydb.h"
+#include "sidtab.h"
+#include "services.h"
+#include "conditional.h"
+#include "mls.h"
+
+unsigned int policydb_loaded_version;
+
+static DEFINE_RWLOCK(policy_rwlock);
+#define POLICY_RDLOCK read_lock(&policy_rwlock)
+#define POLICY_WRLOCK write_lock_irq(&policy_rwlock)
+#define POLICY_RDUNLOCK read_unlock(&policy_rwlock)
+#define POLICY_WRUNLOCK write_unlock_irq(&policy_rwlock)
+
+static DEFINE_SPINLOCK(load_sem);
+#define LOAD_LOCK spin_lock(&load_sem)
+#define LOAD_UNLOCK spin_unlock(&load_sem)
+
+static struct sidtab sidtab;
+struct policydb policydb;
+int ss_initialized = 0;
+
+/*
+ * The largest sequence number that has been used when
+ * providing an access decision to the access vector cache.
+ * The sequence number only changes when a policy change
+ * occurs.
+ */
+static u32 latest_granting = 0;
+
+/* Forward declaration. */
+static int context_struct_to_string(struct context *context, char **scontext,
+                    u32 *scontext_len);
+
+/*
+ * Return the boolean value of a constraint expression
+ * when it is applied to the specified source and target
+ * security contexts.
+ *
+ * xcontext is a special beast...  It is used by the validatetrans rules
+ * only.  For these rules, scontext is the context before the transition,
+ * tcontext is the context after the transition, and xcontext is the context
+ * of the process performing the transition.  All other callers of
+ * constraint_expr_eval should pass in NULL for xcontext.
+ */
+static int constraint_expr_eval(struct context *scontext,
+                struct context *tcontext,
+                struct context *xcontext,
+                struct constraint_expr *cexpr)
+{
+    u32 val1, val2;
+    struct context *c;
+    struct role_datum *r1, *r2;
+    struct mls_level *l1, *l2;
+    struct constraint_expr *e;
+    int s[CEXPR_MAXDEPTH];
+    int sp = -1;
+
+    for (e = cexpr; e; e = e->next) {
+        switch (e->expr_type) {
+        case CEXPR_NOT:
+            BUG_ON(sp < 0);
+            s[sp] = !s[sp];
+            break;
+        case CEXPR_AND:
+            BUG_ON(sp < 1);
+            sp--;
+            s[sp] &= s[sp+1];
+            break;
+        case CEXPR_OR:
+            BUG_ON(sp < 1);
+            sp--;
+            s[sp] |= s[sp+1];
+            break;
+        case CEXPR_ATTR:
+            if (sp == (CEXPR_MAXDEPTH-1))
+                return 0;
+            switch (e->attr) {
+            case CEXPR_USER:
+                val1 = scontext->user;
+                val2 = tcontext->user;
+                break;
+            case CEXPR_TYPE:
+                val1 = scontext->type;
+                val2 = tcontext->type;
+                break;
+            case CEXPR_ROLE:
+                val1 = scontext->role;
+                val2 = tcontext->role;
+                r1 = policydb.role_val_to_struct[val1 - 1];
+                r2 = policydb.role_val_to_struct[val2 - 1];
+                switch (e->op) {
+                case CEXPR_DOM:
+                    s[++sp] = ebitmap_get_bit(&r1->dominates,
+                                  val2 - 1);
+                    continue;
+                case CEXPR_DOMBY:
+                    s[++sp] = ebitmap_get_bit(&r2->dominates,
+                                  val1 - 1);
+                    continue;
+                case CEXPR_INCOMP:
+                    s[++sp] = ( !ebitmap_get_bit(&r1->dominates,
+                                     val2 - 1) &&
+                            !ebitmap_get_bit(&r2->dominates,
+                                     val1 - 1) );
+                    continue;
+                default:
+                    break;
+                }
+                break;
+            case CEXPR_L1L2:
+                l1 = &(scontext->range.level[0]);
+                l2 = &(tcontext->range.level[0]);
+                goto mls_ops;
+            case CEXPR_L1H2:
+                l1 = &(scontext->range.level[0]);
+                l2 = &(tcontext->range.level[1]);
+                goto mls_ops;
+            case CEXPR_H1L2:
+                l1 = &(scontext->range.level[1]);
+                l2 = &(tcontext->range.level[0]);
+                goto mls_ops;
+            case CEXPR_H1H2:
+                l1 = &(scontext->range.level[1]);
+                l2 = &(tcontext->range.level[1]);
+                goto mls_ops;
+            case CEXPR_L1H1:
+                l1 = &(scontext->range.level[0]);
+                l2 = &(scontext->range.level[1]);
+                goto mls_ops;
+            case CEXPR_L2H2:
+                l1 = &(tcontext->range.level[0]);
+                l2 = &(tcontext->range.level[1]);
+                goto mls_ops;
+mls_ops:
+            switch (e->op) {
+            case CEXPR_EQ:
+                s[++sp] = mls_level_eq(l1, l2);
+                continue;
+            case CEXPR_NEQ:
+                s[++sp] = !mls_level_eq(l1, l2);
+                continue;
+            case CEXPR_DOM:
+                s[++sp] = mls_level_dom(l1, l2);
+                continue;
+            case CEXPR_DOMBY:
+                s[++sp] = mls_level_dom(l2, l1);
+                continue;
+            case CEXPR_INCOMP:
+                s[++sp] = mls_level_incomp(l2, l1);
+                continue;
+            default:
+                BUG();
+                return 0;
+            }
+            break;
+            default:
+                BUG();
+                return 0;
+            }
+
+            switch (e->op) {
+            case CEXPR_EQ:
+                s[++sp] = (val1 == val2);
+                break;
+            case CEXPR_NEQ:
+                s[++sp] = (val1 != val2);
+                break;
+            default:
+                BUG();
+                return 0;
+            }
+            break;
+        case CEXPR_NAMES:
+            if (sp == (CEXPR_MAXDEPTH-1))
+                return 0;
+            c = scontext;
+            if (e->attr & CEXPR_TARGET)
+                c = tcontext;
+            else if (e->attr & CEXPR_XTARGET) {
+                c = xcontext;
+                if (!c) {
+                    BUG();
+                    return 0;
+                }
+            }
+            if (e->attr & CEXPR_USER)
+                val1 = c->user;
+            else if (e->attr & CEXPR_ROLE)
+                val1 = c->role;
+            else if (e->attr & CEXPR_TYPE)
+                val1 = c->type;
+            else {
+                BUG();
+                return 0;
+            }
+
+            switch (e->op) {
+            case CEXPR_EQ:
+                s[++sp] = ebitmap_get_bit(&e->names, val1 - 1);
+                break;
+            case CEXPR_NEQ:
+                s[++sp] = !ebitmap_get_bit(&e->names, val1 - 1);
+                break;
+            default:
+                BUG();
+                return 0;
+            }
+            break;
+        default:
+            BUG();
+            return 0;
+        }
+    }
+
+    BUG_ON(sp != 0);
+    return s[0];
+}
+
+/*
+ * Compute access vectors based on a context structure pair for
+ * the permissions in a particular class.
+ */
+static int context_struct_compute_av(struct context *scontext,
+                     struct context *tcontext,
+                     u16 tclass,
+                     u32 requested,
+                     struct av_decision *avd)
+{
+    struct constraint_node *constraint;
+    struct role_allow *ra;
+    struct avtab_key avkey;
+    struct avtab_node *node;
+    struct class_datum *tclass_datum;
+    struct ebitmap *sattr, *tattr;
+    struct ebitmap_node *snode, *tnode;
+    unsigned int i, j;
+
+    if (!tclass || tclass > policydb.p_classes.nprim) {
+        printk(KERN_ERR "security_compute_av:  unrecognized class %d\n",
+               tclass);
+        return -EINVAL;
+    }
+    tclass_datum = policydb.class_val_to_struct[tclass - 1];
+
+    /*
+     * Initialize the access vectors to the default values.
+     */
+    avd->allowed = 0;
+    avd->decided = 0xffffffff;
+    avd->auditallow = 0;
+    avd->auditdeny = 0xffffffff;
+    avd->seqno = latest_granting;
+
+    /*
+     * If a specific type enforcement rule was defined for
+     * this permission check, then use it.
+     */
+    avkey.target_class = tclass;
+    avkey.specified = AVTAB_AV;
+    sattr = &policydb.type_attr_map[scontext->type - 1];
+    tattr = &policydb.type_attr_map[tcontext->type - 1];
+    ebitmap_for_each_bit(sattr, snode, i) {
+        if (!ebitmap_node_get_bit(snode, i))
+            continue;
+        ebitmap_for_each_bit(tattr, tnode, j) {
+            if (!ebitmap_node_get_bit(tnode, j))
+                continue;
+            avkey.source_type = i + 1;
+            avkey.target_type = j + 1;
+            for (node = avtab_search_node(&policydb.te_avtab, &avkey);
+                 node != NULL;
+                 node = avtab_search_node_next(node, avkey.specified)) {
+                if (node->key.specified == AVTAB_ALLOWED)
+                    avd->allowed |= node->datum.data;
+                else if (node->key.specified == AVTAB_AUDITALLOW)
+                    avd->auditallow |= node->datum.data;
+                else if (node->key.specified == AVTAB_AUDITDENY)
+                    avd->auditdeny &= node->datum.data;
+            }
+
+            /* Check conditional av table for additional permissions */
+            cond_compute_av(&policydb.te_cond_avtab, &avkey, avd);
+
+        }
+    }
+
+    /*
+     * Remove any permissions prohibited by a constraint (this includes
+     * the MLS policy).
+     */
+    constraint = tclass_datum->constraints;
+    while (constraint) {
+        if ((constraint->permissions & (avd->allowed)) &&
+            !constraint_expr_eval(scontext, tcontext, NULL,
+                      constraint->expr)) {
+            avd->allowed = (avd->allowed) & ~(constraint->permissions);
+        }
+        constraint = constraint->next;
+    }
+
+    /*
+     * If checking process transition permission and the
+     * role is changing, then check the (current_role, new_role)
+     * pair.
+     */
+    if (tclass == SECCLASS_DOMAIN &&
+/* removed until future dynamic domain capability
+        (avd->allowed & (DOMAIN__TRANSITION | DOMAIN__DYNTRANSITION)) &&
+*/
+        scontext->role != tcontext->role) {
+        for (ra = policydb.role_allow; ra; ra = ra->next) {
+            if (scontext->role == ra->role &&
+                tcontext->role == ra->new_role)
+                break;
+        }
+/* removed until future dynamic domain capability    
+        if (!ra)
+            avd->allowed = (avd->allowed) & ~(DOMAIN__TRANSITION |
+                                            DOMAIN__DYNTRANSITION);
+*/
+    }
+
+    return 0;
+}
+
+static int security_validtrans_handle_fail(struct context *ocontext,
+                                           struct context *ncontext,
+                                           struct context *tcontext,
+                                           u16 tclass)
+{
+    char *o = NULL, *n = NULL, *t = NULL;
+    u32 olen, nlen, tlen;
+
+    if (context_struct_to_string(ocontext, &o, &olen) < 0)
+        goto out;
+    if (context_struct_to_string(ncontext, &n, &nlen) < 0)
+        goto out;
+    if (context_struct_to_string(tcontext, &t, &tlen) < 0)
+        goto out;
+    printk("security_validate_transition:  denied for"
+              " oldcontext=%s newcontext=%s taskcontext=%s tclass=%s",
+              o, n, t, policydb.p_class_val_to_name[tclass-1]);
+out:
+    xfree(o);
+    xfree(n);
+    xfree(t);
+
+    if (!flask_enforcing)
+        return 0;
+    return -EPERM;
+}
+
+int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid,
+                                 u16 tclass)
+{
+    struct context *ocontext;
+    struct context *ncontext;
+    struct context *tcontext;
+    struct class_datum *tclass_datum;
+    struct constraint_node *constraint;
+    int rc = 0;
+
+    if (!ss_initialized)
+        return 0;
+
+    POLICY_RDLOCK;
+
+    if (!tclass || tclass > policydb.p_classes.nprim) {
+        printk(KERN_ERR "security_validate_transition:  "
+               "unrecognized class %d\n", tclass);
+        rc = -EINVAL;
+        goto out;
+    }
+    tclass_datum = policydb.class_val_to_struct[tclass - 1];
+
+    ocontext = sidtab_search(&sidtab, oldsid);
+    if (!ocontext) {
+        printk(KERN_ERR "security_validate_transition: "
+               " unrecognized SID %d\n", oldsid);
+        rc = -EINVAL;
+        goto out;
+    }
+
+    ncontext = sidtab_search(&sidtab, newsid);
+    if (!ncontext) {
+        printk(KERN_ERR "security_validate_transition: "
+               " unrecognized SID %d\n", newsid);
+        rc = -EINVAL;
+        goto out;
+    }
+
+    tcontext = sidtab_search(&sidtab, tasksid);
+    if (!tcontext) {
+        printk(KERN_ERR "security_validate_transition: "
+               " unrecognized SID %d\n", tasksid);
+        rc = -EINVAL;
+        goto out;
+    }
+
+    constraint = tclass_datum->validatetrans;
+    while (constraint) {
+        if (!constraint_expr_eval(ocontext, ncontext, tcontext,
+                                  constraint->expr)) {
+            rc = security_validtrans_handle_fail(ocontext, ncontext,
+                                                 tcontext, tclass);
+            goto out;
+        }
+        constraint = constraint->next;
+    }
+
+out:
+    POLICY_RDUNLOCK;
+    return rc;
+}
+
+/**
+ * security_compute_av - Compute access vector decisions.
+ * @ssid: source security identifier
+ * @tsid: target security identifier
+ * @tclass: target security class
+ * @requested: requested permissions
+ * @avd: access vector decisions
+ *
+ * Compute a set of access vector decisions based on the
+ * SID pair (@ssid, @tsid) for the permissions in @tclass.
+ * Return -%EINVAL if any of the parameters are invalid or %0
+ * if the access vector decisions were computed successfully.
+ */
+int security_compute_av(u32 ssid,
+            u32 tsid,
+            u16 tclass,
+            u32 requested,
+            struct av_decision *avd)
+{
+    struct context *scontext = NULL, *tcontext = NULL;
+    int rc = 0;
+
+    if (!ss_initialized) {
+        avd->allowed = 0xffffffff;
+        avd->decided = 0xffffffff;
+        avd->auditallow = 0;
+        avd->auditdeny = 0xffffffff;
+        avd->seqno = latest_granting;
+        return 0;
+    }
+
+    POLICY_RDLOCK;
+
+    scontext = sidtab_search(&sidtab, ssid);
+    if (!scontext) {
+        printk("security_compute_av:  unrecognized SID %d\n",
+               ssid);
+        rc = -EINVAL;
+        goto out;
+    }
+    tcontext = sidtab_search(&sidtab, tsid);
+    if (!tcontext) {
+        printk("security_compute_av:  unrecognized SID %d\n",
+               tsid);
+        rc = -EINVAL;
+        goto out;
+    }
+
+    rc = context_struct_compute_av(scontext, tcontext, tclass,
+                       requested, avd);
+out:
+    POLICY_RDUNLOCK;
+    return rc;
+}
+
+/*
+ * Write the security context string representation of
+ * the context structure `context' into a dynamically
+ * allocated string of the correct size.  Set `*scontext'
+ * to point to this string and set `*scontext_len' to
+ * the length of the string.
+ */
+static int context_struct_to_string(struct context *context, char **scontext, u32 *scontext_len)
+{
+    char *scontextp;
+
+    *scontext = NULL;
+    *scontext_len = 0;
+
+    /* Compute the size of the context. */
+    *scontext_len += strlen(policydb.p_user_val_to_name[context->user - 1]) + 1;
+    *scontext_len += strlen(policydb.p_role_val_to_name[context->role - 1]) + 1;
+    *scontext_len += strlen(policydb.p_type_val_to_name[context->type - 1]) + 1;
+    *scontext_len += mls_compute_context_len(context);
+
+    /* Allocate space for the context; caller must free this space. */
+    scontextp = xmalloc_array(char, *scontext_len);
+    if (!scontextp) {
+        return -ENOMEM;
+    }
+    *scontext = scontextp;
+
+    /*
+     * Copy the user name, role name and type name into the context.
+     */
+    snprintf(scontextp, *scontext_len, "%s:%s:%s",
+        policydb.p_user_val_to_name[context->user - 1],
+        policydb.p_role_val_to_name[context->role - 1],
+        policydb.p_type_val_to_name[context->type - 1]);
+    scontextp += strlen(policydb.p_user_val_to_name[context->user - 1]) +
+                 1 + strlen(policydb.p_role_val_to_name[context->role - 1]) +
+                 1 + strlen(policydb.p_type_val_to_name[context->type - 1]);
+
+    mls_sid_to_context(context, &scontextp);
+
+    *scontextp = 0;
+
+    return 0;
+}
+
+#include "initial_sid_to_string.h"
+
+/**
+ * security_sid_to_context - Obtain a context for a given SID.
+ * @sid: security identifier, SID
+ * @scontext: security context
+ * @scontext_len: length in bytes
+ *
+ * Write the string representation of the context associated with @sid
+ * into a dynamically allocated string of the correct size.  Set @scontext
+ * to point to this string and set @scontext_len to the length of the string.
+ */
+int security_sid_to_context(u32 sid, char **scontext, u32 *scontext_len)
+{
+    struct context *context;
+    int rc = 0;
+
+    if (!ss_initialized) {
+        if (sid <= SECINITSID_NUM) {
+            char *scontextp;
+
+            *scontext_len = strlen(initial_sid_to_string[sid]) + 1;
+            scontextp = xmalloc_array(char, *scontext_len);
+            strlcpy(scontextp, initial_sid_to_string[sid], *scontext_len);
+            *scontext = scontextp;
+            goto out;
+        }
+        printk(KERN_ERR "security_sid_to_context:  called before initial "
+               "load_policy on unknown SID %d\n", sid);
+        rc = -EINVAL;
+        goto out;
+    }
+    POLICY_RDLOCK;
+    context = sidtab_search(&sidtab, sid);
+    if (!context) {
+        printk(KERN_ERR "security_sid_to_context:  unrecognized SID "
+               "%d\n", sid);
+        rc = -EINVAL;
+        goto out_unlock;
+    }
+    rc = context_struct_to_string(context, scontext, scontext_len);
+out_unlock:
+    POLICY_RDUNLOCK;
+out:
+    return rc;
+
+}
+
+static int security_context_to_sid_core(char *scontext, u32 scontext_len, u32 *sid, u32 def_sid)
+{
+    char *scontext2;
+    struct context context;
+    struct role_datum *role;
+    struct type_datum *typdatum;
+    struct user_datum *usrdatum;
+    char *scontextp, *p, oldc;
+    int rc = 0;
+
+    if (!ss_initialized) {
+        int i;
+
+        for (i = 1; i < SECINITSID_NUM; i++) {
+            if (!strcmp(initial_sid_to_string[i], scontext)) {
+                *sid = i;
+                goto out;
+            }
+        }
+        *sid = SECINITSID_XEN;
+        goto out;
+    }
+    *sid = SECSID_NULL;
+
+    /* Copy the string so that we can modify the copy as we parse it.
+       The string should already by null terminated, but we append a
+       null suffix to the copy to avoid problems with the existing
+       attr package, which doesn't view the null terminator as part
+       of the attribute value. */
+    scontext2 = xmalloc_array(char, scontext_len+1);
+    if (!scontext2) {
+        rc = -ENOMEM;
+        goto out;
+    }
+    memcpy(scontext2, scontext, scontext_len);
+    scontext2[scontext_len] = 0;
+
+    context_init(&context);
+    *sid = SECSID_NULL;
+
+    POLICY_RDLOCK;
+
+    /* Parse the security context. */
+
+    rc = -EINVAL;
+    scontextp = (char *) scontext2;
+
+    /* Extract the user. */
+    p = scontextp;
+    while (*p && *p != ':')
+        p++;
+
+    if (*p == 0)
+        goto out_unlock;
+
+    *p++ = 0;
+
+    usrdatum = hashtab_search(policydb.p_users.table, scontextp);
+    if (!usrdatum)
+        goto out_unlock;
+
+    context.user = usrdatum->value;
+
+    /* Extract role. */
+    scontextp = p;
+    while (*p && *p != ':')
+        p++;
+
+    if (*p == 0)
+        goto out_unlock;
+
+    *p++ = 0;
+
+    role = hashtab_search(policydb.p_roles.table, scontextp);
+    if (!role)
+        goto out_unlock;
+    context.role = role->value;
+
+    /* Extract type. */
+    scontextp = p;
+    while (*p && *p != ':')
+        p++;
+    oldc = *p;
+    *p++ = 0;
+
+    typdatum = hashtab_search(policydb.p_types.table, scontextp);
+    if (!typdatum)
+        goto out_unlock;
+
+    context.type = typdatum->value;
+
+    rc = mls_context_to_sid(oldc, &p, &context, &sidtab, def_sid);
+    if (rc)
+        goto out_unlock;
+
+    if ((p - scontext2) < scontext_len) {
+        rc = -EINVAL;
+        goto out_unlock;
+    }
+
+    /* Check the validity of the new context. */
+    if (!policydb_context_isvalid(&policydb, &context)) {
+        rc = -EINVAL;
+        goto out_unlock;
+    }
+    /* Obtain the new sid. */
+    rc = sidtab_context_to_sid(&sidtab, &context, sid);
+out_unlock:
+    POLICY_RDUNLOCK;
+    context_destroy(&context);
+    xfree(scontext2);
+out:
+    return rc;
+}
+
+/**
+ * security_context_to_sid - Obtain a SID for a given security context.
+ * @scontext: security context
+ * @scontext_len: length in bytes
+ * @sid: security identifier, SID
+ *
+ * Obtains a SID associated with the security context that
+ * has the string representation specified by @scontext.
+ * Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient
+ * memory is available, or 0 on success.
+ */
+int security_context_to_sid(char *scontext, u32 scontext_len, u32 *sid)
+{
+    return security_context_to_sid_core(scontext, scontext_len,
+                                        sid, SECSID_NULL);
+}
+
+/**
+ * security_context_to_sid_default - Obtain a SID for a given security context,
+ * falling back to specified default if needed.
+ *
+ * @scontext: security context
+ * @scontext_len: length in bytes
+ * @sid: security identifier, SID
+ * @def_sid: default SID to assign on errror
+ *
+ * Obtains a SID associated with the security context that
+ * has the string representation specified by @scontext.
+ * The default SID is passed to the MLS layer to be used to allow
+ * kernel labeling of the MLS field if the MLS field is not present
+ * (for upgrading to MLS without full relabel).
+ * Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient
+ * memory is available, or 0 on success.
+ */
+int security_context_to_sid_default(char *scontext, u32 scontext_len, u32 *sid, u32 def_sid)
+{
+    return security_context_to_sid_core(scontext, scontext_len,
+                                        sid, def_sid);
+}
+
+static int compute_sid_handle_invalid_context(
+    struct context *scontext,
+    struct context *tcontext,
+    u16 tclass,
+    struct context *newcontext)
+{
+    char *s = NULL, *t = NULL, *n = NULL;
+    u32 slen, tlen, nlen;
+
+    if (context_struct_to_string(scontext, &s, &slen) < 0)
+        goto out;
+    if (context_struct_to_string(tcontext, &t, &tlen) < 0)
+        goto out;
+    if (context_struct_to_string(newcontext, &n, &nlen) < 0)
+        goto out;
+    printk("security_compute_sid:  invalid context %s"
+          " for scontext=%s"
+          " tcontext=%s"
+          " tclass=%s",
+          n, s, t, policydb.p_class_val_to_name[tclass-1]);
+out:
+    xfree(s);
+    xfree(t);
+    xfree(n);
+    if (!flask_enforcing)
+        return 0;
+    return -EACCES;
+}
+
+static int security_compute_sid(u32 ssid,
+                u32 tsid,
+                u16 tclass,
+                u32 specified,
+                u32 *out_sid)
+{
+    struct context *scontext = NULL, *tcontext = NULL, newcontext;
+    struct role_trans *roletr = NULL;
+    struct avtab_key avkey;
+    struct avtab_datum *avdatum;
+    struct avtab_node *node;
+    int rc = 0;
+
+    if (!ss_initialized) {
+        switch (tclass) {
+        case SECCLASS_DOMAIN:
+            *out_sid = ssid;
+            break;
+        default:
+            *out_sid = tsid;
+            break;
+        }
+        goto out;
+    }
+
+    POLICY_RDLOCK;
+
+    scontext = sidtab_search(&sidtab, ssid);
+    if (!scontext) {
+        printk(KERN_ERR "security_compute_sid:  unrecognized SID %d\n",
+               ssid);
+        rc = -EINVAL;
+        goto out_unlock;
+    }
+    tcontext = sidtab_search(&sidtab, tsid);
+    if (!tcontext) {
+        printk(KERN_ERR "security_compute_sid:  unrecognized SID %d\n",
+               tsid);
+        rc = -EINVAL;
+        goto out_unlock;
+    }
+
+    context_init(&newcontext);
+
+    /* Set the user identity. */
+    switch (specified) {
+    case AVTAB_TRANSITION:
+    case AVTAB_CHANGE:
+        /* Use the process user identity. */
+        newcontext.user = scontext->user;
+        break;
+    case AVTAB_MEMBER:
+        /* Use the related object owner. */
+        newcontext.user = tcontext->user;
+        break;
+    }
+
+    /* Set the role and type to default values. */
+    switch (tclass) {
+    case SECCLASS_DOMAIN:
+        /* Use the current role and type of process. */
+        newcontext.role = scontext->role;
+        newcontext.type = scontext->type;
+        break;
+    default:
+        /* Use the well-defined object role. */
+        newcontext.role = OBJECT_R_VAL;
+        /* Use the type of the related object. */
+        newcontext.type = tcontext->type;
+    }
+
+    /* Look for a type transition/member/change rule. */
+    avkey.source_type = scontext->type;
+    avkey.target_type = tcontext->type;
+    avkey.target_class = tclass;
+    avkey.specified = specified;
+    avdatum = avtab_search(&policydb.te_avtab, &avkey);
+
+    /* If no permanent rule, also check for enabled conditional rules */
+    if(!avdatum) {
+        node = avtab_search_node(&policydb.te_cond_avtab, &avkey);
+        for (; node != NULL; node = avtab_search_node_next(node, specified)) {
+            if (node->key.specified & AVTAB_ENABLED) {
+                avdatum = &node->datum;
+                break;
+            }
+        }
+    }
+
+    if (avdatum) {
+        /* Use the type from the type transition/member/change rule. */
+        newcontext.type = avdatum->data;
+    }
+
+    /* Check for class-specific changes. */
+    switch (tclass) {
+    case SECCLASS_DOMAIN:
+        if (specified & AVTAB_TRANSITION) {
+            /* Look for a role transition rule. */
+            for (roletr = policydb.role_tr; roletr;
+                 roletr = roletr->next) {
+                if (roletr->role == scontext->role &&
+                    roletr->type == tcontext->type) {
+                    /* Use the role transition rule. */
+                    newcontext.role = roletr->new_role;
+                    break;
+                }
+            }
+        }
+        break;
+    default:
+        break;
+    }
+
+    /* Set the MLS attributes.
+       This is done last because it may allocate memory. */
+    rc = mls_compute_sid(scontext, tcontext, tclass, specified, &newcontext);
+    if (rc)
+        goto out_unlock;
+
+    /* Check the validity of the context. */
+    if (!policydb_context_isvalid(&policydb, &newcontext)) {
+        rc = compute_sid_handle_invalid_context(scontext,
+                            tcontext,
+                            tclass,
+                            &newcontext);
+        if (rc)
+            goto out_unlock;
+    }
+    /* Obtain the sid for the context. */
+    rc = sidtab_context_to_sid(&sidtab, &newcontext, out_sid);
+out_unlock:
+    POLICY_RDUNLOCK;
+    context_destroy(&newcontext);
+out:
+    return rc;
+}
+
+/**
+ * security_transition_sid - Compute the SID for a new subject/object.
+ * @ssid: source security identifier
+ * @tsid: target security identifier
+ * @tclass: target security class
+ * @out_sid: security identifier for new subject/object
+ *
+ * Compute a SID to use for labeling a new subject or object in the
+ * class @tclass based on a SID pair (@ssid, @tsid).
+ * Return -%EINVAL if any of the parameters are invalid, -%ENOMEM
+ * if insufficient memory is available, or %0 if the new SID was
+ * computed successfully.
+ */
+int security_transition_sid(u32 ssid,
+                u32 tsid,
+                u16 tclass,
+                u32 *out_sid)
+{
+    return security_compute_sid(ssid, tsid, tclass, AVTAB_TRANSITION, out_sid);
+}
+
+/**
+ * security_member_sid - Compute the SID for member selection.
+ * @ssid: source security identifier
+ * @tsid: target security identifier
+ * @tclass: target security class
+ * @out_sid: security identifier for selected member
+ *
+ * Compute a SID to use when selecting a member of a polyinstantiated
+ * object of class @tclass based on a SID pair (@ssid, @tsid).
+ * Return -%EINVAL if any of the parameters are invalid, -%ENOMEM
+ * if insufficient memory is available, or %0 if the SID was
+ * computed successfully.
+ */
+int security_member_sid(u32 ssid,
+            u32 tsid,
+            u16 tclass,
+            u32 *out_sid)
+{
+    return security_compute_sid(ssid, tsid, tclass, AVTAB_MEMBER, out_sid);
+}
+
+/**
+ * security_change_sid - Compute the SID for object relabeling.
+ * @ssid: source security identifier
+ * @tsid: target security identifier
+ * @tclass: target security class
+ * @out_sid: security identifier for selected member
+ *
+ * Compute a SID to use for relabeling an object of class @tclass
+ * based on a SID pair (@ssid, @tsid).
+ * Return -%EINVAL if any of the parameters are invalid, -%ENOMEM
+ * if insufficient memory is available, or %0 if the SID was
+ * computed successfully.
+ */
+int security_change_sid(u32 ssid,
+            u32 tsid,
+            u16 tclass,
+            u32 *out_sid)
+{
+    return security_compute_sid(ssid, tsid, tclass, AVTAB_CHANGE, out_sid);
+}
+
+/*
+ * Verify that each permission that is defined under the
+ * existing policy is still defined with the same value
+ * in the new policy.
+ */
+static int validate_perm(void *key, void *datum, void *p)
+{
+    struct hashtab *h;
+    struct perm_datum *perdatum, *perdatum2;
+    int rc = 0;
+
+
+    h = p;
+    perdatum = datum;
+
+    perdatum2 = hashtab_search(h, key);
+    if (!perdatum2) {
+        printk(KERN_ERR "security:  permission %s disappeared",
+               (char *)key);
+        rc = -ENOENT;
+        goto out;
+    }
+    if (perdatum->value != perdatum2->value) {
+        printk(KERN_ERR "security:  the value of permission %s changed",
+               (char *)key);
+        rc = -EINVAL;
+    }
+out:
+    return rc;
+}
+
+/*
+ * Verify that each class that is defined under the
+ * existing policy is still defined with the same
+ * attributes in the new policy.
+ */
+static int validate_class(void *key, void *datum, void *p)
+{
+    struct policydb *newp;
+    struct class_datum *cladatum, *cladatum2;
+    int rc;
+
+    newp = p;
+    cladatum = datum;
+
+    cladatum2 = hashtab_search(newp->p_classes.table, key);
+    if (!cladatum2) {
+        printk(KERN_ERR "security:  class %s disappeared\n",
+               (char *)key);
+        rc = -ENOENT;
+        goto out;
+    }
+    if (cladatum->value != cladatum2->value) {
+        printk(KERN_ERR "security:  the value of class %s changed\n",
+               (char *)key);
+        rc = -EINVAL;
+        goto out;
+    }
+    if ((cladatum->comdatum && !cladatum2->comdatum) ||
+        (!cladatum->comdatum && cladatum2->comdatum)) {
+        printk(KERN_ERR "security:  the inherits clause for the access "
+               "vector definition for class %s changed\n", (char *)key);
+        rc = -EINVAL;
+        goto out;
+    }
+    if (cladatum->comdatum) {
+        rc = hashtab_map(cladatum->comdatum->permissions.table, validate_perm,
+                         cladatum2->comdatum->permissions.table);
+        if (rc) {
+            printk(" in the access vector definition for class "
+                   "%s\n", (char *)key);
+            goto out;
+        }
+    }
+    rc = hashtab_map(cladatum->permissions.table, validate_perm,
+                     cladatum2->permissions.table);
+    if (rc)
+        printk(" in access vector definition for class %s\n",
+               (char *)key);
+out:
+    return rc;
+}
+
+/* Clone the SID into the new SID table. */
+static int clone_sid(u32 sid,
+             struct context *context,
+             void *arg)
+{
+    struct sidtab *s = arg;
+
+    return sidtab_insert(s, sid, context);
+}
+
+static inline int convert_context_handle_invalid_context(struct context *context)
+{
+    int rc = 0;
+
+    if (flask_enforcing) {
+        rc = -EINVAL;
+    } else {
+        char *s;
+        u32 len;
+
+        context_struct_to_string(context, &s, &len);
+        printk(KERN_ERR "security:  context %s is invalid\n", s);
+        xfree(s);
+    }
+    return rc;
+}
+
+struct convert_context_args {
+    struct policydb *oldp;
+    struct policydb *newp;
+};
+
+/*
+ * Convert the values in the security context
+ * structure `c' from the values specified
+ * in the policy `p->oldp' to the values specified
+ * in the policy `p->newp'.  Verify that the
+ * context is valid under the new policy.
+ */
+static int convert_context(u32 key,
+               struct context *c,
+               void *p)
+{
+    struct convert_context_args *args;
+    struct context oldc;
+    struct role_datum *role;
+    struct type_datum *typdatum;
+    struct user_datum *usrdatum;
+    char *s;
+    u32 len;
+    int rc;
+
+    args = p;
+
+    rc = context_cpy(&oldc, c);
+    if (rc)
+        goto out;
+
+    rc = -EINVAL;
+
+    /* Convert the user. */
+    usrdatum = hashtab_search(args->newp->p_users.table,
+                              args->oldp->p_user_val_to_name[c->user - 1]);
+    if (!usrdatum) {
+        goto bad;
+    }
+    c->user = usrdatum->value;
+
+    /* Convert the role. */
+    role = hashtab_search(args->newp->p_roles.table,
+                          args->oldp->p_role_val_to_name[c->role - 1]);
+    if (!role) {
+        goto bad;
+    }
+    c->role = role->value;
+
+    /* Convert the type. */
+    typdatum = hashtab_search(args->newp->p_types.table,
+                              args->oldp->p_type_val_to_name[c->type - 1]);
+    if (!typdatum) {
+        goto bad;
+    }
+    c->type = typdatum->value;
+
+    rc = mls_convert_context(args->oldp, args->newp, c);
+    if (rc)
+        goto bad;
+
+    /* Check the validity of the new context. */
+    if (!policydb_context_isvalid(args->newp, c)) {
+        rc = convert_context_handle_invalid_context(&oldc);
+        if (rc)
+            goto bad;
+    }
+
+    context_destroy(&oldc);
+out:
+    return rc;
+bad:
+    context_struct_to_string(&oldc, &s, &len);
+    context_destroy(&oldc);
+    printk(KERN_ERR "security:  invalidating context %s\n", s);
+    xfree(s);
+    goto out;
+}
+
+extern void flask_complete_init(void);
+
+/**
+ * security_load_policy - Load a security policy configuration.
+ * @data: binary policy data
+ * @len: length of data in bytes
+ *
+ * Load a new set of security policy configuration data,
+ * validate it and convert the SID table as necessary.
+ * This function will flush the access vector cache after
+ * loading the new policy.
+ */
+int security_load_policy(void *data, size_t len)
+{
+    struct policydb oldpolicydb, newpolicydb;
+    struct sidtab oldsidtab, newsidtab;
+    struct convert_context_args args;
+    u32 seqno;
+    int rc = 0;
+    struct policy_file file = { data, len }, *fp = &file;
+
+    LOAD_LOCK;
+
+    if (!ss_initialized) {
+        if (policydb_read(&policydb, fp)) {
+            LOAD_UNLOCK;
+            return -EINVAL;
+        }
+        if (policydb_load_isids(&policydb, &sidtab)) {
+            LOAD_UNLOCK;
+            policydb_destroy(&policydb);
+            return -EINVAL;
+        }
+        policydb_loaded_version = policydb.policyvers;
+        ss_initialized = 1;
+        seqno = ++latest_granting;
+        LOAD_UNLOCK;
+        avc_ss_reset(seqno);
+        return 0;
+    }
+
+#if 0
+    sidtab_hash_eval(&sidtab, "sids");
+#endif
+
+    if (policydb_read(&newpolicydb, fp)) {
+        LOAD_UNLOCK;
+        return -EINVAL;
+    }
+
+    sidtab_init(&newsidtab);
+
+    /* Verify that the existing classes did not change. */
+    if (hashtab_map(policydb.p_classes.table, validate_class, &newpolicydb)) {
+        printk(KERN_ERR "security:  the definition of an existing "
+               "class changed\n");
+        rc = -EINVAL;
+        goto err;
+    }
+
+    /* Clone the SID table. */
+    sidtab_shutdown(&sidtab);
+    if (sidtab_map(&sidtab, clone_sid, &newsidtab)) {
+        rc = -ENOMEM;
+        goto err;
+    }
+
+    /* Convert the internal representations of contexts
+       in the new SID table and remove invalid SIDs. */
+    args.oldp = &policydb;
+    args.newp = &newpolicydb;
+    sidtab_map_remove_on_error(&newsidtab, convert_context, &args);
+
+    /* Save the old policydb and SID table to free later. */
+    memcpy(&oldpolicydb, &policydb, sizeof policydb);
+    sidtab_set(&oldsidtab, &sidtab);
+
+    /* Install the new policydb and SID table. */
+    POLICY_WRLOCK;
+    memcpy(&policydb, &newpolicydb, sizeof policydb);
+    sidtab_set(&sidtab, &newsidtab);
+    seqno = ++latest_granting;
+    policydb_loaded_version = policydb.policyvers;
+    POLICY_WRUNLOCK;
+    LOAD_UNLOCK;
+
+    /* Free the old policydb and SID table. */
+    policydb_destroy(&oldpolicydb);
+    sidtab_destroy(&oldsidtab);
+
+    avc_ss_reset(seqno);
+
+    return 0;
+
+err:
+    LOAD_UNLOCK;
+    sidtab_destroy(&newsidtab);
+    policydb_destroy(&newpolicydb);
+    return rc;
+
+}
+
+/**
+ * security_pirq_sid - Obtain the SID for a physical irq.
+ * @pirq: physical irq
+ * @out_sid: security identifier
+ */
+int security_pirq_sid(int pirq, u32 *out_sid)
+{
+    int rc = 0;
+    struct ocontext *c;
+
+    POLICY_RDLOCK;
+
+    c = policydb.ocontexts[OCON_PIRQ];
+    
+    while (c) {
+        if (c->u.pirq == pirq)
+            break;
+        c = c->next;
+    }
+
+    if (c) {
+        if (!c->sid[0]) {
+            rc = sidtab_context_to_sid(&sidtab, &c->context[0], &c->sid[0]);
+            if (rc)
+                goto out;
+        }
+        *out_sid = c->sid[0];
+    } else {
+        *out_sid = SECINITSID_PIRQ;
+    }
+
+out:
+    POLICY_RDUNLOCK;
+    return rc;
+}
+
+/**
+ * security_iomem_sid - Obtain the SID for a page of iomem.
+ * @mfn: iomem mfn
+ * @out_sid: security identifier
+ */
+int security_iomem_sid(unsigned long mfn, u32 *out_sid)
+{
+    struct ocontext *c;
+    int rc = 0;
+
+    POLICY_RDLOCK;
+
+    c = policydb.ocontexts[OCON_IOMEM];
+    while (c) {
+        if (c->u.iomem == mfn)
+            break;
+        c = c->next;
+    }
+
+    if (c) {
+        if (!c->sid[0]) {
+            rc = sidtab_context_to_sid(&sidtab, &c->context[0], &c->sid[0]);
+            if (rc)
+                goto out;
+        }
+        *out_sid = c->sid[0];
+    } else {
+        *out_sid = SECINITSID_IOMEM;
+    }
+
+out:
+    POLICY_RDUNLOCK;
+    return rc;
+}
+
+/**
+ * security_ioport_sid - Obtain the SID for an ioport.
+ * @ioport: ioport
+ * @out_sid: security identifier
+ */
+int security_ioport_sid(u32 ioport, u32 *out_sid)
+{
+    struct ocontext *c;
+    int rc = 0;
+
+    POLICY_RDLOCK;
+
+    c = policydb.ocontexts[OCON_IOPORT];
+    while (c) {
+        if (c->u.ioport == ioport)
+            break;
+        c = c->next;
+    }
+
+    if (c) {
+        if (!c->sid[0]) {
+            rc = sidtab_context_to_sid(&sidtab, &c->context[0], &c->sid[0]);
+            if (rc)
+                goto out;
+        }
+        *out_sid = c->sid[0];
+    } else {
+        *out_sid = SECINITSID_IOPORT;
+    }
+
+out:
+    POLICY_RDUNLOCK;
+    return rc;
+}
+
+#define SIDS_NEL 25
+
+/**
+ * security_get_user_sids - Obtain reachable SIDs for a user.
+ * @fromsid: starting SID
+ * @username: username
+ * @sids: array of reachable SIDs for user
+ * @nel: number of elements in @sids
+ *
+ * Generate the set of SIDs for legal security contexts
+ * for a given user that can be reached by @fromsid.
+ * Set *@sids to point to a dynamically allocated
+ * array containing the set of SIDs.  Set *@nel to the
+ * number of elements in the array.
+ */
+
+int security_get_user_sids(u32 fromsid,
+                       char *username,
+               u32 **sids,
+               u32 *nel)
+{
+    struct context *fromcon, usercon;
+    u32 *mysids, *mysids2, sid;
+    u32 mynel = 0, maxnel = SIDS_NEL;
+    struct user_datum *user;
+    struct role_datum *role;
+    struct av_decision avd;
+    struct ebitmap_node *rnode, *tnode;
+    int rc = 0, i, j;
+
+    if (!ss_initialized) {
+        *sids = NULL;
+        *nel = 0;
+        goto out;
+    }
+
+    POLICY_RDLOCK;
+
+    fromcon = sidtab_search(&sidtab, fromsid);
+    if (!fromcon) {
+        rc = -EINVAL;
+        goto out_unlock;
+    }
+
+    user = hashtab_search(policydb.p_users.table, username);
+    if (!user) {
+        rc = -EINVAL;
+        goto out_unlock;
+    }
+    usercon.user = user->value;
+
+    mysids = xmalloc_array(u32, maxnel);
+    if (!mysids) {
+        rc = -ENOMEM;
+        goto out_unlock;
+    }
+    memset(mysids, 0, maxnel*sizeof(*mysids));
+
+    ebitmap_for_each_bit(&user->roles, rnode, i) {
+        if (!ebitmap_node_get_bit(rnode, i))
+            continue;
+        role = policydb.role_val_to_struct[i];
+        usercon.role = i+1;
+        ebitmap_for_each_bit(&role->types, tnode, j) {
+            if (!ebitmap_node_get_bit(tnode, j))
+                continue;
+            usercon.type = j+1;
+
+            if (mls_setup_user_range(fromcon, user, &usercon))
+                continue;
+
+            rc = context_struct_compute_av(fromcon, &usercon,
+                               SECCLASS_DOMAIN,
+                               DOMAIN__TRANSITION,
+                               &avd);
+            if (rc ||  !(avd.allowed & DOMAIN__TRANSITION))
+                continue;
+            rc = sidtab_context_to_sid(&sidtab, &usercon, &sid);
+            if (rc) {
+                xfree(mysids);
+                goto out_unlock;
+            }
+            if (mynel < maxnel) {
+                mysids[mynel++] = sid;
+            } else {
+                maxnel += SIDS_NEL;
+                mysids2 = xmalloc_array(u32, maxnel);
+                if (!mysids2) {
+                    rc = -ENOMEM;
+                    xfree(mysids);
+                    goto out_unlock;
+                }
+                memset(mysids2, 0, maxnel*sizeof(*mysids2));
+                memcpy(mysids2, mysids, mynel * sizeof(*mysids2));
+                xfree(mysids);
+                mysids = mysids2;
+                mysids[mynel++] = sid;
+            }
+        }
+    }
+
+    *sids = mysids;
+    *nel = mynel;
+
+out_unlock:
+    POLICY_RDUNLOCK;
+out:
+    return rc;
+}
+
+int security_get_bools(int *len, char ***names, int **values)
+{
+    int i, rc = -ENOMEM;
+
+    POLICY_RDLOCK;
+    *names = NULL;
+    *values = NULL;
+
+    *len = policydb.p_bools.nprim;
+    if (!*len) {
+        rc = 0;
+        goto out;
+    }
+
+    *names = (char**)xmalloc_array(char*, *len);
+    if (!*names)
+        goto err;
+    memset(*names, 0, sizeof(char*) * *len);
+
+    *values = (int*)xmalloc_array(int, *len);
+    if (!*values)
+        goto err;
+
+    for (i = 0; i < *len; i++) {
+        size_t name_len;
+        (*values)[i] = policydb.bool_val_to_struct[i]->state;
+        name_len = strlen(policydb.p_bool_val_to_name[i]) + 1;
+        (*names)[i] = (char*)xmalloc_array(char, name_len);
+        if (!(*names)[i])
+            goto err;
+        strlcpy((*names)[i], policydb.p_bool_val_to_name[i], name_len);
+        (*names)[i][name_len - 1] = 0;
+    }
+    rc = 0;
+out:
+    POLICY_RDUNLOCK;
+    return rc;
+err:
+    if (*names) {
+        for (i = 0; i < *len; i++)
+            xfree((*names)[i]);
+    }
+    xfree(*values);
+    goto out;
+}
+
+
+int security_set_bools(int len, int *values)
+{
+    int i, rc = 0;
+    int lenp, seqno = 0;
+    struct cond_node *cur;
+
+    POLICY_WRLOCK;
+
+    lenp = policydb.p_bools.nprim;
+    if (len != lenp) {
+        rc = -EFAULT;
+        goto out;
+    }
+
+    printk(KERN_INFO "security: committed booleans { ");
+    for (i = 0; i < len; i++) {
+        if (values[i]) {
+            policydb.bool_val_to_struct[i]->state = 1;
+        } else {
+            policydb.bool_val_to_struct[i]->state = 0;
+        }
+        if (i != 0)
+            printk(", ");
+        printk("%s:%d", policydb.p_bool_val_to_name[i],
+               policydb.bool_val_to_struct[i]->state);
+    }
+    printk(" }\n");
+
+    for (cur = policydb.cond_list; cur != NULL; cur = cur->next) {
+        rc = evaluate_cond_node(&policydb, cur);
+        if (rc)
+            goto out;
+    }
+
+    seqno = ++latest_granting;
+
+out:
+    POLICY_WRUNLOCK;
+    if (!rc) {
+        avc_ss_reset(seqno);
+    }
+    return rc;
+}
+
+int security_get_bool_value(int bool)
+{
+    int rc = 0;
+    int len;
+
+    POLICY_RDLOCK;
+
+    len = policydb.p_bools.nprim;
+    if (bool >= len) {
+        rc = -EFAULT;
+        goto out;
+    }
+
+    rc = policydb.bool_val_to_struct[bool]->state;
+out:
+    POLICY_RDUNLOCK;
+    return rc;
+}
diff -r 62b752969edf -r 2b79cd115561 xen/xsm/flask/ss/services.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/ss/services.h	Mon May 07 14:51:17 2007 -0400
@@ -0,0 +1,15 @@
+/*
+ * Implementation of the security services.
+ *
+ * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
+ */
+#ifndef _SS_SERVICES_H_
+#define _SS_SERVICES_H_
+
+#include "policydb.h"
+#include "sidtab.h"
+
+extern struct policydb policydb;
+
+#endif    /* _SS_SERVICES_H_ */
+
diff -r 62b752969edf -r 2b79cd115561 xen/xsm/flask/ss/sidtab.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/ss/sidtab.c	Mon May 07 14:51:17 2007 -0400
@@ -0,0 +1,307 @@
+/*
+ * Implementation of the SID table type.
+ *
+ * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
+ */
+ 
+/* Ported to Xen 3.0, George Coker, <gscoker@alpha.ncsc.mil> */
+ 
+#include <xen/lib.h>
+#include <xen/xmalloc.h>
+#include <xen/errno.h>
+#include <xen/spinlock.h>
+#include "flask.h"
+#include "security.h"
+#include "sidtab.h"
+
+#define SIDTAB_HASH(sid) \
+(sid & SIDTAB_HASH_MASK)
+
+#define INIT_SIDTAB_LOCK(s) spin_lock_init(&s->lock)
+#define SIDTAB_LOCK(s, x) spin_lock_irqsave(&s->lock, x)
+#define SIDTAB_UNLOCK(s, x) spin_unlock_irqrestore(&s->lock, x)
+
+int sidtab_init(struct sidtab *s)
+{
+    int i;
+
+    s->htable = (void *)xmalloc_array(struct sidtab_node, SIDTAB_SIZE);
+    if (!s->htable)
+        return -ENOMEM;
+    for (i = 0; i < SIDTAB_SIZE; i++)
+        s->htable[i] = NULL;
+    s->nel = 0;
+    s->next_sid = 1;
+    s->shutdown = 0;
+    INIT_SIDTAB_LOCK(s);
+    return 0;
+}
+
+int sidtab_insert(struct sidtab *s, u32 sid, struct context *context)
+{
+    int hvalue, rc = 0;
+    struct sidtab_node *prev, *cur, *newnode;
+
+    if (!s) {
+        rc = -ENOMEM;
+        goto out;
+    }
+
+    hvalue = SIDTAB_HASH(sid);
+    prev = NULL;
+    cur = s->htable[hvalue];
+    while (cur != NULL && sid > cur->sid) {
+        prev = cur;
+        cur = cur->next;
+    }
+
+    if (cur && sid == cur->sid) {
+        rc = -EEXIST;
+        goto out;
+    }
+
+    newnode = xmalloc(struct sidtab_node);
+    if (newnode == NULL) {
+        rc = -ENOMEM;
+        goto out;
+    }
+    newnode->sid = sid;
+    if (context_cpy(&newnode->context, context)) {
+        xfree(newnode);
+        rc = -ENOMEM;
+        goto out;
+    }
+
+    if (prev) {
+        newnode->next = prev->next;
+        wmb();
+        prev->next = newnode;
+    } else {
+        newnode->next = s->htable[hvalue];
+        wmb();
+        s->htable[hvalue] = newnode;
+    }
+
+    s->nel++;
+    if (sid >= s->next_sid)
+        s->next_sid = sid + 1;
+out:
+    return rc;
+}
+
+struct context *sidtab_search(struct sidtab *s, u32 sid)
+{
+    int hvalue;
+    struct sidtab_node *cur;
+
+    if (!s)
+        return NULL;
+
+    hvalue = SIDTAB_HASH(sid);
+    cur = s->htable[hvalue];
+    while (cur != NULL && sid > cur->sid)
+        cur = cur->next;
+
+    if (cur == NULL || sid != cur->sid) {
+        /* Remap invalid SIDs to the unlabeled SID. */
+        sid = SECINITSID_UNLABELED;
+        hvalue = SIDTAB_HASH(sid);
+        cur = s->htable[hvalue];
+        while (cur != NULL && sid > cur->sid)
+            cur = cur->next;
+        if (!cur || sid != cur->sid)
+            return NULL;
+    }
+
+    return &cur->context;
+}
+
+int sidtab_map(struct sidtab *s,
+           int (*apply) (u32 sid,
+                 struct context *context,
+                 void *args),
+           void *args)
+{
+    int i, rc = 0;
+    struct sidtab_node *cur;
+
+    if (!s)
+        goto out;
+
+    for (i = 0; i < SIDTAB_SIZE; i++) {
+        cur = s->htable[i];
+        while (cur != NULL) {
+            rc = apply(cur->sid, &cur->context, args);
+            if (rc)
+                goto out;
+            cur = cur->next;
+        }
+    }
+out:
+    return rc;
+}
+
+void sidtab_map_remove_on_error(struct sidtab *s,
+                int (*apply) (u32 sid,
+                          struct context *context,
+                          void *args),
+                void *args)
+{
+    int i, ret;
+    struct sidtab_node *last, *cur, *temp;
+
+    if (!s)
+        return;
+
+    for (i = 0; i < SIDTAB_SIZE; i++) {
+        last = NULL;
+        cur = s->htable[i];
+        while (cur != NULL) {
+            ret = apply(cur->sid, &cur->context, args);
+            if (ret) {
+                if (last) {
+                    last->next = cur->next;
+                } else {
+                    s->htable[i] = cur->next;
+                }
+
+                temp = cur;
+                cur = cur->next;
+                context_destroy(&temp->context);
+                xfree(temp);
+                s->nel--;
+            } else {
+                last = cur;
+                cur = cur->next;
+            }
+        }
+    }
+
+    return;
+}
+
+static inline u32 sidtab_search_context(struct sidtab *s,
+                          struct context *context)
+{
+    int i;
+    struct sidtab_node *cur;
+
+    for (i = 0; i < SIDTAB_SIZE; i++) {
+        cur = s->htable[i];
+        while (cur != NULL) {
+            if (context_cmp(&cur->context, context))
+                return cur->sid;
+            cur = cur->next;
+        }
+    }
+    return 0;
+}
+
+int sidtab_context_to_sid(struct sidtab *s,
+              struct context *context,
+              u32 *out_sid)
+{
+    u32 sid;
+    int ret = 0;
+    unsigned long flags;
+
+    *out_sid = SECSID_NULL;
+
+    sid = sidtab_search_context(s, context);
+    if (!sid) {
+        SIDTAB_LOCK(s, flags);
+        /* Rescan now that we hold the lock. */
+        sid = sidtab_search_context(s, context);
+        if (sid)
+            goto unlock_out;
+        /* No SID exists for the context.  Allocate a new one. */
+        if (s->next_sid == UINT_MAX || s->shutdown) {
+            ret = -ENOMEM;
+            goto unlock_out;
+        }
+        sid = s->next_sid++;
+        ret = sidtab_insert(s, sid, context);
+        if (ret)
+            s->next_sid--;
+unlock_out:
+        SIDTAB_UNLOCK(s, flags);
+    }
+
+    if (ret)
+        return ret;
+
+    *out_sid = sid;
+    return 0;
+}
+
+void sidtab_hash_eval(struct sidtab *h, char *tag)
+{
+    int i, chain_len, slots_used, max_chain_len;
+    struct sidtab_node *cur;
+
+    slots_used = 0;
+    max_chain_len = 0;
+    for (i = 0; i < SIDTAB_SIZE; i++) {
+        cur = h->htable[i];
+        if (cur) {
+            slots_used++;
+            chain_len = 0;
+            while (cur) {
+                chain_len++;
+                cur = cur->next;
+            }
+
+            if (chain_len > max_chain_len)
+                max_chain_len = chain_len;
+        }
+    }
+
+    printk(KERN_INFO "%s:  %d entries and %d/%d buckets used, longest "
+           "chain length %d\n", tag, h->nel, slots_used, SIDTAB_SIZE,
+           max_chain_len);
+}
+
+void sidtab_destroy(struct sidtab *s)
+{
+    int i;
+    struct sidtab_node *cur, *temp;
+
+    if (!s)
+        return;
+
+    for (i = 0; i < SIDTAB_SIZE; i++) {
+        cur = s->htable[i];
+        while (cur != NULL) {
+            temp = cur;
+            cur = cur->next;
+            context_destroy(&temp->context);
+            xfree(temp);
+        }
+        s->htable[i] = NULL;
+    }
+    xfree(s->htable);
+    s->htable = NULL;
+    s->nel = 0;
+    s->next_sid = 1;
+}
+
+void sidtab_set(struct sidtab *dst, struct sidtab *src)
+{
+    unsigned long flags;
+
+    SIDTAB_LOCK(src, flags);
+    dst->htable = src->htable;
+    dst->nel = src->nel;
+    dst->next_sid = src->next_sid;
+    dst->shutdown = 0;
+    SIDTAB_UNLOCK(src, flags);
+}
+
+void sidtab_shutdown(struct sidtab *s)
+{
+    unsigned long flags;
+
+    SIDTAB_LOCK(s, flags);
+    s->shutdown = 1;
+    SIDTAB_UNLOCK(s, flags);
+}
diff -r 62b752969edf -r 2b79cd115561 xen/xsm/flask/ss/sidtab.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/ss/sidtab.h	Mon May 07 14:51:17 2007 -0400
@@ -0,0 +1,63 @@
+/*
+ * A security identifier table (sidtab) is a hash table
+ * of security context structures indexed by SID value.
+ *
+ * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
+ */
+
+/* Ported to Xen 3.0, George Coker, <gscoker@alpha.ncsc.mil> */
+
+#ifndef _SS_SIDTAB_H_
+#define _SS_SIDTAB_H_
+
+#include "context.h"
+#include <xen/spinlock.h>
+
+struct sidtab_node {
+    u32 sid;        /* security identifier */
+    struct context context;    /* security context structure */
+    struct sidtab_node *next;
+};
+
+#define SIDTAB_HASH_BITS 7
+#define SIDTAB_HASH_BUCKETS (1 << SIDTAB_HASH_BITS)
+#define SIDTAB_HASH_MASK (SIDTAB_HASH_BUCKETS-1)
+
+#define SIDTAB_SIZE SIDTAB_HASH_BUCKETS
+
+struct sidtab {
+    struct sidtab_node **htable;
+    unsigned int nel;    /* number of elements */
+    unsigned int next_sid;    /* next SID to allocate */
+    unsigned char shutdown;
+    spinlock_t lock;
+};
+
+int sidtab_init(struct sidtab *s);
+int sidtab_insert(struct sidtab *s, u32 sid, struct context *context);
+struct context *sidtab_search(struct sidtab *s, u32 sid);
+
+int sidtab_map(struct sidtab *s,
+           int (*apply) (u32 sid,
+                 struct context *context,
+                 void *args),
+           void *args);
+
+void sidtab_map_remove_on_error(struct sidtab *s,
+                int (*apply) (u32 sid,
+                          struct context *context,
+                          void *args),
+                void *args);
+
+int sidtab_context_to_sid(struct sidtab *s,
+              struct context *context,
+              u32 *sid);
+
+void sidtab_hash_eval(struct sidtab *h, char *tag);
+void sidtab_destroy(struct sidtab *s);
+void sidtab_set(struct sidtab *dst, struct sidtab *src);
+void sidtab_shutdown(struct sidtab *s);
+
+#endif    /* _SS_SIDTAB_H_ */
+
+
diff -r 62b752969edf -r 2b79cd115561 xen/xsm/flask/ss/symtab.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/ss/symtab.c	Mon May 07 14:51:17 2007 -0400
@@ -0,0 +1,47 @@
+/*
+ * Implementation of the symbol table type.
+ *
+ * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
+ */
+ 
+/* Ported to Xen 3.0, George Coker, <gscoker@alpha.ncsc.mil> */
+
+#include <xen/lib.h>
+#include <xen/xmalloc.h>
+#include <xen/string.h>
+#include <xen/errno.h>
+#include "symtab.h"
+
+static unsigned int symhash(struct hashtab *h, void *key)
+{
+    char *p, *keyp;
+    unsigned int size;
+    unsigned int val;
+
+    val = 0;
+    keyp = key;
+    size = strlen(keyp);
+    for (p = keyp; (p - keyp) < size; p++)
+        val = (val << 4 | (val >> (8*sizeof(unsigned int)-4))) ^ (*p);
+    return val & (h->size - 1);
+}
+
+static int symcmp(struct hashtab *h, void *key1, void *key2)
+{
+    char *keyp1, *keyp2;
+
+    keyp1 = key1;
+    keyp2 = key2;
+    return strcmp(keyp1, keyp2);
+}
+
+
+int symtab_init(struct symtab *s, unsigned int size)
+{
+    s->table = hashtab_create(symhash, symcmp, size);
+    if (!s->table)
+        return -1;
+    s->nprim = 0;
+    return 0;
+}
+
diff -r 62b752969edf -r 2b79cd115561 xen/xsm/flask/ss/symtab.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/ss/symtab.h	Mon May 07 14:51:17 2007 -0400
@@ -0,0 +1,23 @@
+/*
+ * A symbol table (symtab) maintains associations between symbol
+ * strings and datum values.  The type of the datum values
+ * is arbitrary.  The symbol table type is implemented
+ * using the hash table type (hashtab).
+ *
+ * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
+ */
+#ifndef _SS_SYMTAB_H_
+#define _SS_SYMTAB_H_
+
+#include "hashtab.h"
+
+struct symtab {
+    struct hashtab *table;    /* hash table (keyed on a string) */
+    u32 nprim;        /* number of primary names in table */
+};
+
+int symtab_init(struct symtab *s, unsigned int size);
+
+#endif    /* _SS_SYMTAB_H_ */
+
+

[-- Attachment #3: Type: text/plain, Size: 138 bytes --]

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xensource.com
http://lists.xensource.com/xen-devel

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [Xense-devel][PATCH][2/4] Xen Securtiy Modules: FLASK
  2007-05-07 21:41 [Xense-devel][PATCH][2/4] Xen Securtiy Modules: FLASK George S. Coker, II
@ 2007-05-07 23:24 ` Chris Wright
  2007-05-08  3:15 ` Mark Williamson
  1 sibling, 0 replies; 5+ messages in thread
From: Chris Wright @ 2007-05-07 23:24 UTC (permalink / raw)
  To: George S. Coker, II; +Cc: xen-devel, xense-devel

And to drill down into module based on core evtchn stuff...

> +static int flask_alloc_security_evtchn(struct evtchn *chn)
> +{
> +    int i;
> +    struct evtchn_security_struct *esec;
> +
> +    for ( i = 0; i < EVTCHNS_PER_BUCKET; i++ ) {
> +        esec = xmalloc(struct evtchn_security_struct);
> +    

As I mentioned in 1/4 review, this should be done at higher level.

> +        if (!esec)
> +            return -ENOMEM;

In fact, this is a leak because there's no unwind, and bucket
is freed if this error is encountered.

> +        
> +        memset(esec, 0, sizeof(struct evtchn_security_struct));
> +    
> +        esec->chn = &chn[i];
> +        esec->sid = SECINITSID_UNLABELED;
> +
> +        (&chn[i])->ssid = esec;
> +    }
> +    
> +    return 0;    
> +}
> +
> +static void flask_free_security_evtchn(struct evtchn *chn)
> +{
> +    int i;
> +    struct evtchn_security_struct *esec;
> +
> +    if (!chn)
> +        return;
> +            
> +    for ( i = 0; i < EVTCHNS_PER_BUCKET; i++ ) {
> +        esec = (&chn[i])->ssid;

This is not a bucket, because this _is_ done at a higher level.  Thus,
writing on and freeing random memory.

> +    
> +        if (!esec)
> +            continue;
> +        
> +        (&chn[i])->ssid = NULL;
> +        xfree(esec);
> +    }
> +
> +}

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [Xense-devel][PATCH][2/4] Xen Securtiy Modules: FLASK
  2007-05-07 21:41 [Xense-devel][PATCH][2/4] Xen Securtiy Modules: FLASK George S. Coker, II
  2007-05-07 23:24 ` Chris Wright
@ 2007-05-08  3:15 ` Mark Williamson
  1 sibling, 0 replies; 5+ messages in thread
From: Mark Williamson @ 2007-05-08  3:15 UTC (permalink / raw)
  To: xen-devel; +Cc: George S. Coker, II, xense-devel

Hi George,

More coding style nits from my automated pedantry script.

> Updates in this patch set include:
>     - reintroduction of rcu locking support in security cache
>     - track xsm changes
>
> Signed-off-by: George Coker <gscoker@alpha.ncsc.mil>

I've not attached the style checker output this one gave me because most of 
it's fairly homogeneous can be fixed by a regexp find/replace.  Issues 
identified:

Most Xen code spaces out the if conditional brackets like so:
    if ( !node_ptr )
if boolean operators are used in the expression they're also surrounded by 
space.  There are a number of places where Linux-style spacing is used 
instead.

Braces are always on their own line in the Xen code...  There are a number of 
places where this patch puts them on a line with another statement, K&R / 
Linux style.

I also found a number of instances of trailing whitespace, and of tabs being 
used for indentation instead of spaces.

All these things can probably be fixed using sed / emacs / etc so I've not 
attached the rather verbose output from the checker...  Please let me know if 
I can help speed things up and I'll send you more information.

Cheers,
Mark

-- 
Dave: Just a question. What use is a unicyle with no seat?  And no pedals!
Mark: To answer a question with a question: What use is a skateboard?
Dave: Skateboards have wheels.
Mark: My wheel has a wheel!

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [Xense-devel][PATCH][2/4] Xen Securtiy Modules: FLASK
  2007-06-04 19:06 George S. Coker, II
@ 2007-06-14 18:14 ` George S. Coker, II
  0 siblings, 0 replies; 5+ messages in thread
From: George S. Coker, II @ 2007-06-14 18:14 UTC (permalink / raw)
  To: xen-devel; +Cc: xense-devel

[-- Attachment #1: Type: text/plain, Size: 662 bytes --]

The previously posted flask xsm patch was a dupe of the xsm tools patch.
The correct patch is attached to this e-mail.

The XSM patches apply cleanly to 15200:bd3d6b4c52ec as well as to the
tip 15249:93f77a5a8437.

Signed-off-by: George Coker <gscoker@alpha.ncsc.mil>

On Mon, 2007-06-04 at 15:06 -0400, George S. Coker, II wrote:
> Updates in this patch set include:
>     - coding style cleanups
>     - track xsm changes
>     - remove patch cruft
> 
> Signed-off-by: George Coker <gscoker@alpha.ncsc.mil>
> 
> 
> _______________________________________________
> Xen-devel mailing list
> Xen-devel@lists.xensource.com
> http://lists.xensource.com/xen-devel


[-- Attachment #2: flask-xsm-060407-xen-15200.diff --]
[-- Type: text/x-patch, Size: 305956 bytes --]

diff -r cb2ecf48cf80 -r 8ae246493872 Config.mk
--- a/Config.mk	Mon Jun 04 11:06:10 2007 -0400
+++ b/Config.mk	Mon Jun 04 11:06:52 2007 -0400
@@ -75,6 +75,14 @@ CFLAGS += $(foreach i, $(EXTRA_INCLUDES)
 #Enable XSM security module.  Enabling XSM requires selection of an 
 #XSM security module.
 XSM_ENABLE ?= n
+ifeq ($(XSM_ENABLE),y)
+FLASK_ENABLE ?= n
+ifeq ($(FLASK_ENABLE),y)
+FLASK_DEVELOP ?= y
+FLASK_BOOTPARAM ?= y
+FLASK_AVC_STATS ?= y
+endif
+endif
 
 # If ACM_SECURITY = y, then the access control module is compiled
 # into Xen and the policy type can be set by the boot policy file
diff -r cb2ecf48cf80 -r 8ae246493872 xen/Rules.mk
--- a/xen/Rules.mk	Mon Jun 04 11:06:10 2007 -0400
+++ b/xen/Rules.mk	Mon Jun 04 11:06:52 2007 -0400
@@ -51,13 +51,17 @@ ALL_OBJS-$(ACM_SECURITY) += $(BASEDIR)/a
 ALL_OBJS-$(ACM_SECURITY) += $(BASEDIR)/acm/built_in.o
 ALL_OBJS-y               += $(BASEDIR)/arch/$(TARGET_ARCH)/built_in.o
 
-CFLAGS-y               += -g -D__XEN__
-CFLAGS-$(XSM_ENABLE)   += -DXSM_ENABLE
-CFLAGS-$(ACM_SECURITY) += -DACM_SECURITY
-CFLAGS-$(verbose)      += -DVERBOSE
-CFLAGS-$(crash_debug)  += -DCRASH_DEBUG
-CFLAGS-$(perfc)        += -DPERF_COUNTERS
-CFLAGS-$(perfc_arrays) += -DPERF_ARRAYS
+CFLAGS-y                  += -g -D__XEN__
+CFLAGS-$(XSM_ENABLE)      += -DXSM_ENABLE
+CFLAGS-$(FLASK_ENABLE)    += -DFLASK_ENABLE -DXSM_MAGIC=0xf97cff8c
+CFLAGS-$(FLASK_DEVELOP)   += -DFLASK_DEVELOP
+CFLAGS-$(FLASK_BOOTPARAM) += -DFLASK_BOOTPARAM
+CFLAGS-$(FLASK_AVC_STATS) += -DFLASK_AVC_STATS
+CFLAGS-$(ACM_SECURITY)    += -DACM_SECURITY
+CFLAGS-$(verbose)         += -DVERBOSE
+CFLAGS-$(crash_debug)     += -DCRASH_DEBUG
+CFLAGS-$(perfc)           += -DPERF_COUNTERS
+CFLAGS-$(perfc_arrays)    += -DPERF_ARRAYS
 
 ifneq ($(max_phys_cpus),)
 CFLAGS-y               += -DMAX_PHYS_CPUS=$(max_phys_cpus)
diff -r cb2ecf48cf80 -r 8ae246493872 xen/common/vsprintf.c
--- a/xen/common/vsprintf.c	Mon Jun 04 11:06:10 2007 -0400
+++ b/xen/common/vsprintf.c	Mon Jun 04 11:06:52 2007 -0400
@@ -513,6 +513,257 @@ EXPORT_SYMBOL(vscnprintf);
 EXPORT_SYMBOL(vscnprintf);
 
 /**
+ * vsscanf - Unformat a buffer into a list of arguments
+ * @buf:	input buffer
+ * @fmt:	format of buffer
+ * @args:	arguments
+ */
+int vsscanf(const char * buf, const char * fmt, va_list args)
+{
+    const char *str = buf;
+    const char *next;
+    char digit;
+    int num = 0;
+    int qualifier;
+    int base;
+    int field_width;
+    int is_sign = 0;
+
+    while(*fmt && *str)
+    {
+        /* skip any white space in format */
+        /* white space in format matchs any amount of
+         * white space, including none, in the input.
+         */
+        if (isspace(*fmt))
+        {
+            while (isspace(*fmt))
+                ++fmt;
+            while (isspace(*str))
+                ++str;
+        }
+
+        /* anything that is not a conversion must match exactly */
+        if (*fmt != '%' && *fmt)
+        {
+            if (*fmt++ != *str++)
+                break;
+            continue;
+        }
+
+        if (!*fmt)
+            break;
+        ++fmt;
+
+        /* skip this conversion.
+         * advance both strings to next white space
+         */
+        if (*fmt == '*')
+        {
+            while (!isspace(*fmt) && *fmt)
+                fmt++;
+            while (!isspace(*str) && *str)
+                str++;
+            continue;
+        }
+
+        /* get field width */
+        field_width = -1;
+		if (isdigit(*fmt))
+            field_width = skip_atoi(&fmt);
+
+        /* get conversion qualifier */
+        qualifier = -1;
+        if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || *fmt == 'Z' 
+                                                                || *fmt == 'z')
+        {
+            qualifier = *fmt++;
+            if (unlikely(qualifier == *fmt))
+            {
+                if (qualifier == 'h')
+                {
+                    qualifier = 'H';
+                    fmt++;
+                }
+                else if (qualifier == 'l')
+                {
+                    qualifier = 'L';
+                    fmt++;
+                }
+            }
+        }
+        base = 10;
+        is_sign = 0;
+
+        if (!*fmt || !*str)
+            break;
+
+        switch(*fmt++)
+        {
+            case 'c':
+            {
+                char *s = (char *) va_arg(args,char*);
+                if (field_width == -1)
+                    field_width = 1;
+                do
+                {
+                    *s++ = *str++;
+                }
+                while (--field_width > 0 && *str);
+                num++;
+            }
+            continue;
+            case 's':
+            {
+                char *s = (char *) va_arg(args, char *);
+                if(field_width == -1)
+                    field_width = INT_MAX;
+                /* first, skip leading white space in buffer */
+                while (isspace(*str))
+                    str++;
+
+                /* now copy until next white space */
+                while (*str && !isspace(*str) && field_width--)
+                {
+                    *s++ = *str++;
+                }
+                *s = '\0';
+                num++;
+            }
+            continue;
+            case 'n':
+            /* return number of characters read so far */
+            {
+                int *i = (int *)va_arg(args,int*);
+                *i = str - buf;
+            }
+            continue;
+            case 'o':
+                base = 8;
+            break;
+            case 'x':
+            case 'X':
+                base = 16;
+            break;
+            case 'i':
+                base = 0;
+            case 'd':
+                is_sign = 1;
+            case 'u':
+            break;
+            case '%':
+                /* looking for '%' in str */
+                if (*str++ != '%') 
+                    return num;
+            continue;
+            default:
+                /* invalid format; stop here */
+                return num;
+        }
+
+        /* have some sort of integer conversion.
+         * first, skip white space in buffer.
+         */
+        while (isspace(*str))
+            str++;
+
+        digit = *str;
+        if (is_sign && digit == '-')
+            digit = *(str + 1);
+
+        if (!digit || (base == 16 && !isxdigit(digit))
+                || (base == 10 && !isdigit(digit))
+                || (base == 8 && (!isdigit(digit) || digit > '7'))
+                || (base == 0 && !isdigit(digit)))
+            break;
+
+        switch(qualifier)
+        {
+            case 'H':	/* that's 'hh' in format */
+                if (is_sign)
+                {
+                    signed char *s = (signed char *) va_arg(args,signed char *);
+                    *s = (signed char) simple_strtol(str,&next,base);
+                }
+                else
+                {
+                    unsigned char *s = (unsigned char *) 
+                                                va_arg(args, unsigned char *);
+                    *s = (unsigned char) simple_strtoul(str, &next, base);
+                }
+            break;
+            case 'h':
+                if (is_sign)
+                {
+                    short *s = (short *) va_arg(args,short *);
+                    *s = (short) simple_strtol(str,&next,base);
+                }
+                else
+                {
+                    unsigned short *s = (unsigned short *) 
+                                                va_arg(args, unsigned short *);
+                    *s = (unsigned short) simple_strtoul(str, &next, base);
+                }
+            break;
+            case 'l':
+                if (is_sign)
+                {
+                    long *l = (long *) va_arg(args,long *);
+                    *l = simple_strtol(str,&next,base);
+                }
+                else
+                {
+                    unsigned long *l = (unsigned long*) 
+                                                    va_arg(args,unsigned long*);
+                    *l = simple_strtoul(str,&next,base);
+                }
+            break;
+            case 'L':
+                if (is_sign)
+                {
+                    long long *l = (long long*) va_arg(args,long long *);
+                    *l = simple_strtoll(str,&next,base);
+                }
+                else
+                {
+                    unsigned long long *l = (unsigned long long*) 
+                                            va_arg(args,unsigned long long*);
+                    *l = simple_strtoull(str,&next,base);
+                }
+            break;
+            case 'Z':
+            case 'z':
+            {
+                size_t *s = (size_t*) va_arg(args,size_t*);
+                *s = (size_t) simple_strtoul(str,&next,base);
+            }
+            break;
+            default:
+                if (is_sign)
+                {
+                    int *i = (int *) va_arg(args, int*);
+                    *i = (int) simple_strtol(str,&next,base);
+                }
+                else
+                {
+                    unsigned int *i = (unsigned int*) 
+                                                    va_arg(args, unsigned int*);
+                    *i = (unsigned int) simple_strtoul(str,&next,base);
+                }
+            break;
+        }
+        num++;
+
+        if (!next)
+            break;
+        str = next;
+    }
+	return num;
+}
+
+EXPORT_SYMBOL(vsscanf);
+
+/**
  * snprintf - Format a string and place it in a buffer
  * @buf: The buffer to place the result into
  * @size: The size of the buffer, including the trailing null space
@@ -561,6 +812,25 @@ int scnprintf(char * buf, size_t size, c
 }
 EXPORT_SYMBOL(scnprintf);
 
+/**
+ * sscanf - Unformat a buffer into a list of arguments
+ * @buf:	input buffer
+ * @fmt:	formatting of buffer
+ * @...:	resulting arguments
+ */
+int sscanf(const char * buf, const char * fmt, ...)
+{
+    va_list args;
+    int i;
+
+    va_start(args,fmt);
+    i = vsscanf(buf,fmt,args);
+    va_end(args);
+    return i;
+}
+
+EXPORT_SYMBOL(sscanf);
+
 /*
  * Local variables:
  * mode: C
diff -r cb2ecf48cf80 -r 8ae246493872 xen/include/public/flask_op.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/include/public/flask_op.h	Mon Jun 04 11:06:52 2007 -0400
@@ -0,0 +1,44 @@
+/*
+ *  This file contains the flask_op hypercall commands and definitions.
+ *
+ *  Author:  George Coker, <gscoker@alpha.ncsc.mil>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2,
+ *  as published by the Free Software Foundation.
+ */
+
+#ifndef __FLASK_OP_H__
+#define __FLASK_OP_H__
+
+#define FLASK_LOAD              1
+#define FLASK_GETENFORCE        2
+#define FLASK_SETENFORCE        3
+#define FLASK_CONTEXT_TO_SID    4
+#define FLASK_SID_TO_CONTEXT    5
+#define FLASK_ACCESS            6
+#define FLASK_CREATE            7
+#define FLASK_RELABEL           8
+#define FLASK_USER              9
+#define FLASK_POLICYVERS        10
+#define FLASK_GETBOOL           11
+#define FLASK_SETBOOL           12
+#define FLASK_COMMITBOOLS       13
+#define FLASK_MLS               14
+#define FLASK_DISABLE           15
+#define FLASK_GETAVC_THRESHOLD  16
+#define FLASK_SETAVC_THRESHOLD  17
+#define FLASK_AVC_HASHSTATS     18
+#define FLASK_AVC_CACHESTATS    19
+#define FLASK_MEMBER            20
+
+typedef struct flask_op {
+    int   size;
+    char *buf;
+} flask_op_t;
+
+DEFINE_XEN_GUEST_HANDLE(flask_op_t);
+
+long do_flask_op (int cmd, XEN_GUEST_HANDLE(xsm_op_t) u_flask_op);
+
+#endif
diff -r cb2ecf48cf80 -r 8ae246493872 xen/include/xen/lib.h
--- a/xen/include/xen/lib.h	Mon Jun 04 11:06:10 2007 -0400
+++ b/xen/include/xen/lib.h	Mon Jun 04 11:06:52 2007 -0400
@@ -75,6 +75,10 @@ extern int scnprintf(char * buf, size_t 
     __attribute__ ((format (printf, 3, 4)));
 extern int vscnprintf(char *buf, size_t size, const char *fmt, va_list args)
     __attribute__ ((format (printf, 3, 0)));
+extern int sscanf(const char * buf, const char * fmt, ...)
+    __attribute__ ((format (scanf, 2, 3)));
+extern int vsscanf(const char * buf, const char * fmt, va_list args)
+    __attribute__ ((format (scanf, 2, 0)));
 
 long simple_strtol(
     const char *cp,const char **endp, unsigned int base);
diff -r cb2ecf48cf80 -r 8ae246493872 xen/xsm/Makefile
--- a/xen/xsm/Makefile	Mon Jun 04 11:06:10 2007 -0400
+++ b/xen/xsm/Makefile	Mon Jun 04 11:06:52 2007 -0400
@@ -3,3 +3,5 @@ ifeq ($(XSM_ENABLE),y)
 ifeq ($(XSM_ENABLE),y)
 obj-y += dummy.o
 endif
+
+subdir-$(FLASK_ENABLE) += flask
diff -r cb2ecf48cf80 -r 8ae246493872 xen/xsm/flask/Makefile
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/Makefile	Mon Jun 04 11:06:52 2007 -0400
@@ -0,0 +1,7 @@
+obj-y += avc.o
+obj-y += hooks.o
+obj-y += flask_op.o
+
+subdir-y += ss
+
+CFLAGS += -I./include
diff -r cb2ecf48cf80 -r 8ae246493872 xen/xsm/flask/avc.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/avc.c	Mon Jun 04 11:06:52 2007 -0400
@@ -0,0 +1,817 @@
+/*
+ * Implementation of the kernel access vector cache (AVC).
+ *
+ * Authors:  Stephen Smalley, <sds@epoch.ncsc.mil>
+ *           James Morris <jmorris@redhat.com>
+ *
+ * Update:   KaiGai, Kohei <kaigai@ak.jp.nec.com>
+ *     Replaced the avc_lock spinlock by RCU.
+ *
+ * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License version 2,
+ *      as published by the Free Software Foundation.
+ */
+ 
+/* Ported to Xen 3.0, George Coker, <gscoker@alpha.ncsc.mil> */
+ 
+#include <xen/lib.h>
+#include <xen/xmalloc.h>
+#include <xen/types.h>
+#include <xen/list.h>
+#include <xen/spinlock.h>
+#include <xen/prefetch.h>
+#include <xen/kernel.h>
+#include <xen/sched.h>
+#include <xen/init.h>
+#include <xen/rcupdate.h>
+#include <asm/atomic.h>
+#include <asm/current.h>
+
+#include "avc.h"
+#include "avc_ss.h"
+
+static const struct av_perm_to_string
+{
+    u16 tclass;
+    u32 value;
+    const char *name;
+} av_perm_to_string[] = {
+#define S_(c, v, s) { c, v, s },
+#include "av_perm_to_string.h"
+#undef S_
+};
+
+static const char *class_to_string[] = {
+#define S_(s) s,
+#include "class_to_string.h"
+#undef S_
+};
+
+#define TB_(s) static const char * s [] = {
+#define TE_(s) };
+#define S_(s) s,
+#include "common_perm_to_string.h"
+#undef TB_
+#undef TE_
+#undef S_
+
+static const struct av_inherit
+{
+    u16 tclass;
+    const char **common_pts;
+    u32 common_base;
+} av_inherit[] = {
+#define S_(c, i, b) { c, common_##i##_perm_to_string, b },
+#include "av_inherit.h"
+#undef S_
+};
+
+#define AVC_CACHE_SLOTS            512
+#define AVC_DEF_CACHE_THRESHOLD        512
+#define AVC_CACHE_RECLAIM        16
+
+#ifdef FLASK_AVC_STATS
+#define avc_cache_stats_incr(field)                 \
+do {                                \
+    __get_cpu_var(avc_cache_stats).field++;        \
+} while (0)
+#else
+#define avc_cache_stats_incr(field)    do {} while (0)
+#endif
+
+struct avc_entry {
+    u32            ssid;
+    u32            tsid;
+    u16            tclass;
+    struct av_decision    avd;
+    atomic_t        used;    /* used recently */
+};
+
+struct avc_node {
+    struct avc_entry    ae;
+    struct list_head    list;
+    struct rcu_head     rhead;
+};
+
+struct avc_cache {
+    struct list_head    slots[AVC_CACHE_SLOTS];
+    spinlock_t        slots_lock[AVC_CACHE_SLOTS]; /* lock for writes */
+    atomic_t        lru_hint;    /* LRU hint for reclaim scan */
+    atomic_t        active_nodes;
+    u32            latest_notif;    /* latest revocation notification */
+};
+
+struct avc_callback_node {
+    int (*callback) (u32 event, u32 ssid, u32 tsid,
+                     u16 tclass, u32 perms,
+                     u32 *out_retained);
+    u32 events;
+    u32 ssid;
+    u32 tsid;
+    u16 tclass;
+    u32 perms;
+    struct avc_callback_node *next;
+};
+
+/* Exported via Flask hypercall */
+unsigned int avc_cache_threshold = AVC_DEF_CACHE_THRESHOLD;
+
+#ifdef FLASK_AVC_STATS
+DEFINE_PER_CPU(struct avc_cache_stats, avc_cache_stats) = { 0 };
+#endif
+
+static struct avc_cache avc_cache;
+static struct avc_callback_node *avc_callbacks;
+
+static inline int avc_hash(u32 ssid, u32 tsid, u16 tclass)
+{
+    return (ssid ^ (tsid<<2) ^ (tclass<<4)) & (AVC_CACHE_SLOTS - 1);
+}
+
+/**
+ * avc_dump_av - Display an access vector in human-readable form.
+ * @tclass: target security class
+ * @av: access vector
+ */
+static void avc_dump_av(u16 tclass, u32 av)
+{
+    const char **common_pts = NULL;
+    u32 common_base = 0;
+    int i, i2, perm;
+
+    if ( av == 0 )
+    {
+        printk(" null");
+        return;
+    }
+
+    for ( i = 0; i < ARRAY_SIZE(av_inherit); i++ )
+    {
+        if (av_inherit[i].tclass == tclass)
+        {
+            common_pts = av_inherit[i].common_pts;
+            common_base = av_inherit[i].common_base;
+            break;
+        }
+    }
+
+    printk(" {");
+    i = 0;
+    perm = 1;
+    while ( perm < common_base )
+    {
+        if (perm & av)
+        {
+            printk(" %s", common_pts[i]);
+            av &= ~perm;
+        }
+        i++;
+        perm <<= 1;
+    }
+
+    while ( i < sizeof(av) * 8 )
+    {
+        if ( perm & av )
+        {
+            for ( i2 = 0; i2 < ARRAY_SIZE(av_perm_to_string); i2++ )
+            {
+                if ( (av_perm_to_string[i2].tclass == tclass) &&
+                    (av_perm_to_string[i2].value == perm) )
+                    break;
+            }
+            if ( i2 < ARRAY_SIZE(av_perm_to_string) )
+            {
+                printk(" %s", av_perm_to_string[i2].name);
+                av &= ~perm;
+            }
+        }
+        i++;
+        perm <<= 1;
+    }
+
+    if ( av )
+        printk(" 0x%x", av);
+
+    printk(" }");
+}
+
+/**
+ * avc_dump_query - Display a SID pair and a class in human-readable form.
+ * @ssid: source security identifier
+ * @tsid: target security identifier
+ * @tclass: target security class
+ */
+static void avc_dump_query(u32 ssid, u32 tsid, u16 tclass)
+{
+    int rc;
+    char *scontext;
+    u32 scontext_len;
+
+    rc = security_sid_to_context(ssid, &scontext, &scontext_len);
+    if ( rc )
+        printk("ssid=%d", ssid);
+    else
+    {
+        printk("scontext=%s", scontext);
+        xfree(scontext);
+    }
+
+    rc = security_sid_to_context(tsid, &scontext, &scontext_len);
+    if ( rc )
+        printk(" tsid=%d", tsid);
+    else
+    {
+        printk(" tcontext=%s", scontext);
+        xfree(scontext);
+    }
+    printk("\n");
+    printk("tclass=%s", class_to_string[tclass]);
+}
+
+/**
+ * avc_init - Initialize the AVC.
+ *
+ * Initialize the access vector cache.
+ */
+void __init avc_init(void)
+{
+    int i;
+
+    for ( i = 0; i < AVC_CACHE_SLOTS; i++ )
+    {
+        INIT_LIST_HEAD(&avc_cache.slots[i]);
+        spin_lock_init(&avc_cache.slots_lock[i]);
+    }
+    atomic_set(&avc_cache.active_nodes, 0);
+    atomic_set(&avc_cache.lru_hint, 0);
+
+    printk("AVC INITIALIZED\n");
+}
+
+int avc_get_hash_stats(char *page)
+{
+    int i, chain_len, max_chain_len, slots_used;
+    struct avc_node *node;
+
+    rcu_read_lock();
+
+    slots_used = 0;
+    max_chain_len = 0;
+    for ( i = 0; i < AVC_CACHE_SLOTS; i++ )
+    {
+        if ( !list_empty(&avc_cache.slots[i]) )
+        {
+            slots_used++;
+            chain_len = 0;
+            list_for_each_entry_rcu(node, &avc_cache.slots[i], list)
+                chain_len++;
+            if ( chain_len > max_chain_len )
+                max_chain_len = chain_len;
+        }
+    }
+
+    rcu_read_unlock();
+    
+    return snprintf(page, PAGE_SIZE, "entries: %d\nbuckets used: %d/%d\n"
+                                "longest chain: %d\n",
+                                atomic_read(&avc_cache.active_nodes),
+                                slots_used, AVC_CACHE_SLOTS, max_chain_len);
+}
+
+static void avc_node_free(struct rcu_head *rhead)
+{
+    struct avc_node *node = container_of(rhead, struct avc_node, rhead);
+    xfree(node);
+    avc_cache_stats_incr(frees);
+}
+
+static void avc_node_delete(struct avc_node *node)
+{
+    list_del_rcu(&node->list);
+    call_rcu(&node->rhead, avc_node_free);
+    atomic_dec(&avc_cache.active_nodes);
+}
+
+static void avc_node_kill(struct avc_node *node)
+{
+    xfree(node);
+    avc_cache_stats_incr(frees);
+    atomic_dec(&avc_cache.active_nodes);
+}
+
+static void avc_node_replace(struct avc_node *new, struct avc_node *old)
+{
+    list_replace_rcu(&old->list, &new->list);
+    call_rcu(&old->rhead, avc_node_free);
+    atomic_dec(&avc_cache.active_nodes);
+}
+
+static inline int avc_reclaim_node(void)
+{
+    struct avc_node *node;
+    int hvalue, try, ecx;
+	unsigned long flags;
+
+    for ( try = 0, ecx = 0; try < AVC_CACHE_SLOTS; try++ )
+    {
+        atomic_inc(&avc_cache.lru_hint);
+        hvalue =  atomic_read(&avc_cache.lru_hint) & (AVC_CACHE_SLOTS - 1);
+
+		spin_lock_irqsave(&avc_cache.slots_lock[hvalue], flags);
+
+        list_for_each_entry(node, &avc_cache.slots[hvalue], list)
+        {
+            if ( atomic_dec_and_test(&node->ae.used) )
+            {
+                /* Recently Unused */
+                avc_node_delete(node);
+                avc_cache_stats_incr(reclaims);
+                ecx++;
+                if ( ecx >= AVC_CACHE_RECLAIM )
+                {
+					spin_unlock_irqrestore(&avc_cache.slots_lock[hvalue], flags);
+                    goto out;
+                }
+            }
+        }
+		spin_unlock_irqrestore(&avc_cache.slots_lock[hvalue], flags);
+    }    
+out:
+    return ecx;
+}
+
+static struct avc_node *avc_alloc_node(void)
+{
+    struct avc_node *node;
+
+    node = xmalloc(struct avc_node);
+    if (!node)
+        goto out;
+
+    memset(node, 0, sizeof(*node));
+    INIT_RCU_HEAD(&node->rhead);
+    INIT_LIST_HEAD(&node->list);
+    atomic_set(&node->ae.used, 1);
+    avc_cache_stats_incr(allocations);
+
+    atomic_inc(&avc_cache.active_nodes);
+    if ( atomic_read(&avc_cache.active_nodes) > avc_cache_threshold )
+        avc_reclaim_node();
+
+out:
+    return node;
+}
+
+static void avc_node_populate(struct avc_node *node, u32 ssid, u32 tsid, u16 tclass, struct avc_entry *ae)
+{
+    node->ae.ssid = ssid;
+    node->ae.tsid = tsid;
+    node->ae.tclass = tclass;
+    memcpy(&node->ae.avd, &ae->avd, sizeof(node->ae.avd));
+}
+
+static inline struct avc_node *avc_search_node(u32 ssid, u32 tsid, u16 tclass)
+{
+    struct avc_node *node, *ret = NULL;
+    int hvalue;
+
+    hvalue = avc_hash(ssid, tsid, tclass);
+    list_for_each_entry_rcu(node, &avc_cache.slots[hvalue], list)
+    {
+        if ( ssid == node->ae.ssid && tclass == node->ae.tclass && 
+                                                        tsid == node->ae.tsid )
+        {
+            ret = node;
+            break;
+        }
+    }
+
+    if ( ret == NULL )
+    {
+        /* cache miss */
+        goto out;
+    }
+
+    /* cache hit */
+    if ( atomic_read(&ret->ae.used) != 1 )
+        atomic_set(&ret->ae.used, 1);
+out:
+    return ret;
+}
+
+/**
+ * avc_lookup - Look up an AVC entry.
+ * @ssid: source security identifier
+ * @tsid: target security identifier
+ * @tclass: target security class
+ * @requested: requested permissions, interpreted based on @tclass
+ *
+ * Look up an AVC entry that is valid for the
+ * @requested permissions between the SID pair
+ * (@ssid, @tsid), interpreting the permissions
+ * based on @tclass.  If a valid AVC entry exists,
+ * then this function return the avc_node.
+ * Otherwise, this function returns NULL.
+ */
+static struct avc_node *avc_lookup(u32 ssid, u32 tsid, u16 tclass, u32 requested)
+{
+    struct avc_node *node;
+
+    avc_cache_stats_incr(lookups);
+    node = avc_search_node(ssid, tsid, tclass);
+
+    if ( node && ((node->ae.avd.decided & requested) == requested) )
+    {
+        avc_cache_stats_incr(hits);
+        goto out;
+    }
+
+    node = NULL;
+    avc_cache_stats_incr(misses);
+out:
+    return node;
+}
+
+static int avc_latest_notif_update(int seqno, int is_insert)
+{
+    int ret = 0;
+    static DEFINE_SPINLOCK(notif_lock);
+    unsigned long flag;
+
+    spin_lock_irqsave(&notif_lock, flag);
+    if ( is_insert )
+    {
+        if ( seqno < avc_cache.latest_notif )
+        {
+            printk(KERN_WARNING "avc:  seqno %d < latest_notif %d\n",
+                   seqno, avc_cache.latest_notif);
+            ret = -EAGAIN;
+        }
+    }
+    else
+    {
+        if ( seqno > avc_cache.latest_notif )
+            avc_cache.latest_notif = seqno;
+    }
+    spin_unlock_irqrestore(&notif_lock, flag);
+
+    return ret;
+}
+
+/**
+ * avc_insert - Insert an AVC entry.
+ * @ssid: source security identifier
+ * @tsid: target security identifier
+ * @tclass: target security class
+ * @ae: AVC entry
+ *
+ * Insert an AVC entry for the SID pair
+ * (@ssid, @tsid) and class @tclass.
+ * The access vectors and the sequence number are
+ * normally provided by the security server in
+ * response to a security_compute_av() call.  If the
+ * sequence number @ae->avd.seqno is not less than the latest
+ * revocation notification, then the function copies
+ * the access vectors into a cache entry, returns
+ * avc_node inserted. Otherwise, this function returns NULL.
+ */
+static struct avc_node *avc_insert(u32 ssid, u32 tsid, u16 tclass, struct avc_entry *ae)
+{
+    struct avc_node *pos, *node = NULL;
+    int hvalue;
+	unsigned long flag;
+
+    if ( avc_latest_notif_update(ae->avd.seqno, 1) )
+        goto out;
+
+    node = avc_alloc_node();
+    if ( node )
+    {
+        hvalue = avc_hash(ssid, tsid, tclass);
+        avc_node_populate(node, ssid, tsid, tclass, ae);
+
+		spin_lock_irqsave(&avc_cache.slots_lock[hvalue], flag);
+        list_for_each_entry(pos, &avc_cache.slots[hvalue], list)
+        {
+            if ( pos->ae.ssid == ssid && pos->ae.tsid == tsid &&
+                                                    pos->ae.tclass == tclass )
+            {
+                avc_node_replace(node, pos);
+                goto found;
+            }
+        }
+        list_add_rcu(&node->list, &avc_cache.slots[hvalue]);
+found:
+		spin_unlock_irqrestore(&avc_cache.slots_lock[hvalue], flag);
+    }
+out:
+    return node;
+}
+
+/**
+ * avc_audit - Audit the granting or denial of permissions.
+ * @ssid: source security identifier
+ * @tsid: target security identifier
+ * @tclass: target security class
+ * @requested: requested permissions
+ * @avd: access vector decisions
+ * @result: result from avc_has_perm_noaudit
+ * @a:  auxiliary audit data
+ *
+ * Audit the granting or denial of permissions in accordance
+ * with the policy.  This function is typically called by
+ * avc_has_perm() after a permission check, but can also be
+ * called directly by callers who use avc_has_perm_noaudit()
+ * in order to separate the permission check from the auditing.
+ * For example, this separation is useful when the permission check must
+ * be performed under a lock, to allow the lock to be released
+ * before calling the auditing code.
+ */
+void avc_audit(u32 ssid, u32 tsid, u16 tclass, u32 requested,
+               struct av_decision *avd, int result, struct avc_audit_data *a)
+{
+    struct domain *d = current->domain;
+    u32 denied, audited;
+
+    denied = requested & ~avd->allowed;
+    if ( denied )
+    {
+        audited = denied;
+        if ( !(audited & avd->auditdeny) )
+            return;
+    }
+    else if ( result )
+    {
+        audited = denied = requested;
+    }
+    else
+    {
+        audited = requested;
+        if ( !(audited & avd->auditallow) )
+            return;
+    }
+
+    printk("avc:  %s ", denied ? "denied" : "granted");
+    avc_dump_av(tclass, audited);
+    printk(" for ");
+
+    if ( a && a->d )
+        d = a->d;
+    if ( d )
+        printk("domid=%d", d->domain_id);
+
+    printk("\n");
+    avc_dump_query(ssid, tsid, tclass);
+    printk("\n");
+
+}
+
+/**
+ * avc_add_callback - Register a callback for security events.
+ * @callback: callback function
+ * @events: security events
+ * @ssid: source security identifier or %SECSID_WILD
+ * @tsid: target security identifier or %SECSID_WILD
+ * @tclass: target security class
+ * @perms: permissions
+ *
+ * Register a callback function for events in the set @events
+ * related to the SID pair (@ssid, @tsid) and
+ * and the permissions @perms, interpreting
+ * @perms based on @tclass.  Returns %0 on success or
+ * -%ENOMEM if insufficient memory exists to add the callback.
+ */
+int avc_add_callback(int (*callback)(u32 event, u32 ssid, u32 tsid, u16 tclass,
+                u32 perms, u32 *out_retained), u32 events, u32 ssid, u32 tsid,
+                                                        u16 tclass, u32 perms)
+{
+    struct avc_callback_node *c;
+    int rc = 0;
+
+    c = xmalloc(struct avc_callback_node);
+    if ( !c )
+    {
+        rc = -ENOMEM;
+        goto out;
+    }
+
+    c->callback = callback;
+    c->events = events;
+    c->ssid = ssid;
+    c->tsid = tsid;
+    c->perms = perms;
+    c->next = avc_callbacks;
+    avc_callbacks = c;
+out:
+    return rc;
+}
+
+static inline int avc_sidcmp(u32 x, u32 y)
+{
+    return (x == y || x == SECSID_WILD || y == SECSID_WILD);
+}
+
+/**
+ * avc_update_node Update an AVC entry
+ * @event : Updating event
+ * @perms : Permission mask bits
+ * @ssid,@tsid,@tclass : identifier of an AVC entry
+ *
+ * if a valid AVC entry doesn't exist,this function returns -ENOENT.
+ * if kmalloc() called internal returns NULL, this function returns -ENOMEM.
+ * otherwise, this function update the AVC entry. The original AVC-entry object
+ * will release later by RCU.
+ */
+static int avc_update_node(u32 event, u32 perms, u32 ssid, u32 tsid, u16 tclass)
+{
+    int hvalue, rc = 0;
+	unsigned long flag;
+    struct avc_node *pos, *node, *orig = NULL;
+    
+    node = avc_alloc_node();
+    if ( !node )
+    {
+        rc = -ENOMEM;
+        goto out;
+    }
+
+    hvalue = avc_hash(ssid, tsid, tclass);    
+	spin_lock_irqsave(&avc_cache.slots_lock[hvalue], flag);
+
+    list_for_each_entry(pos, &avc_cache.slots[hvalue], list)
+    {
+        if ( ssid==pos->ae.ssid && tsid==pos->ae.tsid &&
+                                                        tclass==pos->ae.tclass )
+        {
+            orig = pos;
+            break;
+        }
+    }
+
+    if ( !orig )
+    {
+        rc = -ENOENT;
+        avc_node_kill(node);
+        goto out_unlock;
+    }
+
+    /*
+     * Copy and replace original node.
+     */
+
+    avc_node_populate(node, ssid, tsid, tclass, &orig->ae);
+
+    switch ( event )
+    {
+    case AVC_CALLBACK_GRANT:
+        node->ae.avd.allowed |= perms;
+    break;
+    case AVC_CALLBACK_TRY_REVOKE:
+    case AVC_CALLBACK_REVOKE:
+        node->ae.avd.allowed &= ~perms;
+    break;
+    case AVC_CALLBACK_AUDITALLOW_ENABLE:
+        node->ae.avd.auditallow |= perms;
+    break;
+    case AVC_CALLBACK_AUDITALLOW_DISABLE:
+        node->ae.avd.auditallow &= ~perms;
+    break;
+    case AVC_CALLBACK_AUDITDENY_ENABLE:
+        node->ae.avd.auditdeny |= perms;
+    break;
+    case AVC_CALLBACK_AUDITDENY_DISABLE:
+        node->ae.avd.auditdeny &= ~perms;
+    break;
+    }
+    avc_node_replace(node, orig);
+out_unlock:
+	spin_unlock_irqrestore(&avc_cache.slots_lock[hvalue], flag);
+out:
+    return rc;
+}
+
+/**
+ * avc_ss_reset - Flush the cache and revalidate migrated permissions.
+ * @seqno: policy sequence number
+ */
+int avc_ss_reset(u32 seqno)
+{
+    struct avc_callback_node *c;
+    int i, rc = 0;
+	unsigned long flag;
+    struct avc_node *node;
+
+    for ( i = 0; i < AVC_CACHE_SLOTS; i++ )
+    {
+		spin_lock_irqsave(&avc_cache.slots_lock[i], flag);
+        list_for_each_entry(node, &avc_cache.slots[i], list)
+            avc_node_delete(node);
+		spin_unlock_irqrestore(&avc_cache.slots_lock[i], flag);
+    }
+    
+    for ( c = avc_callbacks; c; c = c->next )
+    {
+        if ( c->events & AVC_CALLBACK_RESET )
+        {
+            rc = c->callback(AVC_CALLBACK_RESET,
+                     0, 0, 0, 0, NULL);
+            if ( rc )
+                goto out;
+        }
+    }
+
+    avc_latest_notif_update(seqno, 0);
+out:
+    return rc;
+}
+
+/**
+ * avc_has_perm_noaudit - Check permissions but perform no auditing.
+ * @ssid: source security identifier
+ * @tsid: target security identifier
+ * @tclass: target security class
+ * @requested: requested permissions, interpreted based on @tclass
+ * @avd: access vector decisions
+ *
+ * Check the AVC to determine whether the @requested permissions are granted
+ * for the SID pair (@ssid, @tsid), interpreting the permissions
+ * based on @tclass, and call the security server on a cache miss to obtain
+ * a new decision and add it to the cache.  Return a copy of the decisions
+ * in @avd.  Return %0 if all @requested permissions are granted,
+ * -%EACCES if any permissions are denied, or another -errno upon
+ * other errors.  This function is typically called by avc_has_perm(),
+ * but may also be called directly to separate permission checking from
+ * auditing, e.g. in cases where a lock must be held for the check but
+ * should be released for the auditing.
+ */
+int avc_has_perm_noaudit(u32 ssid, u32 tsid, u16 tclass, u32 requested,
+                                                     struct av_decision *avd)
+{
+    struct avc_node *node;
+    struct avc_entry entry, *p_ae;
+    int rc = 0;
+    u32 denied;
+
+    rcu_read_lock();
+
+    node = avc_lookup(ssid, tsid, tclass, requested);
+    if ( !node )
+    {
+        rcu_read_unlock();
+        rc = security_compute_av(ssid,tsid,tclass,requested,&entry.avd);
+        if ( rc )
+            goto out;
+        rcu_read_lock();
+        node = avc_insert(ssid,tsid,tclass,&entry);
+    }
+
+    p_ae = node ? &node->ae : &entry;
+
+    if ( avd )
+        memcpy(avd, &p_ae->avd, sizeof(*avd));
+
+    denied = requested & ~(p_ae->avd.allowed);
+
+    if ( !requested || denied )
+    {
+        if ( flask_enforcing )
+            rc = -EACCES;
+        else
+            if ( node )
+                avc_update_node(AVC_CALLBACK_GRANT,requested,
+                        ssid,tsid,tclass);
+    }
+
+    rcu_read_unlock();
+out:
+    return rc;
+}
+
+/**
+ * avc_has_perm - Check permissions and perform any appropriate auditing.
+ * @ssid: source security identifier
+ * @tsid: target security identifier
+ * @tclass: target security class
+ * @requested: requested permissions, interpreted based on @tclass
+ * @auditdata: auxiliary audit data
+ *
+ * Check the AVC to determine whether the @requested permissions are granted
+ * for the SID pair (@ssid, @tsid), interpreting the permissions
+ * based on @tclass, and call the security server on a cache miss to obtain
+ * a new decision and add it to the cache.  Audit the granting or denial of
+ * permissions in accordance with the policy.  Return %0 if all @requested
+ * permissions are granted, -%EACCES if any permissions are denied, or
+ * another -errno upon other errors.
+ */
+int avc_has_perm(u32 ssid, u32 tsid, u16 tclass,
+                 u32 requested, struct avc_audit_data *auditdata)
+{
+    struct av_decision avd;
+    int rc;
+
+    rc = avc_has_perm_noaudit(ssid, tsid, tclass, requested, &avd);
+    avc_audit(ssid, tsid, tclass, requested, &avd, rc, auditdata);
+    return rc;
+}
diff -r cb2ecf48cf80 -r 8ae246493872 xen/xsm/flask/flask_op.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/flask_op.c	Mon Jun 04 11:06:52 2007 -0400
@@ -0,0 +1,1079 @@
+/*
+ *  This file contains the flask_op hypercall and associated functions.
+ *
+ *  Author:  George Coker, <gscoker@alpha.ncsc.mil>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2,
+ *  as published by the Free Software Foundation.
+ */
+
+#include <xen/errno.h>
+#include <xsm/xsm.h>
+#include <xen/guest_access.h>
+
+#include <public/flask_op.h>
+
+#include <avc.h>
+#include <avc_ss.h>
+#include <objsec.h>
+#include <conditional.h>
+
+#ifdef FLASK_DEVELOP
+int flask_enforcing = 0;
+integer_param("flask_enforcing", flask_enforcing);
+#endif
+
+#ifdef FLASK_BOOTPARAM
+int flask_enabled = 1;
+integer_param("flask_enabled", flask_enabled);
+#endif
+
+static DEFINE_SPINLOCK(sel_sem);
+
+/* global data for booleans */
+static int bool_num = 0;
+static int *bool_pending_values = NULL;
+
+extern int ss_initialized;
+
+extern struct xsm_operations *original_ops;
+
+static int domain_has_security(struct domain *d, u32 perms)
+{
+    struct domain_security_struct *dsec;
+    
+    dsec = d->ssid;
+    if ( !dsec )
+        return -EACCES;
+        
+    return avc_has_perm(dsec->sid, SECINITSID_SECURITY, SECCLASS_SECURITY, 
+                                                                perms, NULL);
+}
+
+static int flask_security_user(char *buf, int size)
+{
+    char *page = NULL;
+    char *con, *user, *ptr;
+    u32 sid, *sids;
+    int length;
+    char *newcon;
+    int i, rc;
+    u32 len, nsids;
+        
+    length = domain_has_security(current->domain, SECURITY__COMPUTE_USER);
+    if ( length )
+        return length;
+            
+    length = -ENOMEM;
+    con = xmalloc_array(char, size+1);
+    if ( !con )
+        return length;
+    memset(con, 0, size+1);
+    
+    user = xmalloc_array(char, size+1);
+    if ( !user )
+        goto out;
+    memset(user, 0, size+1);
+    
+    length = -ENOMEM;
+    page = xmalloc_bytes(PAGE_SIZE);
+    if ( !page )
+        goto out2;
+    memset(page, 0, PAGE_SIZE);
+
+    length = -EFAULT;
+    if ( copy_from_user(page, buf, size) )
+        goto out2;
+        
+    length = -EINVAL;
+    if ( sscanf(page, "%s %s", con, user) != 2 )
+        goto out2;
+
+    length = security_context_to_sid(con, strlen(con)+1, &sid);
+    if ( length < 0 )
+        goto out2;
+            
+    length = security_get_user_sids(sid, user, &sids, &nsids);
+    if ( length < 0 )
+        goto out2;
+    
+    memset(page, 0, PAGE_SIZE);
+    length = snprintf(page, PAGE_SIZE, "%u", nsids) + 1;
+    ptr = page + length;
+    for ( i = 0; i < nsids; i++ )
+    {
+        rc = security_sid_to_context(sids[i], &newcon, &len);
+        if ( rc )
+        {
+            length = rc;
+            goto out3;
+        }
+        if ( (length + len) >= PAGE_SIZE )
+        {
+            xfree(newcon);
+            length = -ERANGE;
+            goto out3;
+        }
+        memcpy(ptr, newcon, len);
+        xfree(newcon);
+        ptr += len;
+        length += len;
+    }
+    
+    if ( copy_to_user(buf, page, length) )
+        length = -EFAULT;
+        
+out3:
+    xfree(sids);
+out2:
+    if ( page )
+        xfree(page);
+    xfree(user);
+out:
+    xfree(con);
+    return length;
+}
+
+static int flask_security_relabel(char *buf, int size)
+{
+    char *scon, *tcon;
+    u32 ssid, tsid, newsid;
+    u16 tclass;
+    int length;
+    char *newcon;
+    u32 len;
+
+    length = domain_has_security(current->domain, SECURITY__COMPUTE_RELABEL);
+    if ( length )
+        return length;
+            
+    length = -ENOMEM;
+    scon = xmalloc_array(char, size+1);
+    if ( !scon )
+        return length;
+    memset(scon, 0, size+1);
+        
+    tcon = xmalloc_array(char, size+1);
+    if ( !tcon )
+        goto out;
+    memset(tcon, 0, size+1);
+        
+    length = -EINVAL;
+    if ( sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3 )
+        goto out2;
+            
+    length = security_context_to_sid(scon, strlen(scon)+1, &ssid);
+    if ( length < 0 )
+        goto out2;
+    length = security_context_to_sid(tcon, strlen(tcon)+1, &tsid);
+    if ( length < 0 )
+        goto out2;
+            
+    length = security_change_sid(ssid, tsid, tclass, &newsid);
+    if ( length < 0 )
+        goto out2;
+            
+    length = security_sid_to_context(newsid, &newcon, &len);
+    if ( length < 0 )
+        goto out2;
+            
+    if ( len > PAGE_SIZE )
+    {
+        length = -ERANGE;
+        goto out3;
+    }
+        
+    if ( copy_to_user(buf, newcon, len) )
+        len = -EFAULT;
+
+    length = len;
+        
+out3:
+    xfree(newcon);
+out2:
+    xfree(tcon);
+out:
+    xfree(scon);
+    return length;
+}
+
+static int flask_security_create(char *buf, int size)
+{
+    char *scon, *tcon;
+    u32 ssid, tsid, newsid;
+    u16 tclass;
+    int length;
+    char *newcon;
+    u32 len;
+
+    length = domain_has_security(current->domain, SECURITY__COMPUTE_CREATE);
+    if ( length )
+        return length;
+
+    length = -ENOMEM;
+    scon = xmalloc_array(char, size+1);
+    if ( !scon )
+        return length;
+    memset(scon, 0, size+1);
+
+    tcon = xmalloc_array(char, size+1);
+    if ( !tcon )
+        goto out;
+    memset(tcon, 0, size+1);
+
+    length = -EINVAL;
+    if ( sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3 )
+        goto out2;
+
+    length = security_context_to_sid(scon, strlen(scon)+1, &ssid);
+    if ( length < 0 )
+        goto out2;
+
+    length = security_context_to_sid(tcon, strlen(tcon)+1, &tsid);
+    if ( length < 0 )
+        goto out2;
+
+    length = security_transition_sid(ssid, tsid, tclass, &newsid);
+    if ( length < 0 )
+        goto out2;
+
+    length = security_sid_to_context(newsid, &newcon, &len);
+    if ( length < 0 )    
+        goto out2;
+
+    if ( len > PAGE_SIZE )
+    {
+        printk( "%s:  context size (%u) exceeds payload "
+                "max\n", __FUNCTION__, len);
+        length = -ERANGE;
+        goto out3;
+    }
+
+    if ( copy_to_user(buf, newcon, len) )
+        len = -EFAULT;
+
+    length = len;
+        
+out3:
+    xfree(newcon);
+out2:
+    xfree(tcon);
+out:
+    xfree(scon);
+    return length;
+}
+
+static int flask_security_access(char *buf, int size)
+{
+    char *page = NULL;
+    char *scon, *tcon;
+    u32 ssid, tsid;
+    u16 tclass;
+    u32 req;
+    struct av_decision avd;
+    int length;
+
+    length = domain_has_security(current->domain, SECURITY__COMPUTE_AV);
+    if ( length )
+        return length;
+
+    length = -ENOMEM;
+    scon = xmalloc_array(char, size+1);
+    if (!scon)
+        return length;
+    memset(scon, 0, size+1);
+
+    tcon = xmalloc_array(char, size+1);
+    if ( !tcon )
+        goto out;
+    memset( tcon, 0, size+1 );
+
+    length = -EINVAL;
+    if (sscanf(buf, "%s %s %hu %x", scon, tcon, &tclass, &req) != 4)
+        goto out2;
+
+    length = security_context_to_sid(scon, strlen(scon)+1, &ssid);
+    if ( length < 0 )
+        goto out2;
+
+    length = security_context_to_sid(tcon, strlen(tcon)+1, &tsid);
+    if ( length < 0 )
+        goto out2;
+
+    length = security_compute_av(ssid, tsid, tclass, req, &avd);
+    if ( length < 0 )
+        goto out2;
+
+    page = (char *)xmalloc_bytes(PAGE_SIZE);
+    if ( !page )
+    {
+        length = -ENOMEM;
+        goto out2;
+    }
+
+    memset(page, 0, PAGE_SIZE);
+
+    length = snprintf(page, PAGE_SIZE, "%x %x %x %x %u", 
+                                        avd.allowed, avd.decided,
+                                        avd.auditallow, avd.auditdeny, 
+                                        avd.seqno);
+                
+    if ( copy_to_user(buf, page, length) )
+        length = -EFAULT;
+        
+out2:
+    xfree(tcon);
+out:
+    xfree(scon);
+    return length;
+}
+
+static int flask_security_member(char *buf, int size)
+{
+    char *scon, *tcon;
+    u32 ssid, tsid, newsid;
+    u16 tclass;
+    int length;
+    char *newcon;
+    u32 len;
+
+    length = domain_has_security(current->domain, SECURITY__COMPUTE_MEMBER);
+    if ( length )
+        return length;
+
+    length = -ENOMEM;
+    scon = xmalloc_array(char, size+1);
+    if ( !scon )
+        return length;
+    memset(scon, 0, size+1);
+
+    tcon = xmalloc_array(char, size+1);
+    if ( !tcon )
+        goto out;
+    memset(tcon, 0, size+1);
+
+    length = -EINVAL;
+    if ( sscanf(buf, "%s, %s, %hu", scon, tcon, &tclass) != 3 )
+        goto out2;
+
+    length = security_context_to_sid(scon, strlen(scon)+1, &ssid);
+    if ( length < 0 )
+        goto out2;
+
+    length = security_context_to_sid(tcon, strlen(tcon)+1, &tsid);
+    if ( length < 0 )
+        goto out2;
+
+    length = security_member_sid(ssid, tsid, tclass, &newsid);
+    if ( length < 0 )
+        goto out2;
+
+    length = security_sid_to_context(newsid, &newcon, &len);
+    if ( length < 0 )
+        goto out2;
+
+    if ( len > PAGE_SIZE )
+    {
+        printk("%s:  context size (%u) exceeds payload "
+                "max\n", __FUNCTION__, len);
+        length = -ERANGE;
+        goto out3;
+    }
+
+    if ( copy_to_user(buf, newcon, len) )
+        len = -EFAULT;
+
+    length = len;
+
+out3:
+    xfree(newcon);
+out2:
+    xfree(tcon);
+out:
+    xfree(scon);
+    return length;
+}
+
+static int flask_security_setenforce(char *buf, int count)
+{
+    char *page = NULL;
+    int length;
+    int new_value;
+
+    if ( count < 0 || count >= PAGE_SIZE )
+        return -ENOMEM;
+
+    page = (char *)xmalloc_bytes(PAGE_SIZE);
+    if ( !page )
+        return -ENOMEM;
+    memset(page, 0, PAGE_SIZE);
+    length = -EFAULT;
+    if ( copy_from_user(page, buf, count) )
+        goto out;
+
+    length = -EINVAL;
+    if ( sscanf(page, "%d", &new_value) != 1 )
+        goto out;
+
+    if ( new_value != flask_enforcing )
+    {
+        length = domain_has_security(current->domain, SECURITY__SETENFORCE);
+        if ( length )
+            goto out;
+        flask_enforcing = new_value;
+        if ( flask_enforcing )
+            avc_ss_reset(0);
+    }
+    length = count;
+
+out:
+    xfree(page);
+    return length;
+}
+
+static int flask_security_context(char *buf, int count)
+{
+    char *page = NULL;
+    u32 sid;
+    int length;
+
+    length = domain_has_security(current->domain, SECURITY__CHECK_CONTEXT);
+    if ( length )
+        goto out;
+
+    if ( count < 0 || count >= PAGE_SIZE )
+        return -ENOMEM;
+
+    page = (char *)xmalloc_bytes(PAGE_SIZE);
+    if ( !page )
+        return -ENOMEM;
+    memset(page, 0, PAGE_SIZE);
+    length = -EFAULT;
+    if ( copy_from_user(page, buf, count) )
+        goto out;
+
+    length = security_context_to_sid(page, count, &sid);
+    if ( length < 0 )
+        goto out;
+
+    memset(page, 0, PAGE_SIZE);
+    length = snprintf(page, PAGE_SIZE, "%u", sid);
+
+    if ( copy_to_user(buf, page, count) )
+        length = -EFAULT;
+
+out:
+    xfree(page);
+    return length;
+}
+
+static int flask_security_sid(char *buf, int count)
+{
+    char *page = NULL;
+    char *context;
+    u32 sid;
+    u32 len;
+    int length;
+
+    length = domain_has_security(current->domain, SECURITY__CHECK_CONTEXT);
+    if ( length )
+        goto out;
+
+    if ( count < 0 || count >= PAGE_SIZE )
+        return -ENOMEM;
+
+    page = (char *)xmalloc_bytes(PAGE_SIZE);
+    if ( !page )
+        return -ENOMEM;
+    memset(page, 0, PAGE_SIZE);
+    length = -EFAULT;
+    if ( copy_from_user(page, buf, count) )
+        goto out;
+
+    if ( sscanf(page, "%u", &sid) != 1 )
+        goto out;
+
+    length = security_sid_to_context(sid, &context, &len);
+    if ( length < 0 )
+        goto out;
+
+    if ( copy_to_user(buf, context, len) )
+        length = -EFAULT;
+    
+    xfree(context);
+
+out:
+    xfree(page);
+    return length;
+}
+
+int flask_disable(void)
+{
+    static int flask_disabled = 0;
+
+    if ( ss_initialized )
+    {
+        /* Not permitted after initial policy load. */
+        return -EINVAL;
+    }
+
+    if ( flask_disabled )
+    {
+        /* Only do this once. */
+        return -EINVAL;
+    }
+
+    printk("Flask:  Disabled at runtime.\n");
+
+    flask_disabled = 1;
+
+    /* Reset xsm_ops to the original module. */
+    xsm_ops = original_ops;
+
+    return 0;
+}
+
+static int flask_security_disable(char *buf, int count)
+{
+    char *page = NULL;
+    int length;
+    int new_value;
+
+    if ( count < 0 || count >= PAGE_SIZE )
+        return -ENOMEM;
+    page = (char *)xmalloc_bytes(PAGE_SIZE);
+    if ( !page )
+        return -ENOMEM;
+    memset(page, 0, PAGE_SIZE);
+    length = -EFAULT;
+    if ( copy_from_user(page, buf, count) )
+        goto out;
+
+    length = -EINVAL;
+    if ( sscanf(page, "%d", &new_value) != 1 )
+        goto out;
+
+    if ( new_value )
+    {
+        length = flask_disable();
+        if ( length < 0 )
+            goto out;
+    }
+
+    length = count;
+
+out:
+    xfree(page);
+    return length;
+}
+
+static int flask_security_setavc_threshold(char *buf, int count)
+{
+    char *page = NULL;
+    int ret;
+    int new_value;
+
+    if ( count < 0 || count >= PAGE_SIZE )
+    {
+        ret = -ENOMEM;
+        goto out;
+    }
+
+    page = (char*)xmalloc_bytes(PAGE_SIZE);
+    if (!page)
+        return -ENOMEM;
+    memset(page, 0, PAGE_SIZE);
+
+    if ( copy_from_user(page, buf, count) )
+    {
+        ret = -EFAULT;
+        goto out_free;
+    }
+
+    if ( sscanf(page, "%u", &new_value) != 1 )
+    {
+        ret = -EINVAL;
+        goto out_free;
+    }
+
+    if ( new_value != avc_cache_threshold )
+    {
+        ret = domain_has_security(current->domain, SECURITY__SETSECPARAM);
+        if ( ret )
+            goto out_free;
+        avc_cache_threshold = new_value;
+    }
+    ret = count;
+
+out_free:
+    xfree(page);
+out:
+    return ret;
+}
+
+static int flask_security_set_bool(char *buf, int count)
+{
+    char *page = NULL;
+    int length = -EFAULT;
+    int i, new_value;
+
+    spin_lock(&sel_sem);
+
+    length = domain_has_security(current->domain, SECURITY__SETBOOL);
+    if ( length )
+        goto out;
+
+    if ( count < 0 || count >= PAGE_SIZE )
+    {
+        length = -ENOMEM;
+        goto out;
+    }
+
+    page = (char *)xmalloc_bytes(PAGE_SIZE);
+    if ( !page )
+    {
+        length = -ENOMEM;
+        goto out;
+    }
+    memset(page, 0, PAGE_SIZE);
+
+    if ( copy_from_user(page, buf, count) )
+        goto out;
+
+    length = -EINVAL;
+    if ( sscanf(page, "%d %d", &i, &new_value) != 2 )
+        goto out;
+
+    if ( new_value )
+    {
+        new_value = 1;
+    }
+
+    bool_pending_values[i] = new_value;
+    length = count;
+
+out:
+    spin_unlock(&sel_sem);
+    if ( page )
+        xfree(page);
+    return length;
+}
+
+static int flask_security_commit_bools(char *buf, int count)
+{
+    char *page = NULL;
+    int length = -EFAULT;
+    int new_value;
+
+    spin_lock(&sel_sem);
+
+    length = domain_has_security(current->domain, SECURITY__SETBOOL);
+    if ( length )
+        goto out;
+
+    if ( count < 0 || count >= PAGE_SIZE )
+    {
+        length = -ENOMEM;
+        goto out;
+    }
+
+    page = (char *)xmalloc_bytes(PAGE_SIZE);
+    if ( !page )
+    {
+        length = -ENOMEM;
+        goto out;
+    }
+    memset(page, 0, PAGE_SIZE);
+
+    if ( copy_from_user(page, buf, count) )
+        goto out;
+
+    length = -EINVAL;
+    if ( sscanf(page, "%d", &new_value) != 1 )
+        goto out;
+
+    if ( new_value )
+        security_set_bools(bool_num, bool_pending_values);
+    
+    length = count;
+
+out:
+    spin_unlock(&sel_sem);
+    if ( page )
+        xfree(page);
+    return length;
+}
+
+static int flask_security_get_bool(char *buf, int count)
+{
+    char *page = NULL;
+    int length;
+    int i, cur_enforcing;
+    
+    spin_lock(&sel_sem);
+    
+    length = -EFAULT;
+
+    if ( count < 0 || count > PAGE_SIZE )
+    {
+        length = -EINVAL;
+        goto out;
+    }
+
+    page = (char *)xmalloc_bytes(PAGE_SIZE);
+    if ( !page )
+    {
+        length = -ENOMEM;
+        goto out;
+    }
+    memset(page, 0, PAGE_SIZE);
+
+    if ( copy_from_user(page, buf, count) )
+        goto out;
+
+    length = -EINVAL;
+    if ( sscanf(page, "%d", &i) != 1 )
+        goto out;
+
+    cur_enforcing = security_get_bool_value(i);
+    if ( cur_enforcing < 0 )
+    {
+        length = cur_enforcing;
+        goto out;
+    }
+
+    length = snprintf(page, PAGE_SIZE, "%d %d", cur_enforcing,
+                bool_pending_values[i]);
+    if ( length < 0 )
+        goto out;
+
+    if ( copy_to_user(buf, page, length) )
+        length = -EFAULT;
+
+out:
+    spin_unlock(&sel_sem);
+    if ( page )
+        xfree(page);
+    return length;
+}
+
+static int flask_security_make_bools(void)
+{
+    int i, ret = 0;
+    char **names = NULL;
+    int num;
+    int *values = NULL;
+    
+    xfree(bool_pending_values);
+    
+    ret = security_get_bools(&num, &names, &values);
+    if ( ret != 0 )
+        goto out;
+
+    bool_num = num;
+    bool_pending_values = values;
+
+out:
+    if ( names )
+    {
+        for ( i = 0; i < num; i++ )
+            xfree(names[i]);
+        xfree(names);
+    }    
+    return ret;
+}
+
+#ifdef FLASK_AVC_STATS
+
+static int flask_security_avc_cachestats(char *buf, int count)
+{
+    char *page = NULL;
+    int len = 0;
+    int length = 0;
+    long long idx = 0;
+    int cpu;
+    struct avc_cache_stats *st;
+
+    page = (char *)xmalloc_bytes(PAGE_SIZE);
+    if ( !page )
+        return -ENOMEM;
+    memset(page, 0, PAGE_SIZE);
+
+    len = snprintf(page, PAGE_SIZE, "lookups hits misses allocations reclaims "
+                                                                   "frees\n");
+    memcpy(buf, page, len);
+    buf += len;
+    length += len;
+
+    for ( cpu = idx; cpu < NR_CPUS; ++cpu )
+    {
+        if ( !cpu_possible(cpu) )
+            continue;
+        idx = cpu + 1;
+        st = &per_cpu(avc_cache_stats, cpu);
+
+        len = snprintf(page, PAGE_SIZE, "%u %u %u %u %u %u\n", st->lookups,
+                                       st->hits, st->misses, st->allocations,
+                                                       st->reclaims, st->frees);
+        memcpy(buf, page, len);
+        buf += len;
+        length += len;
+    }
+
+    xfree(page);    
+    return length;
+}
+
+#endif
+
+static int flask_security_load(char *buf, int count)
+{
+    int ret;
+    int length;
+    void *data = NULL;
+
+    spin_lock(&sel_sem);
+
+    length = domain_has_security(current->domain, SECURITY__LOAD_POLICY);
+    if ( length )
+        goto out;
+
+    if ( (count < 0) || (count > 64 * 1024 * 1024) 
+                               || (data = xmalloc_array(char, count)) == NULL )
+    {
+        length = -ENOMEM;
+        goto out;
+    }
+
+    length = -EFAULT;
+    if ( copy_from_user(data, buf, count) != 0 )
+        goto out;
+
+    length = security_load_policy(data, count);
+    if ( length )
+        goto out;
+
+    ret = flask_security_make_bools();
+    if ( ret )
+        length = ret;
+    else
+        length = count;
+
+out:
+    spin_unlock(&sel_sem);
+    xfree(data);
+    return length;
+}
+
+long do_flask_op(int cmd, XEN_GUEST_HANDLE(xsm_op_t) u_flask_op)
+{
+    flask_op_t curop, *op = &curop;
+    int rc = 0;
+    int length = 0;
+    char *page = NULL;
+
+    if ( copy_from_guest(op, u_flask_op, 1) )
+        return -EFAULT;
+
+    switch ( cmd )
+    {
+
+    case FLASK_LOAD:
+    {
+        length = flask_security_load(op->buf, op->size);
+    }
+    break;
+    
+    case FLASK_GETENFORCE:
+    {
+        page = (char *)xmalloc_bytes(PAGE_SIZE);
+        if ( !page )
+            return -ENOMEM;
+        memset(page, 0, PAGE_SIZE);
+        
+        length = snprintf(page, PAGE_SIZE, "%d", flask_enforcing);
+        
+        if ( copy_to_user(op->buf, page, length) )
+        {
+            rc = -EFAULT;
+            goto out;
+        }
+    }
+    break;    
+
+    case FLASK_SETENFORCE:
+    {
+        length = flask_security_setenforce(op->buf, op->size);
+    }
+    break;    
+
+    case FLASK_CONTEXT_TO_SID:
+    {
+        length = flask_security_context(op->buf, op->size);
+    }
+    break;    
+
+    case FLASK_SID_TO_CONTEXT:
+    {
+        length = flask_security_sid(op->buf, op->size);
+    }
+    break; 
+
+    case FLASK_ACCESS:
+    {
+        length = flask_security_access(op->buf, op->size);
+    }
+    break;    
+
+    case FLASK_CREATE:
+    {
+        length = flask_security_create(op->buf, op->size);
+    }
+    break;    
+
+    case FLASK_RELABEL:
+    {
+        length = flask_security_relabel(op->buf, op->size);
+    }
+    break;
+
+    case FLASK_USER:
+    {
+        length = flask_security_user(op->buf, op->size);
+    }
+    break;    
+
+    case FLASK_POLICYVERS:
+    {
+        page = (char *)xmalloc_bytes(PAGE_SIZE);
+        if ( !page )
+            return -ENOMEM;
+        memset(page, 0, PAGE_SIZE);
+
+        length = snprintf(page, PAGE_SIZE, "%d", POLICYDB_VERSION_MAX);
+
+        if ( copy_to_user(op->buf, page, length) )
+        {
+            rc = -EFAULT;
+            goto out;
+        }
+    }
+    break;    
+
+    case FLASK_GETBOOL:
+    {
+        length = flask_security_get_bool(op->buf, op->size);
+    }
+    break;
+
+    case FLASK_SETBOOL:
+    {
+        length = flask_security_set_bool(op->buf, op->size);
+    }
+    break;
+
+    case FLASK_COMMITBOOLS:
+    {
+        length = flask_security_commit_bools(op->buf, op->size);
+    }
+    break;
+
+    case FLASK_MLS:
+    {
+        page = (char *)xmalloc_bytes(PAGE_SIZE);
+        if ( !page )
+            return -ENOMEM;
+        memset(page, 0, PAGE_SIZE);
+
+        length = snprintf(page, PAGE_SIZE, "%d", flask_mls_enabled);
+
+        if ( copy_to_user(op->buf, page, length) )
+        {
+            rc = -EFAULT;
+            goto out;
+        }
+    }
+    break;    
+
+    case FLASK_DISABLE:
+    {
+        length = flask_security_disable(op->buf, op->size);
+    }
+    break;    
+
+    case FLASK_GETAVC_THRESHOLD:
+    {
+        page = (char *)xmalloc_bytes(PAGE_SIZE);
+        if ( !page )
+            return -ENOMEM;
+        memset(page, 0, PAGE_SIZE);
+
+        length = snprintf(page, PAGE_SIZE, "%d", avc_cache_threshold);
+
+        if ( copy_to_user(op->buf, page, length) )
+        {
+            rc = -EFAULT;
+            goto out;
+        }
+    }
+    break;
+
+    case FLASK_SETAVC_THRESHOLD:
+    {
+        length = flask_security_setavc_threshold(op->buf, op->size);
+    }
+    break;
+
+    case FLASK_AVC_HASHSTATS:
+    {
+        page = (char *)xmalloc_bytes(PAGE_SIZE);
+        if ( !page )
+            return -ENOMEM;
+        memset(page, 0, PAGE_SIZE);
+
+        length = avc_get_hash_stats(page);
+
+        if ( copy_to_user(op->buf, page, length) )
+        {
+            rc = -EFAULT;
+            goto out;
+        }
+    }
+    break;
+
+#ifdef FLASK_AVC_STATS    
+    case FLASK_AVC_CACHESTATS:
+    {
+        length = flask_security_avc_cachestats(op->buf, op->size);
+    }
+    break;
+#endif    
+
+    case FLASK_MEMBER:
+    {
+        length = flask_security_member(op->buf, op->size);
+    }
+    break;    
+
+    default:
+        length = -ENOSYS;
+        break;
+
+    }
+
+    if ( length < 0 )
+    {
+        rc = length;
+        goto out;
+    }
+    op->size = length;
+    if ( copy_to_guest(u_flask_op, op, 1) )
+        rc = -EFAULT;
+
+out:
+    if ( page )
+        xfree(page);
+    return rc;
+}
+
diff -r cb2ecf48cf80 -r 8ae246493872 xen/xsm/flask/hooks.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/hooks.c	Mon Jun 04 11:06:52 2007 -0400
@@ -0,0 +1,1182 @@
+ /*
+ *  This file contains the Flask hook function implementations for Xen.
+ *
+ *  Author:  George Coker, <gscoker@alpha.ncsc.mil>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License version 2,
+ *      as published by the Free Software Foundation.
+ */
+
+#include <xen/init.h>
+#include <xen/lib.h>
+#include <xen/sched.h>
+#include <xen/xmalloc.h>
+#include <xsm/xsm.h>
+#include <xen/spinlock.h>
+#include <xen/cpumask.h>
+#include <xen/errno.h>
+#include <xen/guest_access.h>
+#include <public/xen.h>
+#include <public/physdev.h>
+#include <public/platform.h>
+
+#include <public/flask_op.h>
+
+#include <avc.h>
+#include <avc_ss.h>
+#include <objsec.h>
+#include <conditional.h>
+
+struct xsm_operations *original_ops = NULL;
+
+static int domain_has_perm(struct domain *dom1, struct domain *dom2, 
+                                                        u16 class, u32 perms)
+{
+    struct domain_security_struct *dsec1, *dsec2;
+
+    dsec1 = dom1->ssid;
+    dsec2 = dom2->ssid;
+
+    return avc_has_perm(dsec1->sid, dsec2->sid, class, perms, NULL);
+}
+
+static int domain_has_evtchn(struct domain *d, struct evtchn *chn, u32 perms)
+{
+    struct domain_security_struct *dsec;
+    struct evtchn_security_struct *esec;
+
+    dsec = d->ssid;
+    esec = chn->ssid;
+
+    return avc_has_perm(dsec->sid, esec->sid, SECCLASS_EVENT, perms, NULL);
+}
+
+static int domain_has_xen(struct domain *d, u32 perms)
+{
+    struct domain_security_struct *dsec;
+    dsec = d->ssid;
+
+    return avc_has_perm(dsec->sid, SECINITSID_XEN, SECCLASS_XEN, perms, NULL);
+}
+
+static int flask_domain_alloc_security(struct domain *d)
+{
+    struct domain_security_struct *dsec;
+
+    dsec = xmalloc(struct domain_security_struct);
+
+    if ( !dsec )
+        return -ENOMEM;
+
+    memset(dsec, 0, sizeof(struct domain_security_struct));
+
+    dsec->d = d;
+
+    if ( d->domain_id == IDLE_DOMAIN_ID )
+    {
+        dsec->sid = SECINITSID_XEN;
+        dsec->create_sid = SECINITSID_DOM0;
+    }
+    else
+    {
+        dsec->sid = SECINITSID_UNLABELED;
+        dsec->create_sid = SECSID_NULL;
+    }
+
+    d->ssid = dsec;
+
+    return 0;
+}
+
+static void flask_domain_free_security(struct domain *d)
+{
+    struct domain_security_struct *dsec = d->ssid;
+
+    if ( !dsec )
+        return;
+
+    d->ssid = NULL;
+    xfree(dsec);
+}
+
+static int flask_evtchn_unbound(struct domain *d1, struct evtchn *chn, 
+                                                                    domid_t id2)
+{
+    u32 newsid;
+    int rc;
+    domid_t id;
+    struct domain *d2;
+    struct domain_security_struct *dsec, *dsec1, *dsec2;
+    struct evtchn_security_struct *esec;
+
+    dsec = current->domain->ssid;
+    dsec1 = d1->ssid;
+    esec = chn->ssid;
+
+    if ( id2 == DOMID_SELF )
+        id = current->domain->domain_id;
+    else
+        id = id2;
+
+    d2 = get_domain_by_id(id);
+    if ( d2 == NULL )
+        return -EPERM;
+
+    dsec2 = d2->ssid;
+    rc = security_transition_sid(dsec1->sid, dsec2->sid, SECCLASS_EVENT, 
+                                                                    &newsid);
+    if ( rc )
+        goto out;
+
+    rc = avc_has_perm(dsec->sid, newsid, SECCLASS_EVENT,
+                                            EVENT__CREATE|EVENT__ALLOC, NULL);
+    if ( rc )
+        goto out;
+
+    rc = avc_has_perm(newsid, dsec2->sid, SECCLASS_EVENT, EVENT__BIND, NULL);
+    if ( rc )
+        goto out;
+    else
+        esec->sid = newsid;
+
+out:
+    put_domain(d2);
+    return rc;
+}
+
+static int flask_evtchn_interdomain(struct domain *d1, struct evtchn *chn1, 
+                                        struct domain *d2, struct evtchn *chn2)
+{
+    u32 newsid1;
+    u32 newsid2;
+    int rc;
+    struct domain_security_struct *dsec1, *dsec2;
+    struct evtchn_security_struct *esec1, *esec2;
+
+    dsec1 = d1->ssid;
+    dsec2 = d2->ssid;
+
+    esec1 = chn1->ssid;
+    esec2 = chn2->ssid;
+
+    rc = security_transition_sid(dsec1->sid, dsec2->sid, 
+                                        SECCLASS_EVENT, &newsid1);
+    if ( rc )
+    {
+        printk("%s: security_transition_sid failed, rc=%d (domain=%d)\n",
+                                            __FUNCTION__, -rc, d2->domain_id);
+        return rc;
+    }
+
+    rc = avc_has_perm(dsec1->sid, newsid1, SECCLASS_EVENT, EVENT__CREATE, NULL);
+    if ( rc )
+        return rc;
+
+    rc = security_transition_sid(dsec2->sid, dsec1->sid, 
+                                        SECCLASS_EVENT, &newsid2);
+    if ( rc )
+    {
+        printk("%s: security_transition_sid failed, rc=%d (domain=%d)\n",
+                                            __FUNCTION__, -rc, d1->domain_id);
+        return rc;
+    }
+
+    rc = avc_has_perm(dsec2->sid, newsid2, SECCLASS_EVENT, EVENT__CREATE, NULL);
+    if ( rc )
+        return rc;
+
+    rc = avc_has_perm(newsid1, dsec2->sid, SECCLASS_EVENT, EVENT__BIND, NULL);
+    if ( rc )
+        return rc;
+
+    rc = avc_has_perm(newsid2, dsec1->sid, SECCLASS_EVENT, EVENT__BIND, NULL);
+    if ( rc )
+        return rc;    
+
+    esec1->sid = newsid1;
+    esec2->sid = newsid2;
+
+    return rc;
+}
+
+static void flask_evtchn_close_post(struct evtchn *chn)
+{
+    struct evtchn_security_struct *esec;
+    esec = chn->ssid;
+
+    esec->sid = SECINITSID_UNLABELED;
+}
+
+static int flask_evtchn_send(struct domain *d, struct evtchn *chn)
+{
+    return domain_has_evtchn(d, chn, EVENT__SEND);
+}
+
+static int flask_evtchn_status(struct domain *d, struct evtchn *chn)
+{
+    return domain_has_evtchn(d, chn, EVENT__STATUS);
+}
+
+static int flask_evtchn_reset(struct domain *d1, struct domain *d2)
+{
+    return domain_has_perm(d1, d2, SECCLASS_EVENT, EVENT__RESET);
+}
+
+static int flask_alloc_security_evtchn(struct evtchn *chn)
+{
+    struct evtchn_security_struct *esec;
+
+    esec = xmalloc(struct evtchn_security_struct);
+
+    if ( !esec )
+        return -ENOMEM;
+
+    memset(esec, 0, sizeof(struct evtchn_security_struct));
+
+    esec->chn = chn;
+    esec->sid = SECINITSID_UNLABELED;
+
+    chn->ssid = esec;
+
+    return 0;    
+}
+
+static void flask_free_security_evtchn(struct evtchn *chn)
+{
+    struct evtchn_security_struct *esec;
+
+    if ( !chn )
+        return;
+
+    esec = chn->ssid;
+
+    if ( !esec )
+        return;
+
+    chn->ssid = NULL;
+    xfree(esec);
+}
+
+static int flask_grant_mapref(struct domain *d1, struct domain *d2, 
+                                                                uint32_t flags)
+{
+    u32 perms = GRANT__MAP_READ;
+
+    if ( flags & GTF_writing )
+        perms |= GRANT__MAP_WRITE;
+
+    return domain_has_perm(d1, d2, SECCLASS_GRANT, perms);
+}
+
+static int flask_grant_unmapref(struct domain *d1, struct domain *d2)
+{
+    return domain_has_perm(d1, d2, SECCLASS_GRANT, GRANT__UNMAP);
+}
+
+static int flask_grant_setup(struct domain *d1, struct domain *d2)
+{
+    return domain_has_perm(d1, d2, SECCLASS_GRANT, GRANT__SETUP);
+}
+
+static int flask_grant_transfer(struct domain *d1, struct domain *d2)
+{
+    return domain_has_perm(d1, d2, SECCLASS_GRANT, GRANT__TRANSFER);
+}
+
+static int flask_grant_copy(struct domain *d1, struct domain *d2)
+{
+    return domain_has_perm(d1, d2, SECCLASS_GRANT, GRANT__COPY);
+}
+
+static int flask_grant_query_size(struct domain *d1, struct domain *d2)
+{
+    return domain_has_perm(d1, d2, SECCLASS_GRANT, GRANT__QUERY);
+}
+
+static int get_page_sid(unsigned long mfn, u32 *sid)
+{
+    int rc = 0;
+    struct domain *d;
+    struct page_info *page;
+    struct domain_security_struct *dsec;
+
+    if ( mfn_valid(mfn) )
+    {
+        /*mfn is valid if this is a page that Xen is tracking!*/
+        page = mfn_to_page(mfn);        
+        d = page_get_owner(page);
+
+        if ( d == NULL )
+        {
+            rc = security_iomem_sid(mfn, sid);
+            goto out;
+        }
+
+        switch ( d->domain_id )
+        {
+            case DOMID_IO:
+                /*A tracked IO page?*/
+                *sid = SECINITSID_DOMIO;
+            break;
+
+            case DOMID_XEN:
+                /*A page from Xen's private heap?*/
+                *sid = SECINITSID_DOMXEN;
+            break;
+
+            default:
+                /*Pages are implicitly labeled by domain ownership!*/
+                dsec = d->ssid;
+                *sid = dsec->sid;
+            break;
+        }
+
+    }
+    else
+    {
+        /*Possibly an untracked IO page?*/
+        rc = security_iomem_sid(mfn, sid);
+    }
+
+out:
+    return rc;    
+}
+
+static int flask_translate_gpfn_list(struct domain *d, unsigned long mfn)
+{
+    int rc = 0;
+    u32 sid;
+    struct domain_security_struct *dsec;
+    dsec = d->ssid;
+
+    rc = get_page_sid(mfn, &sid);
+    if ( rc )
+        return rc;
+
+    return avc_has_perm(dsec->sid, sid, SECCLASS_MMU, MMU__TRANSLATEGP, NULL);
+}
+
+static int flask_memory_adjust_reservation(struct domain *d1, struct domain *d2)
+{
+    return domain_has_perm(d1, d2, SECCLASS_MMU, MMU__ADJUST);
+}
+
+static int flask_memory_stat_reservation(struct domain *d1, struct domain *d2)
+{
+    return domain_has_perm(d1, d2, SECCLASS_MMU, MMU__STAT);
+}
+
+static int flask_memory_pin_page(struct domain *d, unsigned long mfn)
+{
+    int rc = 0;
+    u32 sid;
+    struct domain_security_struct *dsec;
+    dsec = d->ssid;
+
+    rc = get_page_sid(mfn, &sid);
+    if ( rc )
+        return rc;
+
+    return avc_has_perm(dsec->sid, sid, SECCLASS_MMU, MMU__PINPAGE, NULL);
+}
+
+/* Used to defer flushing of memory structures. */
+struct percpu_mm_info {
+#define DOP_FLUSH_TLB      (1<<0) /* Flush the local TLB.                    */
+#define DOP_FLUSH_ALL_TLBS (1<<1) /* Flush TLBs of all VCPUs of current dom. */
+#define DOP_RELOAD_LDT     (1<<2) /* Reload the LDT shadow mapping.          */
+    unsigned int   deferred_ops;
+    /* If non-NULL, specifies a foreign subject domain for some operations. */
+    struct domain *foreign;
+};
+static DEFINE_PER_CPU(struct percpu_mm_info, percpu_mm_info);
+
+/*
+ * Returns the current foreign domain; defaults to the currently-executing
+ * domain if a foreign override hasn't been specified.
+ */
+#define FOREIGNDOM (this_cpu(percpu_mm_info).foreign ?: current->domain)
+
+static int flask_update_va_mapping(struct domain *d, l1_pgentry_t pte)
+{
+    int rc = 0;
+    u32 psid;
+    u32 map_perms = MMU__MAP_READ;
+    unsigned long mfn;
+    struct domain_security_struct *dsec;
+
+    dsec = d->ssid;
+
+    mfn = gmfn_to_mfn(FOREIGNDOM, l1e_get_pfn(pte));        
+    rc = get_page_sid(mfn, &psid);
+    if ( rc )
+        return rc;
+
+    if ( l1e_get_flags(pte) & _PAGE_RW )
+        map_perms |= MMU__MAP_WRITE;
+
+    return avc_has_perm(dsec->sid, psid, SECCLASS_MMU, map_perms, NULL);
+}
+
+static int flask_console_io(struct domain *d, int cmd)
+{
+    u32 perm;
+
+    switch ( cmd )
+    {
+        case CONSOLEIO_read:
+            perm = XEN__READCONSOLE;
+        break;
+        case CONSOLEIO_write:
+            perm = XEN__WRITECONSOLE;
+        break;
+        default:
+            return -EPERM;
+    }
+
+    return domain_has_xen(d, perm);
+}
+
+static int flask_profile(struct domain *d, int op)
+{
+    u32 perm;
+
+    switch ( op )
+    {
+        case XENOPROF_init:
+        case XENOPROF_enable_virq:
+        case XENOPROF_disable_virq:
+        case XENOPROF_get_buffer:
+            perm = XEN__NONPRIVPROFILE;
+        break;
+        case XENOPROF_reset_active_list:
+        case XENOPROF_reset_passive_list:
+        case XENOPROF_set_active:
+        case XENOPROF_set_passive:
+        case XENOPROF_reserve_counters:
+        case XENOPROF_counter:
+        case XENOPROF_setup_events:
+        case XENOPROF_start:
+        case XENOPROF_stop:
+        case XENOPROF_release_counters:
+        case XENOPROF_shutdown:
+            perm = XEN__PRIVPROFILE;
+        break;
+        default:
+            return -EPERM;
+    }
+
+    return domain_has_xen(d, perm);
+}
+
+static int flask_kexec(void)
+{
+    return domain_has_xen(current->domain, XEN__KEXEC);
+}
+
+static int flask_schedop_shutdown(struct domain *d1, struct domain *d2)
+{
+    return domain_has_perm(d1, d2, SECCLASS_DOMAIN, DOMAIN__SHUTDOWN);
+}
+
+static void flask_security_domaininfo(struct domain *d, 
+                                        struct xen_domctl_getdomaininfo *info)
+{
+    struct domain_security_struct *dsec;
+
+    dsec = d->ssid;
+    info->ssidref = dsec->sid;
+}
+
+static int flask_setvcpucontext(struct domain *d)
+{
+    return domain_has_perm(current->domain, d, SECCLASS_DOMAIN, 
+                                                        DOMAIN__SETVCPUCONTEXT);
+}
+
+static int flask_pausedomain(struct domain *d)
+{
+    return domain_has_perm(current->domain, d, SECCLASS_DOMAIN, DOMAIN__PAUSE);
+}
+
+static int flask_unpausedomain(struct domain *d)
+{
+    return domain_has_perm(current->domain, d, SECCLASS_DOMAIN, DOMAIN__UNPAUSE);
+}
+
+static int flask_resumedomain(struct domain *d)
+{
+    return domain_has_perm(current->domain, d, SECCLASS_DOMAIN, DOMAIN__RESUME);
+}
+
+static int flask_domain_create(struct domain *d, u32 ssidref)
+{
+    int rc;
+    struct domain_security_struct *dsec1;
+    struct domain_security_struct *dsec2;
+
+    dsec1 = current->domain->ssid;
+
+    if ( dsec1->create_sid == SECSID_NULL )
+        dsec1->create_sid = ssidref;
+
+    rc = avc_has_perm(dsec1->sid, dsec1->create_sid, SECCLASS_DOMAIN, 
+                                                        DOMAIN__CREATE, NULL);
+    if ( rc )
+    {
+        dsec1->create_sid = SECSID_NULL;
+        return rc;
+    }
+
+    dsec2 = d->ssid;
+    dsec2->sid = dsec1->create_sid;
+
+    dsec1->create_sid = SECSID_NULL;
+    dsec2->create_sid = SECSID_NULL;
+
+    return rc;
+}
+
+static int flask_max_vcpus(struct domain *d)
+{
+    return domain_has_perm(current->domain, d, SECCLASS_DOMAIN, 
+                                                            DOMAIN__MAX_VCPUS);
+}
+
+static int flask_destroydomain(struct domain *d)
+{
+    return domain_has_perm(current->domain, d, SECCLASS_DOMAIN, 
+                                                            DOMAIN__DESTROY);
+}
+
+static int flask_vcpuaffinity(int cmd, struct domain *d)
+{
+    u32 perm;
+
+    switch ( cmd )
+    {
+        case XEN_DOMCTL_setvcpuaffinity:
+            perm = DOMAIN__SETVCPUAFFINITY;
+        break;
+        case XEN_DOMCTL_getvcpuaffinity:
+            perm = DOMAIN__GETVCPUAFFINITY;
+        break;
+        default:
+            return -EPERM;
+    }
+
+    return domain_has_perm(current->domain, d, SECCLASS_DOMAIN, perm );
+}
+
+static int flask_scheduler(struct domain *d)
+{
+    int rc = 0;
+
+    rc = domain_has_xen(current->domain, XEN__SCHEDULER);
+    if ( rc )
+        return rc;
+
+    return domain_has_perm(current->domain, d, SECCLASS_DOMAIN, 
+                                                            DOMAIN__SCHEDULER);
+}
+
+static int flask_getdomaininfo(struct domain *d)
+{
+    return domain_has_perm(current->domain, d, SECCLASS_DOMAIN,
+                                                        DOMAIN__GETDOMAININFO);
+}
+
+static int flask_getvcpucontext(struct domain *d)
+{
+    return domain_has_perm(current->domain, d, SECCLASS_DOMAIN, 
+                                                        DOMAIN__GETVCPUCONTEXT);
+}
+
+static int flask_getvcpuinfo(struct domain *d)
+{
+    return domain_has_perm(current->domain, d, SECCLASS_DOMAIN,
+                                                        DOMAIN__GETVCPUINFO);
+}
+
+static int flask_domain_settime(struct domain *d)
+{
+    return domain_has_perm(current->domain, d, SECCLASS_DOMAIN, DOMAIN__SETTIME);
+}
+
+static int flask_tbufcontrol(void)
+{
+    return domain_has_xen(current->domain, SECCLASS_XEN);
+}
+
+static int flask_readconsole(uint32_t clear)
+{
+    u32 perms = XEN__READCONSOLE;
+
+    if ( clear )
+        perms |= XEN__CLEARCONSOLE;
+
+    return domain_has_xen(current->domain, perms);
+}
+
+static int flask_sched_id(void)
+{
+    return domain_has_xen(current->domain, XEN__SCHEDULER);
+}
+
+static int flask_setdomainmaxmem(struct domain *d)
+{
+    return domain_has_perm(current->domain, d, SECCLASS_DOMAIN,
+                                                    DOMAIN__SETDOMAINMAXMEM);
+}
+
+static int flask_setdomainhandle(struct domain *d)
+{
+    return domain_has_perm(current->domain, d, SECCLASS_DOMAIN,
+                                                    DOMAIN__SETDOMAINHANDLE);
+}
+
+static int flask_setdebugging(struct domain *d)
+{
+    return domain_has_perm(current->domain, d, SECCLASS_DOMAIN,
+                                                        DOMAIN__SETDEBUGGING);
+}
+
+static inline u32 resource_to_perm(uint8_t access)
+{
+    if ( access )
+        return RESOURCE__ADD;
+    else
+        return RESOURCE__REMOVE;
+}
+
+static int flask_irq_permission(struct domain *d, uint8_t pirq, uint8_t access)
+{
+    u32 perm;
+    u32 rsid;
+    int rc = -EPERM;
+
+    struct domain_security_struct *ssec, *tsec;
+
+    rc = domain_has_perm(current->domain, d, SECCLASS_RESOURCE,
+                                                    resource_to_perm(access));
+
+    if ( rc )
+        return rc;
+
+    if ( access )
+        perm = RESOURCE__ADD_IRQ;
+    else
+        perm = RESOURCE__REMOVE_IRQ;
+
+    ssec = current->domain->ssid;
+    tsec = d->ssid;
+
+    rc = security_pirq_sid(pirq, &rsid);
+    if ( rc )
+        return rc;
+
+    rc = avc_has_perm(ssec->sid, rsid, SECCLASS_RESOURCE, perm, NULL);
+
+    if ( rc )
+        return rc;
+
+    return avc_has_perm(tsec->sid, rsid, SECCLASS_RESOURCE, 
+                                                        RESOURCE__USE, NULL);
+}
+
+static int flask_iomem_permission(struct domain *d, unsigned long mfn, 
+                                                                uint8_t access)
+{
+    u32 perm;
+    u32 rsid;
+    int rc = -EPERM;
+
+    struct domain_security_struct *ssec, *tsec;
+
+    rc = domain_has_perm(current->domain, d, SECCLASS_RESOURCE,
+                                                    resource_to_perm(access));
+
+    if ( rc )
+        return rc;
+
+    if ( access )
+        perm = RESOURCE__ADD_IOMEM;
+    else
+        perm = RESOURCE__REMOVE_IOMEM;
+
+    ssec = current->domain->ssid;
+    tsec = d->ssid;
+
+    rc = security_iomem_sid(mfn, &rsid);
+    if ( rc )
+        return rc;
+
+    rc = avc_has_perm(ssec->sid, rsid, SECCLASS_RESOURCE, perm, NULL);
+
+    if ( rc )
+        return rc;
+
+    return avc_has_perm(tsec->sid, rsid, SECCLASS_RESOURCE, 
+                                                        RESOURCE__USE, NULL);
+}
+
+static int flask_perfcontrol(void)
+{
+    return domain_has_xen(current->domain, XEN__PERFCONTROL);
+}
+
+void flask_complete_init(struct domain *d)
+{
+    struct domain_security_struct *dsec;
+
+    /* Set the security state for the Dom0 domain. */
+    dsec = d->ssid;
+    dsec->sid = SECINITSID_DOM0;
+    dsec->create_sid = SECINITSID_UNLABELED;
+
+    printk("Flask:  Completed initialization.\n");
+}
+
+#ifdef CONFIG_X86
+static int flask_shadow_control(struct domain *d, uint32_t op)
+{
+    u32 perm;
+
+    switch ( op )
+    {
+        case XEN_DOMCTL_SHADOW_OP_OFF:
+            perm = SHADOW__DISABLE;
+        break;
+        case XEN_DOMCTL_SHADOW_OP_ENABLE:
+        case XEN_DOMCTL_SHADOW_OP_ENABLE_TEST:
+        case XEN_DOMCTL_SHADOW_OP_ENABLE_TRANSLATE:
+        case XEN_DOMCTL_SHADOW_OP_GET_ALLOCATION:
+        case XEN_DOMCTL_SHADOW_OP_SET_ALLOCATION:
+            perm = SHADOW__ENABLE;
+        break;
+        case XEN_DOMCTL_SHADOW_OP_ENABLE_LOGDIRTY:
+        case XEN_DOMCTL_SHADOW_OP_PEEK:
+        case XEN_DOMCTL_SHADOW_OP_CLEAN:
+            perm = SHADOW__LOGDIRTY;
+        break;
+        default:
+            return -EPERM;
+    }
+
+    return domain_has_perm(current->domain, d, SECCLASS_SHADOW, perm);
+}
+
+static int flask_ioport_permission(struct domain *d, uint32_t ioport, 
+                                                                uint8_t access)
+{
+    u32 perm;
+    u32 rsid;
+    int rc = -EPERM;
+
+    struct domain_security_struct *ssec, *tsec;
+
+    rc = domain_has_perm(current->domain, d, SECCLASS_RESOURCE,
+                                                    resource_to_perm(access));
+
+    if ( rc )
+        return rc;
+
+    if ( access )
+        perm = RESOURCE__ADD_IOPORT;
+    else
+        perm = RESOURCE__REMOVE_IOPORT;
+
+    ssec = current->domain->ssid;
+    tsec = d->ssid;
+
+    rc = security_ioport_sid(ioport, &rsid);
+    if ( rc )
+        return rc;
+
+    rc = avc_has_perm(ssec->sid, rsid, SECCLASS_RESOURCE, perm, NULL);
+    if ( rc )
+        return rc;
+
+    return avc_has_perm(tsec->sid, rsid, SECCLASS_RESOURCE, 
+                                                        RESOURCE__USE, NULL);    
+}
+
+static int flask_getpageframeinfo(unsigned long mfn)
+{
+    struct page_info *page;
+    struct domain *d;
+    struct domain_security_struct *ssec, *tsec;
+
+    ssec = current->domain->ssid;
+
+    if ( mfn_valid(mfn) )
+        page = mfn_to_page(mfn);
+    else
+        return -EPERM;
+
+    d = page_get_owner(page);
+
+    tsec = d->ssid;
+
+    return avc_has_perm(ssec->sid, tsec->sid, SECCLASS_MMU, 
+                                                        MMU__PAGEINFO, NULL);    
+}
+
+static int flask_getmemlist(struct domain *d)
+{
+    return domain_has_perm(current->domain, d, SECCLASS_MMU, MMU__PAGELIST);
+}
+
+static int flask_hypercall_init(struct domain *d)
+{
+    return domain_has_perm(current->domain, d, SECCLASS_DOMAIN,
+                                                            DOMAIN__HYPERCALL);
+}
+
+static int flask_hvmcontext(struct domain *d, uint32_t cmd)
+{
+    u32 perm;
+
+    switch ( cmd )
+    {
+        case XEN_DOMCTL_sethvmcontext:
+            perm = HVM__SETHVMC;
+        break;
+        case XEN_DOMCTL_gethvmcontext:
+            perm = HVM__GETHVMC;
+        break;
+        default:
+            return -EPERM;
+    }
+
+    return domain_has_perm(current->domain, d, SECCLASS_HVM, perm);
+}
+
+static int flask_address_size(struct domain *d, uint32_t cmd)
+{
+    u32 perm;
+
+    switch ( cmd )
+    {
+        case XEN_DOMCTL_set_address_size:
+            perm = DOMAIN__SETADDRSIZE;
+        break;
+        case XEN_DOMCTL_get_address_size:
+            perm = DOMAIN__GETADDRSIZE;
+        break;
+        default:
+            return -EPERM;
+    }
+
+    return domain_has_perm(current->domain, d, SECCLASS_DOMAIN, perm);
+}
+
+static int flask_hvm_param(struct domain *d, unsigned long op)
+{
+    u32 perm;
+
+    switch ( op )
+    {
+        case HVMOP_set_param:
+            perm = HVM__SETPARAM;
+        break;
+        case HVMOP_get_param:
+            perm = HVM__GETPARAM;
+        break;
+        default:
+            return -EPERM;
+    }
+
+    return domain_has_perm(current->domain, d, SECCLASS_HVM, perm);
+}
+
+static int flask_hvm_set_pci_intx_level(struct domain *d)
+{
+    return domain_has_perm(current->domain, d, SECCLASS_HVM, HVM__PCILEVEL);
+}
+
+static int flask_hvm_set_isa_irq_level(struct domain *d)
+{
+    return domain_has_perm(current->domain, d, SECCLASS_HVM, HVM__IRQLEVEL);
+}
+
+static int flask_hvm_set_pci_link_route(struct domain *d)
+{
+    return domain_has_perm(current->domain, d, SECCLASS_HVM, HVM__PCIROUTE);
+}
+
+static int flask_pirq_unmask(struct domain *d, int pirq)
+{
+    u32 psid;
+    struct domain_security_struct *dsec;
+    dsec = d->ssid;
+
+    if ( security_pirq_sid(pirq, &psid) )
+        return -EPERM;
+
+    return avc_has_perm(dsec->sid, psid, SECCLASS_EVENT, EVENT__UNMASK, NULL);
+}
+
+static int flask_pirq_status(struct domain *d, int pirq)
+{
+    u32 psid;
+    struct domain_security_struct *dsec;
+    dsec = d->ssid;
+
+    if ( security_pirq_sid(pirq, &psid) )
+        return -EPERM;
+
+    return avc_has_perm(dsec->sid, psid, SECCLASS_EVENT, EVENT__STATUS, NULL);
+}
+
+static int flask_apic(struct domain *d, int cmd)
+{
+    u32 perm;
+
+    switch ( cmd )
+    {
+        case PHYSDEVOP_APIC_READ:
+            perm = XEN__READAPIC;
+        break;
+        case PHYSDEVOP_APIC_WRITE:
+            perm = XEN__WRITEAPIC;
+        break;
+        default:
+            return -EPERM;
+    }
+
+    return domain_has_xen(d, perm);
+}
+
+static int flask_assign_vector(struct domain *d, uint32_t pirq)
+{
+    u32 psid;
+    struct domain_security_struct *dsec;
+    dsec = d->ssid;
+
+    if ( security_pirq_sid(pirq, &psid) )
+        return -EPERM;
+
+    return avc_has_perm(dsec->sid, psid, SECCLASS_EVENT, EVENT__VECTOR, NULL);
+}
+
+static int flask_xen_settime(void)
+{
+    return domain_has_xen(current->domain, XEN__SETTIME);
+}
+
+static int flask_memtype(uint32_t access)
+{
+    u32 perm;
+
+    switch ( access )
+    {
+        case XENPF_add_memtype:
+            perm = XEN__MTRR_ADD;
+        break;
+        case XENPF_del_memtype:
+            perm = XEN__MTRR_DEL;
+        break;
+        case XENPF_read_memtype:
+            perm = XEN__MTRR_READ;
+        break;
+        default:
+            return -EPERM;
+    }
+
+    return domain_has_xen(current->domain, perm);
+}
+
+static int flask_microcode(void)
+{
+    return domain_has_xen(current->domain, XEN__MICROCODE);
+}
+
+static int flask_physinfo(void)
+{
+    return domain_has_xen(current->domain, XEN__PHYSINFO);
+}
+
+static int flask_platform_quirk(uint32_t quirk)
+{
+    struct domain_security_struct *dsec;
+    dsec = current->domain->ssid;
+
+    return avc_has_perm(dsec->sid, SECINITSID_XEN, SECCLASS_XEN, 
+                                                            XEN__QUIRK, NULL);
+}
+
+static int flask_machine_memory_map(void)
+{
+    struct domain_security_struct *dsec;
+    dsec = current->domain->ssid;
+
+    return avc_has_perm(dsec->sid, SECINITSID_XEN, SECCLASS_MMU, 
+                                                          MMU__MEMORYMAP, NULL);
+}
+
+static int flask_domain_memory_map(struct domain *d1, struct domain *d2)
+{
+    return domain_has_perm(d1, d2, SECCLASS_MMU, MMU__MEMORYMAP);
+}
+
+static int flask_mmu_normal_update(struct domain *d, intpte_t fpte)
+{
+    int rc = 0;
+    u32 map_perms = MMU__MAP_READ;
+    unsigned long fmfn;
+    struct domain_security_struct *dsec;
+    u32 fsid;
+
+    dsec = d->ssid;
+
+    if ( l1e_get_flags(l1e_from_intpte(fpte)) & _PAGE_RW )
+        map_perms |= MMU__MAP_WRITE;
+
+    fmfn = gmfn_to_mfn(FOREIGNDOM, l1e_get_pfn(l1e_from_intpte(fpte)));
+
+    rc = get_page_sid(fmfn, &fsid);
+    if ( rc )
+        return rc;
+
+    return avc_has_perm(dsec->sid, fsid, SECCLASS_MMU, map_perms, NULL);
+}
+
+static int flask_mmu_machphys_update(struct domain *d, unsigned long mfn)
+{
+    int rc = 0;
+    u32 psid;
+    struct domain_security_struct *dsec;
+    dsec = d->ssid;
+
+    rc = get_page_sid(mfn, &psid);
+    if ( rc )
+        return rc;
+
+    return avc_has_perm(dsec->sid, psid, SECCLASS_MMU, MMU__UPDATEMP, NULL);
+}
+
+static int flask_add_to_physmap(struct domain *d1, struct domain *d2)
+{
+    return domain_has_perm(d1, d2, SECCLASS_MMU, MMU__PHYSMAP);
+}
+#endif
+
+static struct xsm_operations flask_ops = {
+    .security_domaininfo = flask_security_domaininfo,
+    .setvcpucontext = flask_setvcpucontext,
+    .pausedomain = flask_pausedomain,
+    .unpausedomain = flask_unpausedomain,    
+    .resumedomain = flask_resumedomain,    
+    .domain_create = flask_domain_create,
+    .max_vcpus = flask_max_vcpus,
+    .destroydomain = flask_destroydomain,
+    .vcpuaffinity = flask_vcpuaffinity,
+    .scheduler = flask_scheduler,
+    .getdomaininfo = flask_getdomaininfo,
+    .getvcpucontext = flask_getvcpucontext,
+    .getvcpuinfo = flask_getvcpuinfo,
+    .domain_settime = flask_domain_settime,
+    .tbufcontrol = flask_tbufcontrol,
+    .readconsole = flask_readconsole,
+    .sched_id = flask_sched_id,
+    .setdomainmaxmem = flask_setdomainmaxmem,
+    .setdomainhandle = flask_setdomainhandle,
+    .setdebugging = flask_setdebugging,
+    .irq_permission = flask_irq_permission,
+    .iomem_permission = flask_iomem_permission,
+    .perfcontrol = flask_perfcontrol,
+
+    .evtchn_unbound = flask_evtchn_unbound,
+    .evtchn_interdomain = flask_evtchn_interdomain,
+    .evtchn_close_post = flask_evtchn_close_post,
+    .evtchn_send = flask_evtchn_send,
+    .evtchn_status = flask_evtchn_status,
+    .evtchn_reset = flask_evtchn_reset,
+
+    .grant_mapref = flask_grant_mapref,
+    .grant_unmapref = flask_grant_unmapref,
+    .grant_setup = flask_grant_setup,
+    .grant_transfer = flask_grant_transfer,
+    .grant_copy = flask_grant_copy,
+    .grant_query_size = flask_grant_query_size,
+
+    .alloc_security_domain = flask_domain_alloc_security,
+    .free_security_domain = flask_domain_free_security,
+    .alloc_security_evtchn = flask_alloc_security_evtchn,
+    .free_security_evtchn = flask_free_security_evtchn,
+
+    .translate_gpfn_list = flask_translate_gpfn_list,
+    .memory_adjust_reservation = flask_memory_adjust_reservation,
+    .memory_stat_reservation = flask_memory_stat_reservation,
+    .memory_pin_page = flask_memory_pin_page,
+    .update_va_mapping = flask_update_va_mapping,
+
+    .console_io = flask_console_io,
+
+    .profile = flask_profile,
+
+    .kexec = flask_kexec,
+    .schedop_shutdown = flask_schedop_shutdown,
+
+    .__do_xsm_op = do_flask_op,
+    .complete_init = flask_complete_init,    
+
+#ifdef CONFIG_X86
+    .shadow_control = flask_shadow_control,
+    .ioport_permission = flask_ioport_permission,
+    .getpageframeinfo = flask_getpageframeinfo,
+    .getmemlist = flask_getmemlist,
+    .hypercall_init = flask_hypercall_init,
+    .hvmcontext = flask_hvmcontext,
+    .address_size = flask_address_size,
+    .hvm_param = flask_hvm_param,
+    .hvm_set_pci_intx_level = flask_hvm_set_pci_intx_level,
+    .hvm_set_isa_irq_level = flask_hvm_set_isa_irq_level,
+    .hvm_set_pci_link_route = flask_hvm_set_pci_link_route,
+    .pirq_unmask = flask_pirq_unmask,
+    .pirq_status = flask_pirq_status,
+    .apic = flask_apic,
+    .assign_vector = flask_assign_vector,
+    .xen_settime = flask_xen_settime,
+    .memtype = flask_memtype,
+    .microcode = flask_microcode,
+    .physinfo = flask_physinfo,
+    .platform_quirk = flask_platform_quirk,
+    .machine_memory_map = flask_machine_memory_map,
+    .domain_memory_map = flask_domain_memory_map,
+    .mmu_normal_update = flask_mmu_normal_update,
+    .mmu_machphys_update = flask_mmu_machphys_update,
+    .add_to_physmap = flask_add_to_physmap,
+#endif
+};
+
+static __init int flask_init(void)
+{
+    int ret = 0;
+
+    if ( !flask_enabled ) {
+        printk("Flask:  Disabled at boot.\n");
+        return 0;
+    }
+
+    printk("Flask:  Initializing.\n");
+
+    avc_init();
+
+    original_ops = xsm_ops;
+    if ( register_xsm(&flask_ops) )
+        panic("Flask: Unable to register with XSM.\n");
+
+    ret = security_load_policy(policy_buffer, policy_size);
+
+    if ( flask_enforcing )
+        printk("Flask:  Starting in enforcing mode.\n");
+    else
+        printk("Flask:  Starting in permissive mode.\n");
+
+    return ret;
+}
+
+xsm_initcall(flask_init);
diff -r cb2ecf48cf80 -r 8ae246493872 xen/xsm/flask/include/av_inherit.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/include/av_inherit.h	Mon Jun 04 11:06:52 2007 -0400
@@ -0,0 +1,1 @@
+/* This file is automatically generated.  Do not edit. */
diff -r cb2ecf48cf80 -r 8ae246493872 xen/xsm/flask/include/av_perm_to_string.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/include/av_perm_to_string.h	Mon Jun 04 11:06:52 2007 -0400
@@ -0,0 +1,99 @@
+/* This file is automatically generated.  Do not edit. */
+   S_(SECCLASS_XEN, XEN__SCHEDULER, "scheduler")
+   S_(SECCLASS_XEN, XEN__SETTIME, "settime")
+   S_(SECCLASS_XEN, XEN__TBUFCONTROL, "tbufcontrol")
+   S_(SECCLASS_XEN, XEN__READCONSOLE, "readconsole")
+   S_(SECCLASS_XEN, XEN__CLEARCONSOLE, "clearconsole")
+   S_(SECCLASS_XEN, XEN__PERFCONTROL, "perfcontrol")
+   S_(SECCLASS_XEN, XEN__MTRR_ADD, "mtrr_add")
+   S_(SECCLASS_XEN, XEN__MTRR_DEL, "mtrr_del")
+   S_(SECCLASS_XEN, XEN__MTRR_READ, "mtrr_read")
+   S_(SECCLASS_XEN, XEN__MICROCODE, "microcode")
+   S_(SECCLASS_XEN, XEN__PHYSINFO, "physinfo")
+   S_(SECCLASS_XEN, XEN__QUIRK, "quirk")
+   S_(SECCLASS_XEN, XEN__WRITECONSOLE, "writeconsole")
+   S_(SECCLASS_XEN, XEN__READAPIC, "readapic")
+   S_(SECCLASS_XEN, XEN__WRITEAPIC, "writeapic")
+   S_(SECCLASS_XEN, XEN__PRIVPROFILE, "privprofile")
+   S_(SECCLASS_XEN, XEN__NONPRIVPROFILE, "nonprivprofile")
+   S_(SECCLASS_XEN, XEN__KEXEC, "kexec")
+   S_(SECCLASS_DOMAIN, DOMAIN__SETVCPUCONTEXT, "setvcpucontext")
+   S_(SECCLASS_DOMAIN, DOMAIN__PAUSE, "pause")
+   S_(SECCLASS_DOMAIN, DOMAIN__UNPAUSE, "unpause")
+   S_(SECCLASS_DOMAIN, DOMAIN__RESUME, "resume")
+   S_(SECCLASS_DOMAIN, DOMAIN__CREATE, "create")
+   S_(SECCLASS_DOMAIN, DOMAIN__MAX_VCPUS, "max_vcpus")
+   S_(SECCLASS_DOMAIN, DOMAIN__DESTROY, "destroy")
+   S_(SECCLASS_DOMAIN, DOMAIN__SETVCPUAFFINITY, "setvcpuaffinity")
+   S_(SECCLASS_DOMAIN, DOMAIN__GETVCPUAFFINITY, "getvcpuaffinity")
+   S_(SECCLASS_DOMAIN, DOMAIN__SCHEDULER, "scheduler")
+   S_(SECCLASS_DOMAIN, DOMAIN__GETDOMAININFO, "getdomaininfo")
+   S_(SECCLASS_DOMAIN, DOMAIN__GETVCPUINFO, "getvcpuinfo")
+   S_(SECCLASS_DOMAIN, DOMAIN__GETVCPUCONTEXT, "getvcpucontext")
+   S_(SECCLASS_DOMAIN, DOMAIN__SETDOMAINMAXMEM, "setdomainmaxmem")
+   S_(SECCLASS_DOMAIN, DOMAIN__SETDOMAINHANDLE, "setdomainhandle")
+   S_(SECCLASS_DOMAIN, DOMAIN__SETDEBUGGING, "setdebugging")
+   S_(SECCLASS_DOMAIN, DOMAIN__HYPERCALL, "hypercall")
+   S_(SECCLASS_DOMAIN, DOMAIN__TRANSITION, "transition")
+   S_(SECCLASS_DOMAIN, DOMAIN__SETTIME, "settime")
+   S_(SECCLASS_DOMAIN, DOMAIN__SHUTDOWN, "shutdown")
+   S_(SECCLASS_DOMAIN, DOMAIN__SETADDRSIZE, "setaddrsize")
+   S_(SECCLASS_DOMAIN, DOMAIN__GETADDRSIZE, "getaddrsize")
+   S_(SECCLASS_HVM, HVM__SETHVMC, "sethvmc")
+   S_(SECCLASS_HVM, HVM__GETHVMC, "gethvmc")
+   S_(SECCLASS_HVM, HVM__SETPARAM, "setparam")
+   S_(SECCLASS_HVM, HVM__GETPARAM, "getparam")
+   S_(SECCLASS_HVM, HVM__PCILEVEL, "pcilevel")
+   S_(SECCLASS_HVM, HVM__IRQLEVEL, "irqlevel")
+   S_(SECCLASS_HVM, HVM__PCIROUTE, "pciroute")
+   S_(SECCLASS_EVENT, EVENT__BIND, "bind")
+   S_(SECCLASS_EVENT, EVENT__CLOSE, "close")
+   S_(SECCLASS_EVENT, EVENT__SEND, "send")
+   S_(SECCLASS_EVENT, EVENT__STATUS, "status")
+   S_(SECCLASS_EVENT, EVENT__UNMASK, "unmask")
+   S_(SECCLASS_EVENT, EVENT__NOTIFY, "notify")
+   S_(SECCLASS_EVENT, EVENT__CREATE, "create")
+   S_(SECCLASS_EVENT, EVENT__ALLOC, "alloc")
+   S_(SECCLASS_EVENT, EVENT__VECTOR, "vector")
+   S_(SECCLASS_EVENT, EVENT__RESET, "reset")
+   S_(SECCLASS_GRANT, GRANT__MAP_READ, "map_read")
+   S_(SECCLASS_GRANT, GRANT__MAP_WRITE, "map_write")
+   S_(SECCLASS_GRANT, GRANT__UNMAP, "unmap")
+   S_(SECCLASS_GRANT, GRANT__TRANSFER, "transfer")
+   S_(SECCLASS_GRANT, GRANT__SETUP, "setup")
+   S_(SECCLASS_GRANT, GRANT__COPY, "copy")
+   S_(SECCLASS_GRANT, GRANT__QUERY, "query")
+   S_(SECCLASS_MMU, MMU__MAP_READ, "map_read")
+   S_(SECCLASS_MMU, MMU__MAP_WRITE, "map_write")
+   S_(SECCLASS_MMU, MMU__PAGEINFO, "pageinfo")
+   S_(SECCLASS_MMU, MMU__PAGELIST, "pagelist")
+   S_(SECCLASS_MMU, MMU__ADJUST, "adjust")
+   S_(SECCLASS_MMU, MMU__STAT, "stat")
+   S_(SECCLASS_MMU, MMU__TRANSLATEGP, "translategp")
+   S_(SECCLASS_MMU, MMU__UPDATEMP, "updatemp")
+   S_(SECCLASS_MMU, MMU__PHYSMAP, "physmap")
+   S_(SECCLASS_MMU, MMU__PINPAGE, "pinpage")
+   S_(SECCLASS_MMU, MMU__MFNLIST, "mfnlist")
+   S_(SECCLASS_MMU, MMU__MEMORYMAP, "memorymap")
+   S_(SECCLASS_SHADOW, SHADOW__DISABLE, "disable")
+   S_(SECCLASS_SHADOW, SHADOW__ENABLE, "enable")
+   S_(SECCLASS_SHADOW, SHADOW__LOGDIRTY, "logdirty")
+   S_(SECCLASS_RESOURCE, RESOURCE__ADD, "add")
+   S_(SECCLASS_RESOURCE, RESOURCE__REMOVE, "remove")
+   S_(SECCLASS_RESOURCE, RESOURCE__USE, "use")
+   S_(SECCLASS_RESOURCE, RESOURCE__ADD_IRQ, "add_irq")
+   S_(SECCLASS_RESOURCE, RESOURCE__REMOVE_IRQ, "remove_irq")
+   S_(SECCLASS_RESOURCE, RESOURCE__ADD_IOPORT, "add_ioport")
+   S_(SECCLASS_RESOURCE, RESOURCE__REMOVE_IOPORT, "remove_ioport")
+   S_(SECCLASS_RESOURCE, RESOURCE__ADD_IOMEM, "add_iomem")
+   S_(SECCLASS_RESOURCE, RESOURCE__REMOVE_IOMEM, "remove_iomem")
+   S_(SECCLASS_SECURITY, SECURITY__COMPUTE_AV, "compute_av")
+   S_(SECCLASS_SECURITY, SECURITY__COMPUTE_CREATE, "compute_create")
+   S_(SECCLASS_SECURITY, SECURITY__COMPUTE_MEMBER, "compute_member")
+   S_(SECCLASS_SECURITY, SECURITY__CHECK_CONTEXT, "check_context")
+   S_(SECCLASS_SECURITY, SECURITY__LOAD_POLICY, "load_policy")
+   S_(SECCLASS_SECURITY, SECURITY__COMPUTE_RELABEL, "compute_relabel")
+   S_(SECCLASS_SECURITY, SECURITY__COMPUTE_USER, "compute_user")
+   S_(SECCLASS_SECURITY, SECURITY__SETENFORCE, "setenforce")
+   S_(SECCLASS_SECURITY, SECURITY__SETBOOL, "setbool")
+   S_(SECCLASS_SECURITY, SECURITY__SETSECPARAM, "setsecparam")
diff -r cb2ecf48cf80 -r 8ae246493872 xen/xsm/flask/include/av_permissions.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/include/av_permissions.h	Mon Jun 04 11:06:52 2007 -0400
@@ -0,0 +1,108 @@
+/* This file is automatically generated.  Do not edit. */
+#define XEN__SCHEDULER                            0x00000001UL
+#define XEN__SETTIME                              0x00000002UL
+#define XEN__TBUFCONTROL                          0x00000004UL
+#define XEN__READCONSOLE                          0x00000008UL
+#define XEN__CLEARCONSOLE                         0x00000010UL
+#define XEN__PERFCONTROL                          0x00000020UL
+#define XEN__MTRR_ADD                             0x00000040UL
+#define XEN__MTRR_DEL                             0x00000080UL
+#define XEN__MTRR_READ                            0x00000100UL
+#define XEN__MICROCODE                            0x00000200UL
+#define XEN__PHYSINFO                             0x00000400UL
+#define XEN__QUIRK                                0x00000800UL
+#define XEN__WRITECONSOLE                         0x00001000UL
+#define XEN__READAPIC                             0x00002000UL
+#define XEN__WRITEAPIC                            0x00004000UL
+#define XEN__PRIVPROFILE                          0x00008000UL
+#define XEN__NONPRIVPROFILE                       0x00010000UL
+#define XEN__KEXEC                                0x00020000UL
+
+#define DOMAIN__SETVCPUCONTEXT                    0x00000001UL
+#define DOMAIN__PAUSE                             0x00000002UL
+#define DOMAIN__UNPAUSE                           0x00000004UL
+#define DOMAIN__RESUME                            0x00000008UL
+#define DOMAIN__CREATE                            0x00000010UL
+#define DOMAIN__MAX_VCPUS                         0x00000020UL
+#define DOMAIN__DESTROY                           0x00000040UL
+#define DOMAIN__SETVCPUAFFINITY                   0x00000080UL
+#define DOMAIN__GETVCPUAFFINITY                   0x00000100UL
+#define DOMAIN__SCHEDULER                         0x00000200UL
+#define DOMAIN__GETDOMAININFO                     0x00000400UL
+#define DOMAIN__GETVCPUINFO                       0x00000800UL
+#define DOMAIN__GETVCPUCONTEXT                    0x00001000UL
+#define DOMAIN__SETDOMAINMAXMEM                   0x00002000UL
+#define DOMAIN__SETDOMAINHANDLE                   0x00004000UL
+#define DOMAIN__SETDEBUGGING                      0x00008000UL
+#define DOMAIN__HYPERCALL                         0x00010000UL
+#define DOMAIN__TRANSITION                        0x00020000UL
+#define DOMAIN__SETTIME                           0x00040000UL
+#define DOMAIN__SHUTDOWN                          0x00080000UL
+#define DOMAIN__SETADDRSIZE                       0x00100000UL
+#define DOMAIN__GETADDRSIZE                       0x00200000UL
+
+#define HVM__SETHVMC                              0x00000001UL
+#define HVM__GETHVMC                              0x00000002UL
+#define HVM__SETPARAM                             0x00000004UL
+#define HVM__GETPARAM                             0x00000008UL
+#define HVM__PCILEVEL                             0x00000010UL
+#define HVM__IRQLEVEL                             0x00000020UL
+#define HVM__PCIROUTE                             0x00000040UL
+
+#define EVENT__BIND                               0x00000001UL
+#define EVENT__CLOSE                              0x00000002UL
+#define EVENT__SEND                               0x00000004UL
+#define EVENT__STATUS                             0x00000008UL
+#define EVENT__UNMASK                             0x00000010UL
+#define EVENT__NOTIFY                             0x00000020UL
+#define EVENT__CREATE                             0x00000040UL
+#define EVENT__ALLOC                              0x00000080UL
+#define EVENT__VECTOR                             0x00000100UL
+#define EVENT__RESET                              0x00000200UL
+
+#define GRANT__MAP_READ                           0x00000001UL
+#define GRANT__MAP_WRITE                          0x00000002UL
+#define GRANT__UNMAP                              0x00000004UL
+#define GRANT__TRANSFER                           0x00000008UL
+#define GRANT__SETUP                              0x00000010UL
+#define GRANT__COPY                               0x00000020UL
+#define GRANT__QUERY                              0x00000040UL
+
+#define MMU__MAP_READ                             0x00000001UL
+#define MMU__MAP_WRITE                            0x00000002UL
+#define MMU__PAGEINFO                             0x00000004UL
+#define MMU__PAGELIST                             0x00000008UL
+#define MMU__ADJUST                               0x00000010UL
+#define MMU__STAT                                 0x00000020UL
+#define MMU__TRANSLATEGP                          0x00000040UL
+#define MMU__UPDATEMP                             0x00000080UL
+#define MMU__PHYSMAP                              0x00000100UL
+#define MMU__PINPAGE                              0x00000200UL
+#define MMU__MFNLIST                              0x00000400UL
+#define MMU__MEMORYMAP                            0x00000800UL
+
+#define SHADOW__DISABLE                           0x00000001UL
+#define SHADOW__ENABLE                            0x00000002UL
+#define SHADOW__LOGDIRTY                          0x00000004UL
+
+#define RESOURCE__ADD                             0x00000001UL
+#define RESOURCE__REMOVE                          0x00000002UL
+#define RESOURCE__USE                             0x00000004UL
+#define RESOURCE__ADD_IRQ                         0x00000008UL
+#define RESOURCE__REMOVE_IRQ                      0x00000010UL
+#define RESOURCE__ADD_IOPORT                      0x00000020UL
+#define RESOURCE__REMOVE_IOPORT                   0x00000040UL
+#define RESOURCE__ADD_IOMEM                       0x00000080UL
+#define RESOURCE__REMOVE_IOMEM                    0x00000100UL
+
+#define SECURITY__COMPUTE_AV                      0x00000001UL
+#define SECURITY__COMPUTE_CREATE                  0x00000002UL
+#define SECURITY__COMPUTE_MEMBER                  0x00000004UL
+#define SECURITY__CHECK_CONTEXT                   0x00000008UL
+#define SECURITY__LOAD_POLICY                     0x00000010UL
+#define SECURITY__COMPUTE_RELABEL                 0x00000020UL
+#define SECURITY__COMPUTE_USER                    0x00000040UL
+#define SECURITY__SETENFORCE                      0x00000080UL
+#define SECURITY__SETBOOL                         0x00000100UL
+#define SECURITY__SETSECPARAM                     0x00000200UL
+
diff -r cb2ecf48cf80 -r 8ae246493872 xen/xsm/flask/include/avc.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/include/avc.h	Mon Jun 04 11:06:52 2007 -0400
@@ -0,0 +1,106 @@
+/*
+ * Access vector cache interface for object managers.
+ *
+ * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
+ */
+ 
+/* Ported to Xen 3.0, George Coker, <gscoker@alpha.ncsc.mil> */
+
+#ifndef _FLASK_AVC_H_
+#define _FLASK_AVC_H_
+
+#include <xen/errno.h>
+#include <xen/lib.h>
+#include <xen/spinlock.h>
+#include <asm/percpu.h>
+#include "flask.h"
+#include "av_permissions.h"
+#include "security.h"
+
+#ifdef FLASK_DEVELOP
+extern int flask_enforcing;
+#else
+#define flask_enforcing 1
+#endif
+
+/*
+ * An entry in the AVC.
+ */
+struct avc_entry;
+
+struct task_struct;
+struct vfsmount;
+struct dentry;
+struct inode;
+struct sock;
+struct sk_buff;
+
+/* Auxiliary data to use in generating the audit record. */
+struct avc_audit_data {
+    char    type;
+#define AVC_AUDIT_DATA_FS   1
+#define AVC_AUDIT_DATA_NET  2
+#define AVC_AUDIT_DATA_CAP  3
+#define AVC_AUDIT_DATA_IPC  4
+    struct domain *d;
+};
+
+#define v4info fam.v4
+#define v6info fam.v6
+
+/* Initialize an AVC audit data structure. */
+#define AVC_AUDIT_DATA_INIT(_d,_t) \
+        { memset((_d), 0, sizeof(struct avc_audit_data)); \
+         (_d)->type = AVC_AUDIT_DATA_##_t; }
+
+/*
+ * AVC statistics
+ */
+struct avc_cache_stats
+{
+    unsigned int lookups;
+    unsigned int hits;
+    unsigned int misses;
+    unsigned int allocations;
+    unsigned int reclaims;
+    unsigned int frees;
+};
+
+/*
+ * AVC operations
+ */
+
+void avc_init(void);
+
+void avc_audit(u32 ssid, u32 tsid, u16 tclass, u32 requested,
+        struct av_decision *avd, int result, struct avc_audit_data *auditdata);
+
+int avc_has_perm_noaudit(u32 ssid, u32 tsid, u16 tclass, u32 requested,
+                                                     struct av_decision *avd);
+
+int avc_has_perm(u32 ssid, u32 tsid, u16 tclass, u32 requested,
+                                             struct avc_audit_data *auditdata);
+
+#define AVC_CALLBACK_GRANT        1
+#define AVC_CALLBACK_TRY_REVOKE        2
+#define AVC_CALLBACK_REVOKE        4
+#define AVC_CALLBACK_RESET        8
+#define AVC_CALLBACK_AUDITALLOW_ENABLE    16
+#define AVC_CALLBACK_AUDITALLOW_DISABLE    32
+#define AVC_CALLBACK_AUDITDENY_ENABLE    64
+#define AVC_CALLBACK_AUDITDENY_DISABLE    128
+
+int avc_add_callback(int (*callback)(u32 event, u32 ssid, u32 tsid,
+                        u16 tclass, u32 perms, u32 *out_retained), u32 events, 
+                                    u32 ssid, u32 tsid, u16 tclass, u32 perms);
+
+/* Exported to selinuxfs */
+int avc_get_hash_stats(char *page);
+extern unsigned int avc_cache_threshold;
+
+#ifdef FLASK_AVC_STATS
+DECLARE_PER_CPU(struct avc_cache_stats, avc_cache_stats);
+#endif
+
+#endif /* _FLASK_AVC_H_ */
+
diff -r cb2ecf48cf80 -r 8ae246493872 xen/xsm/flask/include/avc_ss.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/include/avc_ss.h	Mon Jun 04 11:06:52 2007 -0400
@@ -0,0 +1,14 @@
+/*
+ * Access vector cache interface for the security server.
+ *
+ * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
+ */
+#ifndef _FLASK_AVC_SS_H_
+#define _FLASK_AVC_SS_H_
+
+#include "flask.h"
+
+int avc_ss_reset(u32 seqno);
+
+#endif /* _FLASK_AVC_SS_H_ */
+
diff -r cb2ecf48cf80 -r 8ae246493872 xen/xsm/flask/include/class_to_string.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/include/class_to_string.h	Mon Jun 04 11:06:52 2007 -0400
@@ -0,0 +1,14 @@
+/* This file is automatically generated.  Do not edit. */
+/*
+ * Security object class definitions
+ */
+    S_("null")
+    S_("xen")
+    S_("domain")
+    S_("hvm")
+    S_("mmu")
+    S_("resource")
+    S_("shadow")
+    S_("event")
+    S_("grant")
+    S_("security")
diff -r cb2ecf48cf80 -r 8ae246493872 xen/xsm/flask/include/common_perm_to_string.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/include/common_perm_to_string.h	Mon Jun 04 11:06:52 2007 -0400
@@ -0,0 +1,1 @@
+/* This file is automatically generated.  Do not edit. */
diff -r cb2ecf48cf80 -r 8ae246493872 xen/xsm/flask/include/conditional.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/include/conditional.h	Mon Jun 04 11:06:52 2007 -0400
@@ -0,0 +1,22 @@
+/*
+ * Interface to booleans in the security server. This is exported
+ * for the selinuxfs.
+ *
+ * Author: Karl MacMillan <kmacmillan@tresys.com>
+ *
+ * Copyright (C) 2003 - 2004 Tresys Technology, LLC
+ *    This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation, version 2.
+ */
+
+#ifndef _FLASK_CONDITIONAL_H_
+#define _FLASK_CONDITIONAL_H_
+
+int security_get_bools(int *len, char ***names, int **values);
+
+int security_set_bools(int len, int *values);
+
+int security_get_bool_value(int bool);
+
+#endif
diff -r cb2ecf48cf80 -r 8ae246493872 xen/xsm/flask/include/flask.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/include/flask.h	Mon Jun 04 11:06:52 2007 -0400
@@ -0,0 +1,36 @@
+/* This file is automatically generated.  Do not edit. */
+#ifndef _FLASK_FLASK_H_
+#define _FLASK_FLASK_H_
+
+/*
+ * Security object class definitions
+ */
+#define SECCLASS_XEN                                     1
+#define SECCLASS_DOMAIN                                  2
+#define SECCLASS_HVM                                     3
+#define SECCLASS_MMU                                     4
+#define SECCLASS_RESOURCE                                5
+#define SECCLASS_SHADOW                                  6
+#define SECCLASS_EVENT                                   7
+#define SECCLASS_GRANT                                   8
+#define SECCLASS_SECURITY                                9
+
+/*
+ * Security identifier indices for initial entities
+ */
+#define SECINITSID_XEN                                  1
+#define SECINITSID_DOM0                                 2
+#define SECINITSID_DOMU                                 3
+#define SECINITSID_DOMIO                                4
+#define SECINITSID_DOMXEN                               5
+#define SECINITSID_UNLABELED                            6
+#define SECINITSID_SECURITY                             7
+#define SECINITSID_IOPORT                               8
+#define SECINITSID_IOMEM                                9
+#define SECINITSID_VCPU                                 10
+#define SECINITSID_VIRQ                                 11
+#define SECINITSID_PIRQ                                 12
+
+#define SECINITSID_NUM                                  12
+
+#endif
diff -r cb2ecf48cf80 -r 8ae246493872 xen/xsm/flask/include/initial_sid_to_string.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/include/initial_sid_to_string.h	Mon Jun 04 11:06:52 2007 -0400
@@ -0,0 +1,18 @@
+/* This file is automatically generated.  Do not edit. */
+static char *initial_sid_to_string[] =
+{
+    "null",
+    "xen",
+    "dom0",
+    "domU",
+    "domio",
+    "domxen",
+    "unlabeled",
+    "security",
+    "ioport",
+    "iomem",
+    "vcpu",
+    "virq",
+    "pirq",
+};
+
diff -r cb2ecf48cf80 -r 8ae246493872 xen/xsm/flask/include/objsec.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/include/objsec.h	Mon Jun 04 11:06:52 2007 -0400
@@ -0,0 +1,33 @@
+/*
+ *  NSA Security-Enhanced Linux (SELinux) security module
+ *
+ *  This file contains the Flask security data structures for xen objects.
+ *
+ *  Author(s):  George Coker, <gscoker@alpha.ncsc.mil>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License version 2,
+ *      as published by the Free Software Foundation.
+ */
+
+#ifndef _FLASK_OBJSEC_H_
+#define _FLASK_OBJSEC_H_
+
+#include <xen/sched.h>
+#include "flask.h"
+#include "avc.h"
+
+struct domain_security_struct {
+    struct domain *d;      /* back pointer to domain object */
+    u32 sid;               /* current SID */
+    u32 create_sid;
+};
+
+struct evtchn_security_struct {
+    struct evtchn *chn;      /* back pointer to evtchn object */
+    u32 sid;                 /* current SID */
+};
+
+extern unsigned int selinux_checkreqprot;
+
+#endif /* _FLASK_OBJSEC_H_ */
diff -r cb2ecf48cf80 -r 8ae246493872 xen/xsm/flask/include/security.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/include/security.h	Mon Jun 04 11:06:52 2007 -0400
@@ -0,0 +1,83 @@
+/*
+ * Security server interface.
+ *
+ * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
+ *
+ */
+
+/* Ported to Xen 3.0, George Coker, <gscoker@alpha.ncsc.mil> */
+
+#ifndef _FLASK_SECURITY_H_
+#define _FLASK_SECURITY_H_
+
+#include "flask.h"
+
+#define SECSID_NULL            0x00000000 /* unspecified SID */
+#define SECSID_WILD            0xffffffff /* wildcard SID */
+#define SECCLASS_NULL            0x0000 /* no class */
+
+#define FLASK_MAGIC 0xf97cff8c
+
+/* Identify specific policy version changes */
+#define POLICYDB_VERSION_BASE        15
+#define POLICYDB_VERSION_BOOL        16
+#define POLICYDB_VERSION_IPV6        17
+#define POLICYDB_VERSION_NLCLASS    18
+#define POLICYDB_VERSION_VALIDATETRANS    19
+#define POLICYDB_VERSION_MLS        19
+#define POLICYDB_VERSION_AVTAB        20
+
+/* Range of policy versions we understand*/
+#define POLICYDB_VERSION_MIN   POLICYDB_VERSION_BASE
+#define POLICYDB_VERSION_MAX   POLICYDB_VERSION_AVTAB
+
+#ifdef FLASK_BOOTPARAM
+extern int flask_enabled;
+#else
+#define flask_enabled 1
+#endif
+
+extern int flask_mls_enabled;
+
+int security_load_policy(void * data, size_t len);
+
+struct av_decision {
+    u32 allowed;
+    u32 decided;
+    u32 auditallow;
+    u32 auditdeny;
+    u32 seqno;
+};
+
+int security_compute_av(u32 ssid, u32 tsid, u16 tclass, u32 requested,
+                                                    struct av_decision *avd);
+
+int security_transition_sid(u32 ssid, u32 tsid, u16 tclass, u32 *out_sid);
+
+int security_member_sid(u32 ssid, u32 tsid, u16 tclass, u32 *out_sid);
+
+int security_change_sid(u32 ssid, u32 tsid, u16 tclass, u32 *out_sid);
+
+int security_sid_to_context(u32 sid, char **scontext, u32 *scontext_len);
+
+int security_context_to_sid(char *scontext, u32 scontext_len, u32 *out_sid);
+
+int security_context_to_sid_default(char *scontext, u32 scontext_len, 
+                                                    u32 *out_sid, u32 def_sid);
+
+int security_get_user_sids(u32 callsid, char *username, u32 **sids, u32 *nel);
+
+int security_pirq_sid(int pirq, u32 *out_sid);
+
+int security_virq_sid(int virq, u32 *out_sid);
+
+int security_vcpu_sid(int vcpu, u32 *out_sid);
+
+int security_iomem_sid(unsigned long, u32 *out_sid);
+
+int security_ioport_sid(u32 ioport, u32 *out_sid);
+
+int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid,
+                                                                    u16 tclass);
+
+#endif /* _FLASK_SECURITY_H_ */
diff -r cb2ecf48cf80 -r 8ae246493872 xen/xsm/flask/ss/Makefile
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/ss/Makefile	Mon Jun 04 11:06:52 2007 -0400
@@ -0,0 +1,11 @@
+obj-y += ebitmap.o
+obj-y += hashtab.o
+obj-y += symtab.o
+obj-y += sidtab.o
+obj-y += avtab.o
+obj-y += policydb.o
+obj-y += services.o
+obj-y += conditional.o
+obj-y += mls.o
+
+CFLAGS += -I../include
diff -r cb2ecf48cf80 -r 8ae246493872 xen/xsm/flask/ss/avtab.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/ss/avtab.c	Mon Jun 04 11:06:52 2007 -0400
@@ -0,0 +1,471 @@
+/*
+ * Implementation of the access vector table type.
+ *
+ * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
+ */
+
+/* Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com>
+ *
+ *     Added conditional policy language extensions
+ *
+ * Copyright (C) 2003 Tresys Technology, LLC
+ *    This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation, version 2.
+ */
+
+/* Ported to Xen 3.0, George Coker, <gscoker@alpha.ncsc.mil> */
+
+#include <xen/lib.h>
+#include <asm/byteorder.h>
+#include <xen/types.h>
+#include <xen/xmalloc.h>
+#include <xen/errno.h>
+
+#include "avtab.h"
+#include "policydb.h"
+
+#define AVTAB_HASH(keyp) \
+((keyp->target_class + \
+ (keyp->target_type << 2) + \
+ (keyp->source_type << 9)) & \
+ AVTAB_HASH_MASK)
+
+static struct avtab_node* avtab_insert_node(struct avtab *h, int hvalue,
+    struct avtab_node * prev, struct avtab_node * cur, struct avtab_key *key, 
+                                                    struct avtab_datum *datum)
+{
+    struct avtab_node * newnode;
+    newnode = xmalloc(struct avtab_node);
+    if ( newnode == NULL )
+        return NULL;
+    memset(newnode, 0, sizeof(struct avtab_node));
+    newnode->key = *key;
+    newnode->datum = *datum;
+    if ( prev )
+    {
+        newnode->next = prev->next;
+        prev->next = newnode;
+    }
+    else
+    {
+        newnode->next = h->htable[hvalue];
+        h->htable[hvalue] = newnode;
+    }
+
+    h->nel++;
+    return newnode;
+}
+
+static int avtab_insert(struct avtab *h, struct avtab_key *key, 
+                                                    struct avtab_datum *datum)
+{
+    int hvalue;
+    struct avtab_node *prev, *cur, *newnode;
+    u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD);
+
+    if ( !h )
+        return -EINVAL;
+
+    hvalue = AVTAB_HASH(key);
+    for ( prev = NULL, cur = h->htable[hvalue]; cur;
+                                                    prev = cur, cur = cur->next)
+    {
+        if ( key->source_type == cur->key.source_type &&
+                                key->target_type == cur->key.target_type &&
+                                key->target_class == cur->key.target_class &&
+                                            (specified & cur->key.specified) )
+            return -EEXIST;
+        if ( key->source_type < cur->key.source_type )
+            break;
+        if ( key->source_type == cur->key.source_type &&
+                                    key->target_type < cur->key.target_type )
+            break;
+        if ( key->source_type == cur->key.source_type &&
+                                    key->target_type == cur->key.target_type &&
+                                    key->target_class < cur->key.target_class )
+            break;
+    }
+
+    newnode = avtab_insert_node(h, hvalue, prev, cur, key, datum);
+    if( !newnode )
+        return -ENOMEM;
+
+    return 0;
+}
+
+/* Unlike avtab_insert(), this function allow multiple insertions of the same
+ * key/specified mask into the table, as needed by the conditional avtab.
+ * It also returns a pointer to the node inserted.
+ */
+struct avtab_node * avtab_insert_nonunique(struct avtab * h, 
+                            struct avtab_key * key, struct avtab_datum * datum)
+{
+    int hvalue;
+    struct avtab_node *prev, *cur, *newnode;
+    u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD);
+
+    if ( !h )
+        return NULL;
+    hvalue = AVTAB_HASH(key);
+    for ( prev = NULL, cur = h->htable[hvalue]; cur; 
+                                                prev = cur, cur = cur->next )
+    {
+        if ( key->source_type == cur->key.source_type &&
+                                key->target_type == cur->key.target_type &&
+                                key->target_class == cur->key.target_class &&
+                                            (specified & cur->key.specified) )
+            break;
+        if ( key->source_type < cur->key.source_type )
+            break;
+        if ( key->source_type == cur->key.source_type &&
+                                    key->target_type < cur->key.target_type )
+            break;
+        if ( key->source_type == cur->key.source_type &&
+                                key->target_type == cur->key.target_type &&
+                                key->target_class < cur->key.target_class )
+            break;
+    }
+    newnode = avtab_insert_node(h, hvalue, prev, cur, key, datum);
+
+    return newnode;
+}
+
+struct avtab_datum *avtab_search(struct avtab *h, struct avtab_key *key)
+{
+    int hvalue;
+    struct avtab_node *cur;
+    u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD);
+
+    if ( !h )
+        return NULL;
+
+    hvalue = AVTAB_HASH(key);
+    for ( cur = h->htable[hvalue]; cur; cur = cur->next )
+    {
+        if ( key->source_type == cur->key.source_type &&
+                                key->target_type == cur->key.target_type &&
+                                key->target_class == cur->key.target_class &&
+                                            (specified & cur->key.specified) )
+            return &cur->datum;
+
+        if ( key->source_type < cur->key.source_type )
+            break;
+        if ( key->source_type == cur->key.source_type &&
+                                    key->target_type < cur->key.target_type )
+            break;
+        if ( key->source_type == cur->key.source_type &&
+                                key->target_type == cur->key.target_type &&
+                                key->target_class < cur->key.target_class )
+            break;
+    }
+
+    return NULL;
+}
+
+/* This search function returns a node pointer, and can be used in
+ * conjunction with avtab_search_next_node()
+ */
+struct avtab_node* avtab_search_node(struct avtab *h, struct avtab_key *key)
+{
+    int hvalue;
+    struct avtab_node *cur;
+    u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD);
+
+    if ( !h )
+        return NULL;
+
+    hvalue = AVTAB_HASH(key);
+    for ( cur = h->htable[hvalue]; cur; cur = cur->next )
+    {
+        if ( key->source_type == cur->key.source_type &&
+                                key->target_type == cur->key.target_type &&
+                                key->target_class == cur->key.target_class &&
+                                            (specified & cur->key.specified) )
+            return cur;
+
+        if ( key->source_type < cur->key.source_type )
+            break;
+        if ( key->source_type == cur->key.source_type &&
+                                    key->target_type < cur->key.target_type )
+            break;
+        if ( key->source_type == cur->key.source_type &&
+                                    key->target_type == cur->key.target_type &&
+                                    key->target_class < cur->key.target_class )
+            break;
+    }
+    return NULL;
+}
+
+struct avtab_node* avtab_search_node_next(struct avtab_node *node, 
+                                                                int specified)
+{
+    struct avtab_node *cur;
+
+    if ( !node )
+        return NULL;
+
+    specified &= ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD);
+    for ( cur = node->next; cur; cur = cur->next )
+    {
+        if ( node->key.source_type == cur->key.source_type &&
+                            node->key.target_type == cur->key.target_type &&
+                            node->key.target_class == cur->key.target_class &&
+                                            (specified & cur->key.specified) )
+            return cur;
+
+        if ( node->key.source_type < cur->key.source_type )
+            break;
+        if ( node->key.source_type == cur->key.source_type &&
+                                node->key.target_type < cur->key.target_type )
+            break;
+        if ( node->key.source_type == cur->key.source_type &&
+                            node->key.target_type == cur->key.target_type &&
+                            node->key.target_class < cur->key.target_class )
+            break;
+    }
+    return NULL;
+}
+
+void avtab_destroy(struct avtab *h)
+{
+    int i;
+    struct avtab_node *cur, *temp;
+
+    if ( !h || !h->htable )
+        return;
+
+    for ( i = 0; i < AVTAB_SIZE; i++ )
+    {
+        cur = h->htable[i];
+        while ( cur != NULL )
+        {
+            temp = cur;
+            cur = cur->next;
+            xfree(temp);
+        }
+        h->htable[i] = NULL;
+    }
+    xfree(h->htable);
+    h->htable = NULL;
+}
+
+
+int avtab_init(struct avtab *h)
+{
+    int i;
+
+    h->htable = (void *)xmalloc_array(struct avtab_node, AVTAB_SIZE);
+    if ( !h->htable )
+        return -ENOMEM;
+    for ( i = 0; i < AVTAB_SIZE; i++ )
+        h->htable[i] = NULL;
+    h->nel = 0;
+    return 0;
+}
+
+void avtab_hash_eval(struct avtab *h, char *tag)
+{
+    int i, chain_len, slots_used, max_chain_len;
+    struct avtab_node *cur;
+
+    slots_used = 0;
+    max_chain_len = 0;
+    for ( i = 0; i < AVTAB_SIZE; i++ )
+    {
+        cur = h->htable[i];
+        if ( cur )
+        {
+            slots_used++;
+            chain_len = 0;
+            while ( cur )
+            {
+                chain_len++;
+                cur = cur->next;
+            }
+
+            if ( chain_len > max_chain_len )
+                max_chain_len = chain_len;
+        }
+    }
+
+    printk(KERN_INFO "%s:  %d entries and %d/%d buckets used, longest "
+           "chain length %d\n", tag, h->nel, slots_used, AVTAB_SIZE,
+                                                               max_chain_len);
+}
+
+static uint16_t spec_order[] = {
+    AVTAB_ALLOWED,
+    AVTAB_AUDITDENY,
+    AVTAB_AUDITALLOW,
+    AVTAB_TRANSITION,
+    AVTAB_CHANGE,
+    AVTAB_MEMBER
+};
+
+int avtab_read_item(void *fp, u32 vers, struct avtab *a,
+                            int (*insertf)(struct avtab *a, struct avtab_key *k,
+                                    struct avtab_datum *d, void *p), void *p)
+{
+    __le16 buf16[4];
+    u16 enabled;
+    __le32 buf32[7];
+    u32 items, items2, val;
+    struct avtab_key key;
+    struct avtab_datum datum;
+    int i, rc;
+
+    memset(&key, 0, sizeof(struct avtab_key));
+    memset(&datum, 0, sizeof(struct avtab_datum));
+
+    if ( vers < POLICYDB_VERSION_AVTAB )
+    {
+        rc = next_entry(buf32, fp, sizeof(u32));
+        if ( rc < 0 )
+        {
+            printk(KERN_ERR "security: avtab: truncated entry\n");
+            return -1;
+        }
+        items2 = le32_to_cpu(buf32[0]);
+        if ( items2 > ARRAY_SIZE(buf32) )
+        {
+            printk(KERN_ERR "security: avtab: entry overflow\n");
+            return -1;
+
+        }
+        rc = next_entry(buf32, fp, sizeof(u32)*items2);
+        if ( rc < 0 )
+        {
+            printk(KERN_ERR "security: avtab: truncated entry\n");
+            return -1;
+        }
+        items = 0;
+
+        val = le32_to_cpu(buf32[items++]);
+        key.source_type = (u16)val;
+        if ( key.source_type != val )
+        {
+            printk("security: avtab: truncated source type\n");
+            return -1;
+        }
+        val = le32_to_cpu(buf32[items++]);
+        key.target_type = (u16)val;
+        if ( key.target_type != val )
+        {
+            printk("security: avtab: truncated target type\n");
+            return -1;
+        }
+        val = le32_to_cpu(buf32[items++]);
+        key.target_class = (u16)val;
+        if ( key.target_class != val )
+        {
+            printk("security: avtab: truncated target class\n");
+            return -1;
+        }
+
+        val = le32_to_cpu(buf32[items++]);
+        enabled = (val & AVTAB_ENABLED_OLD) ? AVTAB_ENABLED : 0;
+
+        if ( !(val & (AVTAB_AV | AVTAB_TYPE)) )
+        {
+            printk("security: avtab: null entry\n");
+            return -1;
+        }
+        if ( (val & AVTAB_AV) && (val & AVTAB_TYPE) )
+        {
+            printk("security: avtab: entry has both access vectors and types\n");
+            return -1;
+        }
+
+        for ( i = 0; i < sizeof(spec_order)/sizeof(u16); i++ )
+        {
+            if ( val & spec_order[i] )
+            {
+                key.specified = spec_order[i] | enabled;
+                datum.data = le32_to_cpu(buf32[items++]);
+                rc = insertf(a, &key, &datum, p);
+                if ( rc )
+                    return rc;
+            }
+        }
+
+        if ( items != items2 ) {
+            printk("security: avtab: entry only had %d items, expected %d\n", 
+                                                                items2, items);
+            return -1;
+        }
+        return 0;
+    }
+
+    rc = next_entry(buf16, fp, sizeof(u16)*4);
+    if ( rc < 0 )
+    {
+        printk("security: avtab: truncated entry\n");
+        return -1;
+    }
+
+    items = 0;
+    key.source_type = le16_to_cpu(buf16[items++]);
+    key.target_type = le16_to_cpu(buf16[items++]);
+    key.target_class = le16_to_cpu(buf16[items++]);
+    key.specified = le16_to_cpu(buf16[items++]);
+
+    rc = next_entry(buf32, fp, sizeof(u32));
+    if ( rc < 0 )
+    {
+        printk("security: avtab: truncated entry\n");
+        return -1;
+    }
+    datum.data = le32_to_cpu(*buf32);
+    return insertf(a, &key, &datum, p);
+}
+
+static int avtab_insertf(struct avtab *a, struct avtab_key *k,
+                                                struct avtab_datum *d, void *p)
+{
+    return avtab_insert(a, k, d);
+}
+
+int avtab_read(struct avtab *a, void *fp, u32 vers)
+{
+    int rc;
+    __le32 buf[1];
+    u32 nel, i;
+
+    rc = next_entry(buf, fp, sizeof(u32));
+    if ( rc < 0 )
+    {
+        printk(KERN_ERR "security: avtab: truncated table\n");
+        goto bad;
+    }
+    nel = le32_to_cpu(buf[0]);
+    if ( !nel )
+    {
+        printk(KERN_ERR "security: avtab: table is empty\n");
+        rc = -EINVAL;
+        goto bad;
+    }
+    for ( i = 0; i < nel; i++ )
+    {
+        rc = avtab_read_item(fp,vers, a, avtab_insertf, NULL);
+        if ( rc )
+        {
+            if ( rc == -ENOMEM )
+                printk(KERN_ERR "security: avtab: out of memory\n");
+            else if ( rc == -EEXIST )
+                printk(KERN_ERR "security: avtab: duplicate entry\n");
+            else
+                rc = -EINVAL;
+            goto bad;
+        }
+    }
+
+    rc = 0;
+out:
+    return rc;
+
+bad:
+    avtab_destroy(a);
+    goto out;
+}
+
diff -r cb2ecf48cf80 -r 8ae246493872 xen/xsm/flask/ss/avtab.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/ss/avtab.h	Mon Jun 04 11:06:52 2007 -0400
@@ -0,0 +1,85 @@
+/*
+ * An access vector table (avtab) is a hash table
+ * of access vectors and transition types indexed
+ * by a type pair and a class.  An access vector
+ * table is used to represent the type enforcement
+ * tables.
+ *
+ *  Author : Stephen Smalley, <sds@epoch.ncsc.mil>
+ */
+
+/* Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com>
+ *
+ *     Added conditional policy language extensions
+ *
+ * Copyright (C) 2003 Tresys Technology, LLC
+ *    This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation, version 2.
+ */
+
+/* Ported to Xen 3.0, George Coker, <gscoker@alpha.ncsc.mil> */
+
+#ifndef _SS_AVTAB_H_
+#define _SS_AVTAB_H_
+
+struct avtab_key {
+    u16 source_type;    /* source type */
+    u16 target_type;    /* target type */
+    u16 target_class;    /* target object class */
+#define AVTAB_ALLOWED     1
+#define AVTAB_AUDITALLOW  2
+#define AVTAB_AUDITDENY   4
+#define AVTAB_AV         (AVTAB_ALLOWED | AVTAB_AUDITALLOW | AVTAB_AUDITDENY)
+#define AVTAB_TRANSITION 16
+#define AVTAB_MEMBER     32
+#define AVTAB_CHANGE     64
+#define AVTAB_TYPE       (AVTAB_TRANSITION | AVTAB_MEMBER | AVTAB_CHANGE)
+#define AVTAB_ENABLED_OLD    0x80000000 /* reserved for used in cond_avtab */
+#define AVTAB_ENABLED    0x8000 /* reserved for used in cond_avtab */
+    u16 specified;    /* what field is specified */
+};
+
+struct avtab_datum {
+    u32 data; /* access vector or type value */
+};
+
+struct avtab_node {
+    struct avtab_key key;
+    struct avtab_datum datum;
+    struct avtab_node *next;
+};
+
+struct avtab {
+    struct avtab_node **htable;
+    u32 nel;    /* number of elements */
+};
+
+int avtab_init(struct avtab *);
+struct avtab_datum *avtab_search(struct avtab *h, struct avtab_key *k);
+void avtab_destroy(struct avtab *h);
+void avtab_hash_eval(struct avtab *h, char *tag);
+
+int avtab_read_item(void *fp, uint32_t vers, struct avtab *a,
+            int (*insert)(struct avtab *a, struct avtab_key *k,
+                  struct avtab_datum *d, void *p),
+            void *p);
+
+int avtab_read(struct avtab *a, void *fp, u32 vers);
+
+struct avtab_node *avtab_insert_nonunique(struct avtab *h, 
+                            struct avtab_key *key, struct avtab_datum *datum);
+
+struct avtab_node *avtab_search_node(struct avtab *h, struct avtab_key *key);
+
+struct avtab_node *avtab_search_node_next(struct avtab_node *node, 
+                                                                int specified);
+
+#define AVTAB_HASH_BITS 15
+#define AVTAB_HASH_BUCKETS (1 << AVTAB_HASH_BITS)
+#define AVTAB_HASH_MASK (AVTAB_HASH_BUCKETS-1)
+
+#define AVTAB_SIZE AVTAB_HASH_BUCKETS
+
+#endif    /* _SS_AVTAB_H_ */
+
diff -r cb2ecf48cf80 -r 8ae246493872 xen/xsm/flask/ss/conditional.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/ss/conditional.c	Mon Jun 04 11:06:52 2007 -0400
@@ -0,0 +1,546 @@
+/* Authors: Karl MacMillan <kmacmillan@tresys.com>
+ *          Frank Mayer <mayerf@tresys.com>
+ *
+ * Copyright (C) 2003 - 2004 Tresys Technology, LLC
+ *    This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation, version 2.
+ */
+
+/* Ported to Xen 3.0, George Coker, <gscoker@alpha.ncsc.mil> */
+
+#include <asm/byteorder.h>
+#include <xen/lib.h>
+#include <xen/types.h>
+#include <xen/errno.h>
+#include <xen/string.h>
+#include <xen/spinlock.h>
+#include <xen/xmalloc.h>
+
+#include "security.h"
+#include "conditional.h"
+
+/*
+ * cond_evaluate_expr evaluates a conditional expr
+ * in reverse polish notation. It returns true (1), false (0),
+ * or undefined (-1). Undefined occurs when the expression
+ * exceeds the stack depth of COND_EXPR_MAXDEPTH.
+ */
+static int cond_evaluate_expr(struct policydb *p, struct cond_expr *expr)
+{
+    struct cond_expr *cur;
+    int s[COND_EXPR_MAXDEPTH];
+    int sp = -1;
+
+    for ( cur = expr; cur != NULL; cur = cur->next )
+    {
+        switch ( cur->expr_type )
+        {
+            case COND_BOOL:
+                if ( sp == (COND_EXPR_MAXDEPTH - 1) )
+                    return -1;
+                sp++;
+                s[sp] = p->bool_val_to_struct[cur->bool - 1]->state;
+            break;
+            case COND_NOT:
+                if ( sp < 0 )
+                    return -1;
+                s[sp] = !s[sp];
+            break;
+            case COND_OR:
+                if ( sp < 1 )
+                    return -1;
+                sp--;
+                s[sp] |= s[sp + 1];
+            break;
+            case COND_AND:
+                if ( sp < 1 )
+                    return -1;
+                sp--;
+                s[sp] &= s[sp + 1];
+            break;
+          case COND_XOR:
+                if ( sp < 1 )
+                    return -1;
+               sp--;
+                s[sp] ^= s[sp + 1];
+               break;
+            case COND_EQ:
+                if ( sp < 1 )
+                    return -1;
+                sp--;
+                s[sp] = (s[sp] == s[sp + 1]);
+            break;
+            case COND_NEQ:
+                if ( sp < 1 )
+                    return -1;
+                sp--;
+                s[sp] = (s[sp] != s[sp + 1]);
+            break;
+            default:
+                return -1;
+        }
+    }
+    return s[0];
+}
+
+/*
+ * evaluate_cond_node evaluates the conditional stored in
+ * a struct cond_node and if the result is different than the
+ * current state of the node it sets the rules in the true/false
+ * list appropriately. If the result of the expression is undefined
+ * all of the rules are disabled for safety.
+ */
+int evaluate_cond_node(struct policydb *p, struct cond_node *node)
+{
+    int new_state;
+    struct cond_av_list* cur;
+
+    new_state = cond_evaluate_expr(p, node->expr);
+    if ( new_state != node->cur_state )
+    {
+        node->cur_state = new_state;
+        if ( new_state == -1 )
+            printk(KERN_ERR "security: expression result was undefined - disabling all rules.\n");
+        /* turn the rules on or off */
+        for ( cur = node->true_list; cur != NULL; cur = cur->next )
+        {
+            if ( new_state <= 0 )
+                cur->node->key.specified &= ~AVTAB_ENABLED;
+            else
+                cur->node->key.specified |= AVTAB_ENABLED;
+        }
+
+        for ( cur = node->false_list; cur != NULL; cur = cur->next )
+        {
+            /* -1 or 1 */
+            if ( new_state )
+                cur->node->key.specified &= ~AVTAB_ENABLED;
+            else
+                cur->node->key.specified |= AVTAB_ENABLED;
+        }
+    }
+    return 0;
+}
+
+int cond_policydb_init(struct policydb *p)
+{
+    p->bool_val_to_struct = NULL;
+    p->cond_list = NULL;
+    if ( avtab_init(&p->te_cond_avtab) )
+        return -1;
+
+    return 0;
+}
+
+static void cond_av_list_destroy(struct cond_av_list *list)
+{
+    struct cond_av_list *cur, *next;
+    for ( cur = list; cur != NULL; cur = next )
+    {
+        next = cur->next;
+        /* the avtab_ptr_t node is destroy by the avtab */
+        xfree(cur);
+    }
+}
+
+static void cond_node_destroy(struct cond_node *node)
+{
+    struct cond_expr *cur_expr, *next_expr;
+
+    for ( cur_expr = node->expr; cur_expr != NULL; cur_expr = next_expr )
+    {
+        next_expr = cur_expr->next;
+        xfree(cur_expr);
+    }
+    cond_av_list_destroy(node->true_list);
+    cond_av_list_destroy(node->false_list);
+    xfree(node);
+}
+
+static void cond_list_destroy(struct cond_node *list)
+{
+    struct cond_node *next, *cur;
+
+    if ( list == NULL )
+        return;
+
+    for ( cur = list; cur != NULL; cur = next )
+    {
+        next = cur->next;
+        cond_node_destroy(cur);
+    }
+}
+
+void cond_policydb_destroy(struct policydb *p)
+{
+    xfree(p->bool_val_to_struct);
+    avtab_destroy(&p->te_cond_avtab);
+    cond_list_destroy(p->cond_list);
+}
+
+int cond_init_bool_indexes(struct policydb *p)
+{
+    xfree(p->bool_val_to_struct);
+    p->bool_val_to_struct = (struct cond_bool_datum**)
+        xmalloc_array(struct cond_bool_datum*, p->p_bools.nprim);
+    if ( !p->bool_val_to_struct )
+        return -1;
+    return 0;
+}
+
+int cond_destroy_bool(void *key, void *datum, void *p)
+{
+    xfree(key);
+    xfree(datum);
+    return 0;
+}
+
+int cond_index_bool(void *key, void *datum, void *datap)
+{
+    struct policydb *p;
+    struct cond_bool_datum *booldatum;
+
+    booldatum = datum;
+    p = datap;
+
+    if ( !booldatum->value || booldatum->value > p->p_bools.nprim )
+        return -EINVAL;
+
+    p->p_bool_val_to_name[booldatum->value - 1] = key;
+    p->bool_val_to_struct[booldatum->value -1] = booldatum;
+
+    return 0;
+}
+
+static int bool_isvalid(struct cond_bool_datum *b)
+{
+    if ( !(b->state == 0 || b->state == 1) )
+        return 0;
+    return 1;
+}
+
+int cond_read_bool(struct policydb *p, struct hashtab *h, void *fp)
+{
+    char *key = NULL;
+    struct cond_bool_datum *booldatum;
+    __le32 buf[3];
+    u32 len;
+    int rc;
+
+    booldatum = xmalloc(struct cond_bool_datum);
+    if ( !booldatum )
+        return -1;
+    memset(booldatum, 0, sizeof(struct cond_bool_datum));
+
+    rc = next_entry(buf, fp, sizeof buf);
+    if ( rc < 0 )
+        goto err;
+
+    booldatum->value = le32_to_cpu(buf[0]);
+    booldatum->state = le32_to_cpu(buf[1]);
+
+    if ( !bool_isvalid(booldatum) )
+        goto err;
+
+    len = le32_to_cpu(buf[2]);
+
+    key = xmalloc_array(char, len + 1);
+    if ( !key )
+        goto err;
+    rc = next_entry(key, fp, len);
+    if ( rc < 0 )
+        goto err;
+    key[len] = 0;
+    if ( hashtab_insert(h, key, booldatum) )
+        goto err;
+
+    return 0;
+err:
+    cond_destroy_bool(key, booldatum, NULL);
+    return -1;
+}
+
+struct cond_insertf_data
+{
+    struct policydb *p;
+    struct cond_av_list *other;
+    struct cond_av_list *head;
+    struct cond_av_list *tail;
+};
+
+static int cond_insertf(struct avtab *a, struct avtab_key *k, 
+                                            struct avtab_datum *d, void *ptr)
+{
+    struct cond_insertf_data *data = ptr;
+    struct policydb *p = data->p;
+    struct cond_av_list *other = data->other, *list, *cur;
+    struct avtab_node *node_ptr;
+    u8 found;
+
+    /*
+     * For type rules we have to make certain there aren't any
+     * conflicting rules by searching the te_avtab and the
+     * cond_te_avtab.
+     */
+    if ( k->specified & AVTAB_TYPE )
+    {
+        if ( avtab_search(&p->te_avtab, k) )
+        {
+            printk("security: type rule already exists outside of a "
+                                                                "conditional.");
+            goto err;
+        }
+        /*
+         * If we are reading the false list other will be a pointer to
+         * the true list. We can have duplicate entries if there is only
+         * 1 other entry and it is in our true list.
+         *
+         * If we are reading the true list (other == NULL) there shouldn't
+         * be any other entries.
+         */
+        if ( other )
+        {
+            node_ptr = avtab_search_node(&p->te_cond_avtab, k);
+            if ( node_ptr )
+            {
+                if ( avtab_search_node_next(node_ptr, k->specified) )
+                {
+                    printk("security: too many conflicting type rules.");
+                    goto err;
+                }
+                found = 0;
+                for ( cur = other; cur != NULL; cur = cur->next )
+                {
+                    if ( cur->node == node_ptr )
+                    {
+                        found = 1;
+                        break;
+                    }
+                }
+                if ( !found )
+                {
+                    printk("security: conflicting type rules.\n");
+                    goto err;
+                }
+            }
+        }
+        else
+        {
+            if ( avtab_search(&p->te_cond_avtab, k) )
+            {
+                printk("security: conflicting type rules when adding type rule "
+                                                                "for true.\n");
+                goto err;
+            }
+        }
+    }
+
+    node_ptr = avtab_insert_nonunique(&p->te_cond_avtab, k, d);
+    if ( !node_ptr )
+    {
+        printk("security: could not insert rule.");
+        goto err;
+    }
+
+    list = xmalloc(struct cond_av_list);
+    if ( !list )
+        goto err;
+    memset(list, 0, sizeof(*list));
+
+    list->node = node_ptr;
+    if ( !data->head )
+        data->head = list;
+    else
+        data->tail->next = list;
+    data->tail = list;
+    return 0;
+
+err:
+    cond_av_list_destroy(data->head);
+    data->head = NULL;
+    return -1;
+}
+
+static int cond_read_av_list(struct policydb *p, void *fp, 
+                    struct cond_av_list **ret_list, struct cond_av_list *other)
+{
+    int i, rc;
+    __le32 buf[1];
+    u32 len;
+    struct cond_insertf_data data;
+
+    *ret_list = NULL;
+
+    len = 0;
+    rc = next_entry(buf, fp, sizeof(u32));
+    if ( rc < 0 )
+        return -1;
+
+    len = le32_to_cpu(buf[0]);
+    if ( len == 0 )
+    {
+        return 0;
+    }
+
+    data.p = p;
+    data.other = other;
+    data.head = NULL;
+    data.tail = NULL;
+    for ( i = 0; i < len; i++ )
+    {
+        rc = avtab_read_item(fp, p->policyvers, &p->te_cond_avtab, cond_insertf,
+                                                                        &data);
+        if ( rc )
+            return rc;
+    }
+
+    *ret_list = data.head;
+    return 0;
+}
+
+static int expr_isvalid(struct policydb *p, struct cond_expr *expr)
+{
+    if ( expr->expr_type <= 0 || expr->expr_type > COND_LAST )
+    {
+        printk("security: conditional expressions uses unknown operator.\n");
+        return 0;
+    }
+
+    if ( expr->bool > p->p_bools.nprim )
+    {
+        printk("security: conditional expressions uses unknown bool.\n");
+        return 0;
+    }
+    return 1;
+}
+
+static int cond_read_node(struct policydb *p, struct cond_node *node, void *fp)
+{
+    __le32 buf[2];
+    u32 len, i;
+    int rc;
+    struct cond_expr *expr = NULL, *last = NULL;
+
+    rc = next_entry(buf, fp, sizeof(u32));
+    if ( rc < 0 )
+        return -1;
+
+    node->cur_state = le32_to_cpu(buf[0]);
+
+    len = 0;
+    rc = next_entry(buf, fp, sizeof(u32));
+    if ( rc < 0 )
+        return -1;
+
+    /* expr */
+    len = le32_to_cpu(buf[0]);
+
+    for ( i = 0; i < len; i++ )
+    {
+        rc = next_entry(buf, fp, sizeof(u32) * 2);
+        if ( rc < 0 )
+            goto err;
+
+        expr = xmalloc(struct cond_expr);
+        if ( !expr )
+        {
+            goto err;
+        }
+        memset(expr, 0, sizeof(struct cond_expr));
+
+        expr->expr_type = le32_to_cpu(buf[0]);
+        expr->bool = le32_to_cpu(buf[1]);
+
+        if ( !expr_isvalid(p, expr) )
+        {
+            xfree(expr);
+            goto err;
+        }
+
+        if ( i == 0 ) 
+            node->expr = expr;
+        else
+            last->next = expr;
+
+        last = expr;
+    }
+
+    if ( cond_read_av_list(p, fp, &node->true_list, NULL) != 0 )
+        goto err;
+    if ( cond_read_av_list(p, fp, &node->false_list, node->true_list) != 0 )
+        goto err;
+    return 0;
+err:
+    cond_node_destroy(node);
+    return -1;
+}
+
+int cond_read_list(struct policydb *p, void *fp)
+{
+    struct cond_node *node, *last = NULL;
+    __le32 buf[1];
+    u32 i, len;
+    int rc;
+
+    rc = next_entry(buf, fp, sizeof buf);
+    if ( rc < 0 )
+        return -1;
+
+    len = le32_to_cpu(buf[0]);
+
+    for ( i = 0; i < len; i++ )
+    {
+        node = xmalloc(struct cond_node);
+        if ( !node )
+            goto err;
+        memset(node, 0, sizeof(struct cond_node));
+
+        if ( cond_read_node(p, node, fp) != 0 )
+            goto err;
+
+        if ( i == 0 )
+            p->cond_list = node;
+        else
+            last->next = node;
+
+        last = node;
+    }
+    return 0;
+err:
+    cond_list_destroy(p->cond_list);
+    p->cond_list = NULL;
+    return -1;
+}
+
+/* Determine whether additional permissions are granted by the conditional
+ * av table, and if so, add them to the result
+ */
+void cond_compute_av(struct avtab *ctab, struct avtab_key *key, 
+                                                        struct av_decision *avd)
+{
+    struct avtab_node *node;
+
+    if( !ctab || !key || !avd )
+        return;
+
+    for( node = avtab_search_node(ctab, key); node != NULL;
+                node = avtab_search_node_next(node, key->specified) )
+    {
+        if ( (u16) (AVTAB_ALLOWED|AVTAB_ENABLED) ==
+             (node->key.specified & (AVTAB_ALLOWED|AVTAB_ENABLED)) )
+            avd->allowed |= node->datum.data;
+        if ( (u16) (AVTAB_AUDITDENY|AVTAB_ENABLED) ==
+             (node->key.specified & (AVTAB_AUDITDENY|AVTAB_ENABLED)) )
+            /* Since a '0' in an auditdeny mask represents a
+             * permission we do NOT want to audit (dontaudit), we use
+             * the '&' operand to ensure that all '0's in the mask
+             * are retained (much unlike the allow and auditallow cases).
+             */
+            avd->auditdeny &= node->datum.data;
+        if ( (u16) (AVTAB_AUDITALLOW|AVTAB_ENABLED) ==
+             (node->key.specified & (AVTAB_AUDITALLOW|AVTAB_ENABLED)) )
+            avd->auditallow |= node->datum.data;
+    }
+    return;
+}
diff -r cb2ecf48cf80 -r 8ae246493872 xen/xsm/flask/ss/conditional.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/ss/conditional.h	Mon Jun 04 11:06:52 2007 -0400
@@ -0,0 +1,77 @@
+/* Authors: Karl MacMillan <kmacmillan@tresys.com>
+ *          Frank Mayer <mayerf@tresys.com>
+ *
+ * Copyright (C) 2003 - 2004 Tresys Technology, LLC
+ *    This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation, version 2.
+ */
+
+#ifndef _CONDITIONAL_H_
+#define _CONDITIONAL_H_
+
+#include "avtab.h"
+#include "symtab.h"
+#include "policydb.h"
+
+#define COND_EXPR_MAXDEPTH 10
+
+/*
+ * A conditional expression is a list of operators and operands
+ * in reverse polish notation.
+ */
+struct cond_expr {
+#define COND_BOOL    1 /* plain bool */
+#define COND_NOT    2 /* !bool */
+#define COND_OR        3 /* bool || bool */
+#define COND_AND    4 /* bool && bool */
+#define COND_XOR    5 /* bool ^ bool */
+#define COND_EQ        6 /* bool == bool */
+#define COND_NEQ    7 /* bool != bool */
+#define COND_LAST    8
+    __u32 expr_type;
+    __u32 bool;
+    struct cond_expr *next;
+};
+
+/*
+ * Each cond_node contains a list of rules to be enabled/disabled
+ * depending on the current value of the conditional expression. This
+ * struct is for that list.
+ */
+struct cond_av_list {
+    struct avtab_node *node;
+    struct cond_av_list *next;
+};
+
+/*
+ * A cond node represents a conditional block in a policy. It
+ * contains a conditional expression, the current state of the expression,
+ * two lists of rules to enable/disable depending on the value of the
+ * expression (the true list corresponds to if and the false list corresponds
+ * to else)..
+ */
+struct cond_node {
+    int cur_state;
+    struct cond_expr *expr;
+    struct cond_av_list *true_list;
+    struct cond_av_list *false_list;
+    struct cond_node *next;
+};
+
+int cond_policydb_init(struct policydb* p);
+void cond_policydb_destroy(struct policydb* p);
+
+int cond_init_bool_indexes(struct policydb* p);
+int cond_destroy_bool(void *key, void *datum, void *p);
+
+int cond_index_bool(void *key, void *datum, void *datap);
+
+int cond_read_bool(struct policydb *p, struct hashtab *h, void *fp);
+int cond_read_list(struct policydb *p, void *fp);
+
+void cond_compute_av(struct avtab *ctab, struct avtab_key *key, struct av_decision *avd);
+
+int evaluate_cond_node(struct policydb *p, struct cond_node *node);
+
+#endif /* _CONDITIONAL_H_ */
diff -r cb2ecf48cf80 -r 8ae246493872 xen/xsm/flask/ss/constraint.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/ss/constraint.h	Mon Jun 04 11:06:52 2007 -0400
@@ -0,0 +1,61 @@
+/*
+ * A constraint is a condition that must be satisfied in
+ * order for one or more permissions to be granted.
+ * Constraints are used to impose additional restrictions
+ * beyond the type-based rules in `te' or the role-based
+ * transition rules in `rbac'.  Constraints are typically
+ * used to prevent a process from transitioning to a new user
+ * identity or role unless it is in a privileged type.
+ * Constraints are likewise typically used to prevent a
+ * process from labeling an object with a different user
+ * identity.
+ *
+ * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
+ */
+#ifndef _SS_CONSTRAINT_H_
+#define _SS_CONSTRAINT_H_
+
+#include "ebitmap.h"
+
+#define CEXPR_MAXDEPTH 5
+
+struct constraint_expr {
+#define CEXPR_NOT        1 /* not expr */
+#define CEXPR_AND        2 /* expr and expr */
+#define CEXPR_OR        3 /* expr or expr */
+#define CEXPR_ATTR        4 /* attr op attr */
+#define CEXPR_NAMES        5 /* attr op names */
+    u32 expr_type;        /* expression type */
+
+#define CEXPR_USER 1        /* user */
+#define CEXPR_ROLE 2        /* role */
+#define CEXPR_TYPE 4        /* type */
+#define CEXPR_TARGET 8        /* target if set, source otherwise */
+#define CEXPR_XTARGET 16    /* special 3rd target for validatetrans rule */
+#define CEXPR_L1L2 32        /* low level 1 vs. low level 2 */
+#define CEXPR_L1H2 64        /* low level 1 vs. high level 2 */
+#define CEXPR_H1L2 128        /* high level 1 vs. low level 2 */
+#define CEXPR_H1H2 256        /* high level 1 vs. high level 2 */
+#define CEXPR_L1H1 512        /* low level 1 vs. high level 1 */
+#define CEXPR_L2H2 1024        /* low level 2 vs. high level 2 */
+    u32 attr;        /* attribute */
+
+#define CEXPR_EQ     1        /* == or eq */
+#define CEXPR_NEQ    2        /* != */
+#define CEXPR_DOM    3        /* dom */
+#define CEXPR_DOMBY  4        /* domby  */
+#define CEXPR_INCOMP 5        /* incomp */
+    u32 op;            /* operator */
+
+    struct ebitmap names;    /* names */
+
+    struct constraint_expr *next;   /* next expression */
+};
+
+struct constraint_node {
+    u32 permissions;    /* constrained permissions */
+    struct constraint_expr *expr;    /* constraint on permissions */
+    struct constraint_node *next;    /* next constraint */
+};
+
+#endif    /* _SS_CONSTRAINT_H_ */
diff -r cb2ecf48cf80 -r 8ae246493872 xen/xsm/flask/ss/context.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/ss/context.h	Mon Jun 04 11:06:52 2007 -0400
@@ -0,0 +1,110 @@
+/*
+ * A security context is a set of security attributes
+ * associated with each subject and object controlled
+ * by the security policy.  Security contexts are
+ * externally represented as variable-length strings
+ * that can be interpreted by a user or application
+ * with an understanding of the security policy.
+ * Internally, the security server uses a simple
+ * structure.  This structure is private to the
+ * security server and can be changed without affecting
+ * clients of the security server.
+ *
+ * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
+ */
+ 
+/* Ported to Xen 3.0, George Coker, <gscoker@alpha.ncsc.mil> */
+ 
+#ifndef _SS_CONTEXT_H_
+#define _SS_CONTEXT_H_
+
+#include "ebitmap.h"
+#include "mls_types.h"
+#include "security.h"
+
+/*
+ * A security context consists of an authenticated user
+ * identity, a role, a type and a MLS range.
+ */
+struct context {
+    u32 user;
+    u32 role;
+    u32 type;
+    struct mls_range range;
+};
+
+static inline void mls_context_init(struct context *c)
+{
+    memset(&c->range, 0, sizeof(c->range));
+}
+
+static inline int mls_context_cpy(struct context *dst, struct context *src)
+{
+    int rc;
+
+    if (!flask_mls_enabled)
+        return 0;
+
+    dst->range.level[0].sens = src->range.level[0].sens;
+    rc = ebitmap_cpy(&dst->range.level[0].cat, &src->range.level[0].cat);
+    if (rc)
+        goto out;
+
+    dst->range.level[1].sens = src->range.level[1].sens;
+    rc = ebitmap_cpy(&dst->range.level[1].cat, &src->range.level[1].cat);
+    if (rc)
+        ebitmap_destroy(&dst->range.level[0].cat);
+out:
+    return rc;
+}
+
+static inline int mls_context_cmp(struct context *c1, struct context *c2)
+{
+    if (!flask_mls_enabled)
+        return 1;
+
+    return ((c1->range.level[0].sens == c2->range.level[0].sens) &&
+        ebitmap_cmp(&c1->range.level[0].cat,&c2->range.level[0].cat) &&
+        (c1->range.level[1].sens == c2->range.level[1].sens) &&
+        ebitmap_cmp(&c1->range.level[1].cat,&c2->range.level[1].cat));
+}
+
+static inline void mls_context_destroy(struct context *c)
+{
+    if (!flask_mls_enabled)
+        return;
+
+    ebitmap_destroy(&c->range.level[0].cat);
+    ebitmap_destroy(&c->range.level[1].cat);
+    mls_context_init(c);
+}
+
+static inline void context_init(struct context *c)
+{
+    memset(c, 0, sizeof(*c));
+}
+
+static inline int context_cpy(struct context *dst, struct context *src)
+{
+    dst->user = src->user;
+    dst->role = src->role;
+    dst->type = src->type;
+    return mls_context_cpy(dst, src);
+}
+
+static inline void context_destroy(struct context *c)
+{
+    c->user = c->role = c->type = 0;
+    mls_context_destroy(c);
+}
+
+static inline int context_cmp(struct context *c1, struct context *c2)
+{
+    return ((c1->user == c2->user) &&
+        (c1->role == c2->role) &&
+        (c1->type == c2->type) &&
+        mls_context_cmp(c1, c2));
+}
+
+#endif    /* _SS_CONTEXT_H_ */
+
diff -r cb2ecf48cf80 -r 8ae246493872 xen/xsm/flask/ss/ebitmap.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/ss/ebitmap.c	Mon Jun 04 11:06:52 2007 -0400
@@ -0,0 +1,328 @@
+/*
+ * Implementation of the extensible bitmap type.
+ *
+ * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
+ */
+
+/* Ported to Xen 3.0, George Coker, <gscoker@alpha.ncsc.mil> */
+
+#include <asm/byteorder.h>
+#include <xen/lib.h>
+#include <xen/xmalloc.h>
+#include <xen/errno.h>
+#include <xen/spinlock.h>
+#include "ebitmap.h"
+#include "policydb.h"
+
+int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2)
+{
+    struct ebitmap_node *n1, *n2;
+
+    if ( e1->highbit != e2->highbit )
+        return 0;
+
+    n1 = e1->node;
+    n2 = e2->node;
+    while ( n1 && n2 && (n1->startbit == n2->startbit) && (n1->map == n2->map) )
+    {
+        n1 = n1->next;
+        n2 = n2->next;
+    }
+
+    if ( n1 || n2 )
+        return 0;
+
+    return 1;
+}
+
+int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src)
+{
+    struct ebitmap_node *n, *new, *prev;
+
+    ebitmap_init(dst);
+    n = src->node;
+    prev = NULL;
+    while ( n )
+    {
+        new = xmalloc(struct ebitmap_node);
+        if ( !new )
+        {
+            ebitmap_destroy(dst);
+            return -ENOMEM;
+        }
+        memset(new, 0, sizeof(*new));
+        new->startbit = n->startbit;
+        new->map = n->map;
+        new->next = NULL;
+        if ( prev )
+            prev->next = new;
+        else
+            dst->node = new;
+        prev = new;
+        n = n->next;
+    }
+
+    dst->highbit = src->highbit;
+    return 0;
+}
+
+int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2)
+{
+    struct ebitmap_node *n1, *n2;
+
+    if ( e1->highbit < e2->highbit )
+        return 0;
+
+    n1 = e1->node;
+    n2 = e2->node;
+    while ( n1 && n2 && (n1->startbit <= n2->startbit) )
+    {
+        if ( n1->startbit < n2->startbit )
+        {
+            n1 = n1->next;
+            continue;
+        }
+        if ( (n1->map & n2->map) != n2->map )
+            return 0;
+
+        n1 = n1->next;
+        n2 = n2->next;
+    }
+
+    if ( n2 )
+        return 0;
+
+    return 1;
+}
+
+int ebitmap_get_bit(struct ebitmap *e, unsigned long bit)
+{
+    struct ebitmap_node *n;
+
+    if ( e->highbit < bit )
+        return 0;
+
+    n = e->node;
+    while ( n && (n->startbit <= bit) )
+    {
+        if ( (n->startbit + MAPSIZE) > bit )
+        {
+            if ( n->map & (MAPBIT << (bit - n->startbit)) )
+                return 1;
+            else
+                return 0;
+        }
+        n = n->next;
+    }
+
+    return 0;
+}
+
+int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value)
+{
+    struct ebitmap_node *n, *prev, *new;
+
+    prev = NULL;
+    n = e->node;
+    while ( n && n->startbit <= bit )
+    {
+        if ( (n->startbit + MAPSIZE) > bit )
+        {
+            if ( value )
+            {
+                n->map |= (MAPBIT << (bit - n->startbit));
+            }
+            else
+            {
+                n->map &= ~(MAPBIT << (bit - n->startbit));
+                if ( !n->map )
+                {
+                    /* drop this node from the bitmap */
+
+                    if ( !n->next )
+                    {
+                        /*
+                         * this was the highest map
+                         * within the bitmap
+                         */
+                        if ( prev )
+                            e->highbit = prev->startbit + MAPSIZE;
+                        else
+                            e->highbit = 0;
+                    }
+                    if ( prev )
+                        prev->next = n->next;
+                    else
+                        e->node = n->next;
+
+                    xfree(n);
+                }
+            }
+            return 0;
+        }
+        prev = n;
+        n = n->next;
+    }
+
+    if ( !value )
+        return 0;
+
+    new = xmalloc(struct ebitmap_node);
+    if ( !new )
+        return -ENOMEM;
+    memset(new, 0, sizeof(*new));
+
+    new->startbit = bit & ~(MAPSIZE - 1);
+    new->map = (MAPBIT << (bit - new->startbit));
+
+    if ( !n )
+        /* this node will be the highest map within the bitmap */
+        e->highbit = new->startbit + MAPSIZE;
+
+    if ( prev )
+    {
+        new->next = prev->next;
+        prev->next = new;
+    }
+    else
+    {
+        new->next = e->node;
+        e->node = new;
+    }
+
+    return 0;
+}
+
+void ebitmap_destroy(struct ebitmap *e)
+{
+    struct ebitmap_node *n, *temp;
+
+    if ( !e )
+        return;
+
+    n = e->node;
+    while ( n )
+    {
+        temp = n;
+        n = n->next;
+        xfree(temp);
+    }
+
+    e->highbit = 0;
+    e->node = NULL;
+    return;
+}
+
+int ebitmap_read(struct ebitmap *e, void *fp)
+{
+    int rc;
+    struct ebitmap_node *n, *l;
+    __le32 buf[3];
+    u32 mapsize, count, i;
+    __le64 map;
+
+    ebitmap_init(e);
+
+    rc = next_entry(buf, fp, sizeof buf);
+    if ( rc < 0 )
+        goto out;
+
+    mapsize = le32_to_cpu(buf[0]);
+    e->highbit = le32_to_cpu(buf[1]);
+    count = le32_to_cpu(buf[2]);
+
+    if ( mapsize != MAPSIZE )
+    {
+        printk(KERN_ERR "security: ebitmap: map size %u does not "
+               "match my size %Zd (high bit was %d)\n", mapsize,
+               MAPSIZE, e->highbit);
+        goto bad;
+    }
+    if ( !e->highbit )
+    {
+        e->node = NULL;
+        goto ok;
+    }
+    if ( e->highbit & (MAPSIZE - 1) )
+    {
+        printk(KERN_ERR "security: ebitmap: high bit (%d) is not a "
+               "multiple of the map size (%Zd)\n", e->highbit, MAPSIZE);
+        goto bad;
+    }
+    l = NULL;
+    for ( i = 0; i < count; i++ )
+    {
+        rc = next_entry(buf, fp, sizeof(u32));
+        if ( rc < 0 )
+        {
+            printk(KERN_ERR "security: ebitmap: truncated map\n");
+            goto bad;
+        }
+        n = xmalloc(struct ebitmap_node);
+        if ( !n )
+        {
+            printk(KERN_ERR "security: ebitmap: out of memory\n");
+            rc = -ENOMEM;
+            goto bad;
+        }
+        memset(n, 0, sizeof(*n));
+
+        n->startbit = le32_to_cpu(buf[0]);
+
+        if ( n->startbit & (MAPSIZE - 1) )
+        {
+            printk(KERN_ERR "security: ebitmap start bit (%d) is "
+                   "not a multiple of the map size (%Zd)\n",
+                   n->startbit, MAPSIZE);
+            goto bad_free;
+        }
+        if ( n->startbit > (e->highbit - MAPSIZE) )
+        {
+            printk(KERN_ERR "security: ebitmap start bit (%d) is "
+                   "beyond the end of the bitmap (%Zd)\n",
+                   n->startbit, (e->highbit - MAPSIZE));
+            goto bad_free;
+        }
+        rc = next_entry(&map, fp, sizeof(u64));
+        if ( rc < 0 )
+        {
+            printk(KERN_ERR "security: ebitmap: truncated map\n");
+            goto bad_free;
+        }
+        n->map = le64_to_cpu(map);
+
+        if ( !n->map )
+        {
+            printk(KERN_ERR "security: ebitmap: null map in "
+                   "ebitmap (startbit %d)\n", n->startbit);
+            goto bad_free;
+        }
+        if ( l )
+        {
+            if ( n->startbit <= l->startbit )
+            {
+                printk(KERN_ERR "security: ebitmap: start "
+                       "bit %d comes after start bit %d\n",
+                       n->startbit, l->startbit);
+                goto bad_free;
+            }
+            l->next = n;
+        }
+        else
+            e->node = n;
+
+        l = n;
+    }
+
+ok:
+    rc = 0;
+out:
+    return rc;
+bad_free:
+    xfree(n);
+bad:
+    if ( !rc )
+        rc = -EINVAL;
+    ebitmap_destroy(e);
+    goto out;
+}
diff -r cb2ecf48cf80 -r 8ae246493872 xen/xsm/flask/ss/ebitmap.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/ss/ebitmap.h	Mon Jun 04 11:06:52 2007 -0400
@@ -0,0 +1,79 @@
+/*
+ * An extensible bitmap is a bitmap that supports an
+ * arbitrary number of bits.  Extensible bitmaps are
+ * used to represent sets of values, such as types,
+ * roles, categories, and classes.
+ *
+ * Each extensible bitmap is implemented as a linked
+ * list of bitmap nodes, where each bitmap node has
+ * an explicitly specified starting bit position within
+ * the total bitmap.
+ *
+ * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
+ */
+#ifndef _SS_EBITMAP_H_
+#define _SS_EBITMAP_H_
+
+#define MAPTYPE u64            /* portion of bitmap in each node */
+#define MAPSIZE (sizeof(MAPTYPE) * 8)    /* number of bits in node bitmap */
+#define MAPBIT  1ULL            /* a bit in the node bitmap */
+
+struct ebitmap_node {
+    u32 startbit;        /* starting position in the total bitmap */
+    MAPTYPE map;        /* this node's portion of the bitmap */
+    struct ebitmap_node *next;
+};
+
+struct ebitmap {
+    struct ebitmap_node *node;    /* first node in the bitmap */
+    u32 highbit;    /* highest position in the total bitmap */
+};
+
+#define ebitmap_length(e) ((e)->highbit)
+#define ebitmap_startbit(e) ((e)->node ? (e)->node->startbit : 0)
+
+static inline unsigned int ebitmap_start(struct ebitmap *e,
+                                                 struct ebitmap_node **n)
+{
+    *n = e->node;
+    return ebitmap_startbit(e);
+}
+
+static inline void ebitmap_init(struct ebitmap *e)
+{
+    memset(e, 0, sizeof(*e));
+}
+
+static inline unsigned int ebitmap_next(struct ebitmap_node **n,
+                                                        unsigned int bit)
+{
+    if ( (bit == ((*n)->startbit + MAPSIZE - 1)) && (*n)->next )
+    {
+        *n = (*n)->next;
+        return (*n)->startbit;
+    }
+
+    return (bit+1);
+}
+
+static inline int ebitmap_node_get_bit(struct ebitmap_node * n,
+                                                        unsigned int bit)
+{
+    if ( n->map & (MAPBIT << (bit - n->startbit)) )
+        return 1;
+    return 0;
+}
+
+#define ebitmap_for_each_bit(e, n, bit) \
+    for ( bit = ebitmap_start(e, &n); bit < ebitmap_length(e); \
+                                    bit = ebitmap_next(&n, bit) ) \
+
+int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2);
+int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src);
+int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2);
+int ebitmap_get_bit(struct ebitmap *e, unsigned long bit);
+int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value);
+void ebitmap_destroy(struct ebitmap *e);
+int ebitmap_read(struct ebitmap *e, void *fp);
+
+#endif    /* _SS_EBITMAP_H_ */
diff -r cb2ecf48cf80 -r 8ae246493872 xen/xsm/flask/ss/hashtab.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/ss/hashtab.c	Mon Jun 04 11:06:52 2007 -0400
@@ -0,0 +1,181 @@
+/*
+ * Implementation of the hash table type.
+ *
+ * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
+ */
+
+/* Ported to Xen 3.0, George Coker, <gscoker@alpha.ncsc.mil> */
+
+#include <xen/lib.h>
+#include <xen/xmalloc.h>
+#include <xen/errno.h>
+#include "hashtab.h"
+
+struct hashtab *hashtab_create(u32 (*hash_value)(struct hashtab *h, void *key),
+            int (*keycmp)(struct hashtab *h, void *key1, void *key2), u32 size)
+{
+    struct hashtab *p;
+    u32 i;
+
+    p = xmalloc(struct hashtab);
+    if ( p == NULL )
+        return p;
+
+    memset(p, 0, sizeof(*p));
+    p->size = size;
+    p->nel = 0;
+    p->hash_value = hash_value;
+    p->keycmp = keycmp;
+    p->htable = (void *)xmalloc_array(struct hashtab_node, size);
+    if ( p->htable == NULL )
+    {
+        xfree(p);
+        return NULL;
+    }
+
+    for ( i = 0; i < size; i++ )
+        p->htable[i] = NULL;
+
+    return p;
+}
+
+int hashtab_insert(struct hashtab *h, void *key, void *datum)
+{
+    u32 hvalue;
+    struct hashtab_node *prev, *cur, *newnode;
+
+    if ( !h || h->nel == HASHTAB_MAX_NODES )
+        return -EINVAL;
+
+    hvalue = h->hash_value(h, key);
+    prev = NULL;
+    cur = h->htable[hvalue];
+    while ( cur && h->keycmp(h, key, cur->key) > 0 )
+    {
+        prev = cur;
+        cur = cur->next;
+    }
+
+    if ( cur && (h->keycmp(h, key, cur->key) == 0) )
+        return -EEXIST;
+
+    newnode = xmalloc(struct hashtab_node);
+    if ( newnode == NULL )
+        return -ENOMEM;
+    memset(newnode, 0, sizeof(*newnode));
+    newnode->key = key;
+    newnode->datum = datum;
+    if ( prev )
+    {
+        newnode->next = prev->next;
+        prev->next = newnode;
+    }
+    else
+    {
+        newnode->next = h->htable[hvalue];
+        h->htable[hvalue] = newnode;
+    }
+
+    h->nel++;
+    return 0;
+}
+
+void *hashtab_search(struct hashtab *h, void *key)
+{
+    u32 hvalue;
+    struct hashtab_node *cur;
+
+    if ( !h )
+        return NULL;
+
+    hvalue = h->hash_value(h, key);
+    cur = h->htable[hvalue];
+    while ( cur != NULL && h->keycmp(h, key, cur->key) > 0 )
+        cur = cur->next;
+
+    if ( cur == NULL || (h->keycmp(h, key, cur->key) != 0) )
+        return NULL;
+
+    return cur->datum;
+}
+
+void hashtab_destroy(struct hashtab *h)
+{
+    u32 i;
+    struct hashtab_node *cur, *temp;
+
+    if ( !h )
+        return;
+
+    for ( i = 0; i < h->size; i++ )
+    {
+        cur = h->htable[i];
+        while ( cur != NULL )
+        {
+            temp = cur;
+            cur = cur->next;
+            xfree(temp);
+        }
+        h->htable[i] = NULL;
+    }
+
+    xfree(h->htable);
+    h->htable = NULL;
+
+    xfree(h);
+}
+
+int hashtab_map(struct hashtab *h,
+        int (*apply)(void *k, void *d, void *args),
+        void *args)
+{
+    u32 i;
+    int ret;
+    struct hashtab_node *cur;
+
+    if ( !h )
+        return 0;
+
+    for ( i = 0; i < h->size; i++ )
+    {
+        cur = h->htable[i];
+        while ( cur != NULL )
+        {
+            ret = apply(cur->key, cur->datum, args);
+            if ( ret )
+                return ret;
+            cur = cur->next;
+        }
+    }
+    return 0;
+}
+
+
+void hashtab_stat(struct hashtab *h, struct hashtab_info *info)
+{
+    u32 i, chain_len, slots_used, max_chain_len;
+    struct hashtab_node *cur;
+
+    slots_used = 0;
+    max_chain_len = 0;
+    for ( slots_used = max_chain_len = i = 0; i < h->size; i++ )
+    {
+        cur = h->htable[i];
+        if ( cur )
+        {
+            slots_used++;
+            chain_len = 0;
+            while ( cur )
+            {
+                chain_len++;
+                cur = cur->next;
+            }
+
+            if ( chain_len > max_chain_len )
+                max_chain_len = chain_len;
+        }
+    }
+
+    info->slots_used = slots_used;
+    info->max_chain_len = max_chain_len;
+}
diff -r cb2ecf48cf80 -r 8ae246493872 xen/xsm/flask/ss/hashtab.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/ss/hashtab.h	Mon Jun 04 11:06:52 2007 -0400
@@ -0,0 +1,85 @@
+/*
+ * A hash table (hashtab) maintains associations between
+ * key values and datum values.  The type of the key values
+ * and the type of the datum values is arbitrary.  The
+ * functions for hash computation and key comparison are
+ * provided by the creator of the table.
+ *
+ * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
+ */
+#ifndef _SS_HASHTAB_H_
+#define _SS_HASHTAB_H_
+
+#define HASHTAB_MAX_NODES    0xffffffff
+
+struct hashtab_node {
+    void *key;
+    void *datum;
+    struct hashtab_node *next;
+};
+
+struct hashtab {
+    struct hashtab_node **htable;    /* hash table */
+    u32 size;            /* number of slots in hash table */
+    u32 nel;            /* number of elements in hash table */
+    u32 (*hash_value)(struct hashtab *h, void *key);
+                    /* hash function */
+    int (*keycmp)(struct hashtab *h, void *key1, void *key2);
+                    /* key comparison function */
+};
+
+struct hashtab_info {
+    u32 slots_used;
+    u32 max_chain_len;
+};
+
+/*
+ * Creates a new hash table with the specified characteristics.
+ *
+ * Returns NULL if insufficent space is available or
+ * the new hash table otherwise.
+ */
+struct hashtab *hashtab_create(u32 (*hash_value)(struct hashtab *h, void *key),
+            int (*keycmp)(struct hashtab *h, void *key1, void *key2), u32 size);
+
+/*
+ * Inserts the specified (key, datum) pair into the specified hash table.
+ *
+ * Returns -ENOMEM on memory allocation error,
+ * -EEXIST if there is already an entry with the same key,
+ * -EINVAL for general errors or
+ * 0 otherwise.
+ */
+int hashtab_insert(struct hashtab *h, void *k, void *d);
+
+/*
+ * Searches for the entry with the specified key in the hash table.
+ *
+ * Returns NULL if no entry has the specified key or
+ * the datum of the entry otherwise.
+ */
+void *hashtab_search(struct hashtab *h, void *k);
+
+/*
+ * Destroys the specified hash table.
+ */
+void hashtab_destroy(struct hashtab *h);
+
+/*
+ * Applies the specified apply function to (key,datum,args)
+ * for each entry in the specified hash table.
+ *
+ * The order in which the function is applied to the entries
+ * is dependent upon the internal structure of the hash table.
+ *
+ * If apply returns a non-zero status, then hashtab_map will cease
+ * iterating through the hash table and will propagate the error
+ * return to its caller.
+ */
+int hashtab_map(struct hashtab *h,
+                        int (*apply)(void *k, void *d, void *args), void *args);
+
+/* Fill info with some hash table statistics */
+void hashtab_stat(struct hashtab *h, struct hashtab_info *info);
+
+#endif    /* _SS_HASHTAB_H */
diff -r cb2ecf48cf80 -r 8ae246493872 xen/xsm/flask/ss/mls.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/ss/mls.c	Mon Jun 04 11:06:52 2007 -0400
@@ -0,0 +1,612 @@
+/*
+ * Implementation of the multi-level security (MLS) policy.
+ *
+ * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
+ */
+
+/*
+ * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
+ *
+ *    Support for enhanced MLS infrastructure.
+ *
+ * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
+ */
+
+/* Ported to Xen 3.0, George Coker, <gscoker@alpha.ncsc.mil> */
+
+#include <xen/lib.h>
+#include <xen/xmalloc.h>
+#include <xen/string.h>
+#include <xen/errno.h>
+#include "sidtab.h"
+#include "mls.h"
+#include "policydb.h"
+#include "services.h"
+
+/*
+ * Return the length in bytes for the MLS fields of the
+ * security context string representation of `context'.
+ */
+int mls_compute_context_len(struct context * context)
+{
+    int i, l, len, range;
+    struct ebitmap_node *node;
+
+    if (!flask_mls_enabled)
+        return 0;
+
+    len = 1; /* for the beginning ":" */
+    for ( l = 0; l < 2; l++ )
+    {
+        range = 0;
+        len += strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
+
+        ebitmap_for_each_bit(&context->range.level[l].cat, node, i)
+        {
+            if ( ebitmap_node_get_bit(node, i) )
+            {
+                if ( range )
+                {
+                    range++;
+                    continue;
+                }
+
+                len += strlen(policydb.p_cat_val_to_name[i]) + 1;
+                range++;
+            }
+            else
+            {
+                if ( range > 1 )
+                    len += strlen(policydb.p_cat_val_to_name[i - 1]) + 1;
+                range = 0;
+            }
+        }
+        /* Handle case where last category is the end of range */
+        if ( range > 1 )
+            len += strlen(policydb.p_cat_val_to_name[i - 1]) + 1;
+
+        if ( l == 0 )
+        {
+            if ( mls_level_eq(&context->range.level[0], 
+                                                &context->range.level[1]) )
+                break;
+            else
+                len++;
+        }
+    }
+
+    return len;
+}
+
+/*
+ * Write the security context string representation of
+ * the MLS fields of `context' into the string `*scontext'.
+ * Update `*scontext' to point to the end of the MLS fields.
+ */
+void mls_sid_to_context(struct context *context, char **scontext)
+{
+    char *scontextp;
+    int i, l, range, wrote_sep;
+    struct ebitmap_node *node;
+
+    if ( !flask_mls_enabled )
+        return;
+
+    scontextp = *scontext;
+
+    *scontextp = ':';
+    scontextp++;
+
+    for ( l = 0; l < 2; l++ )
+    {
+        range = 0;
+        wrote_sep = 0;
+        strlcpy(scontextp,
+                policydb.p_sens_val_to_name[context->range.level[l].sens - 1],
+                strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1]));
+        scontextp += strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
+
+        /* categories */
+        ebitmap_for_each_bit(&context->range.level[l].cat, node, i)
+        {
+            if ( ebitmap_node_get_bit(node, i) )
+            {
+                if ( range )
+                {
+                    range++;
+                    continue;
+                }
+
+                if ( !wrote_sep )
+                {
+                    *scontextp++ = ':';
+                    wrote_sep = 1;
+                }
+                else
+                    *scontextp++ = ',';
+                strlcpy(scontextp, policydb.p_cat_val_to_name[i], 
+                    strlen(policydb.p_cat_val_to_name[i]));
+                scontextp += strlen(policydb.p_cat_val_to_name[i]);
+                range++;
+            }
+            else
+            {
+                if ( range > 1 )
+                {
+                    if ( range > 2 )
+                        *scontextp++ = '.';
+                    else
+                        *scontextp++ = ',';
+
+                    strlcpy(scontextp, policydb.p_cat_val_to_name[i - 1],
+                        strlen(policydb.p_cat_val_to_name[i - 1]));
+                    scontextp += strlen(policydb.p_cat_val_to_name[i - 1]);
+                }
+                range = 0;
+            }
+        }
+
+        /* Handle case where last category is the end of range */
+        if ( range > 1 )
+        {
+            if ( range > 2 )
+                *scontextp++ = '.';
+            else
+                *scontextp++ = ',';
+
+            strlcpy(scontextp, policydb.p_cat_val_to_name[i - 1],
+                strlen(policydb.p_cat_val_to_name[i - 1]));
+            scontextp += strlen(policydb.p_cat_val_to_name[i - 1]);
+        }
+
+        if ( l == 0 )
+        {
+            if ( mls_level_eq(&context->range.level[0],
+                                                 &context->range.level[1]) )
+                break;
+            else
+            {
+                *scontextp = '-';
+                scontextp++;
+            }
+        }
+    }
+
+    *scontext = scontextp;
+    return;
+}
+
+/*
+ * Return 1 if the MLS fields in the security context
+ * structure `c' are valid.  Return 0 otherwise.
+ */
+int mls_context_isvalid(struct policydb *p, struct context *c)
+{
+    struct level_datum *levdatum;
+    struct user_datum *usrdatum;
+    struct ebitmap_node *node;
+    int i, l;
+
+    if ( !flask_mls_enabled )
+        return 1;
+
+    /*
+     * MLS range validity checks: high must dominate low, low level must
+     * be valid (category set <-> sensitivity check), and high level must
+     * be valid (category set <-> sensitivity check)
+     */
+    if ( !mls_level_dom(&c->range.level[1], &c->range.level[0]) )
+        /* High does not dominate low. */
+        return 0;
+
+    for ( l = 0; l < 2; l++ )
+    {
+        if ( !c->range.level[l].sens || c->range.level[l].sens > 
+                                                            p->p_levels.nprim )
+            return 0;
+        levdatum = hashtab_search(p->p_levels.table,
+            p->p_sens_val_to_name[c->range.level[l].sens - 1]);
+        if ( !levdatum )
+            return 0;
+
+        ebitmap_for_each_bit(&c->range.level[l].cat, node, i)
+        {
+            if ( ebitmap_node_get_bit(node, i) )
+            {
+                if ( i > p->p_cats.nprim )
+                    return 0;
+                if ( !ebitmap_get_bit(&levdatum->level->cat, i) )
+                    /*
+                     * Category may not be associated with
+                     * sensitivity in low level.
+                     */
+                    return 0;
+            }
+        }
+    }
+
+    if ( c->role == OBJECT_R_VAL )
+        return 1;
+
+    /*
+     * User must be authorized for the MLS range.
+     */
+    if ( !c->user || c->user > p->p_users.nprim )
+        return 0;
+    usrdatum = p->user_val_to_struct[c->user - 1];
+    if ( !mls_range_contains(usrdatum->range, c->range) )
+        return 0; /* user may not be associated with range */
+
+    return 1;
+}
+
+/*
+ * Copies the MLS range from `src' into `dst'.
+ */
+static inline int mls_copy_context(struct context *dst, struct context *src)
+{
+    int l, rc = 0;
+
+    /* Copy the MLS range from the source context */
+    for ( l = 0; l < 2; l++ )
+    {
+        dst->range.level[l].sens = src->range.level[l].sens;
+        rc = ebitmap_cpy(&dst->range.level[l].cat,
+                 &src->range.level[l].cat);
+        if ( rc )
+            break;
+    }
+
+    return rc;
+}
+
+/*
+ * Set the MLS fields in the security context structure
+ * `context' based on the string representation in
+ * the string `*scontext'.  Update `*scontext' to
+ * point to the end of the string representation of
+ * the MLS fields.
+ *
+ * This function modifies the string in place, inserting
+ * NULL characters to terminate the MLS fields.
+ *
+ * If a def_sid is provided and no MLS field is present,
+ * copy the MLS field of the associated default context.
+ * Used for upgraded to MLS systems where objects may lack
+ * MLS fields.
+ *
+ * Policy read-lock must be held for sidtab lookup.
+ *
+ */
+int mls_context_to_sid(char oldc, char **scontext, struct context *context,
+                                                struct sidtab *s, u32 def_sid)
+{
+
+    char delim;
+    char *scontextp, *p, *rngptr;
+    struct level_datum *levdatum;
+    struct cat_datum *catdatum, *rngdatum;
+    int l, rc = -EINVAL;
+
+    if ( !flask_mls_enabled )
+        return 0;
+
+    /*
+     * No MLS component to the security context, try and map to
+     * default if provided.
+     */
+    if ( !oldc )
+    {
+        struct context *defcon;
+
+        if ( def_sid == SECSID_NULL )
+            goto out;
+
+        defcon = sidtab_search(s, def_sid);
+        if ( !defcon )
+            goto out;
+
+        rc = mls_copy_context(context, defcon);
+        goto out;
+    }
+
+    /* Extract low sensitivity. */
+    scontextp = p = *scontext;
+    while ( *p && *p != ':' && *p != '-' )
+        p++;
+
+    delim = *p;
+    if ( delim != 0 )
+        *p++ = 0;
+
+    for ( l = 0; l < 2; l++ )
+    {
+        levdatum = hashtab_search(policydb.p_levels.table, scontextp);
+        if ( !levdatum )
+        {
+            rc = -EINVAL;
+            goto out;
+        }
+
+        context->range.level[l].sens = levdatum->level->sens;
+
+        if ( delim == ':' )
+        {
+            /* Extract category set. */
+            while ( 1 )
+            {
+                scontextp = p;
+                while ( *p && *p != ',' && *p != '-' )
+                    p++;
+                delim = *p;
+                if ( delim != 0 )
+                    *p++ = 0;
+
+                /* Separate into range if exists */
+                if ( (rngptr = strchr(scontextp, '.')) != NULL )
+                {
+                    /* Remove '.' */
+                    *rngptr++ = 0;
+                }
+
+                catdatum = hashtab_search(policydb.p_cats.table, scontextp);
+                if ( !catdatum )
+                {
+                    rc = -EINVAL;
+                    goto out;
+                }
+
+                rc = ebitmap_set_bit(&context->range.level[l].cat,
+                                                    catdatum->value - 1, 1);
+                if ( rc )
+                    goto out;
+
+                /* If range, set all categories in range */
+                if ( rngptr )
+                {
+                    int i;
+
+                    rngdatum = hashtab_search(policydb.p_cats.table, rngptr);
+                    if ( !rngdatum )
+                    {
+                        rc = -EINVAL;
+                        goto out;
+                    }
+
+                    if ( catdatum->value >= rngdatum->value )
+                    {
+                        rc = -EINVAL;
+                        goto out;
+                    }
+
+                    for ( i = catdatum->value; i < rngdatum->value; i++ )
+                    {
+                        rc = ebitmap_set_bit(&context->range.level[l].cat, i, 1);
+                        if ( rc )
+                            goto out;
+                    }
+                }
+
+                if ( delim != ',' )
+                    break;
+            }
+        }
+        if ( delim == '-' )
+        {
+            /* Extract high sensitivity. */
+            scontextp = p;
+            while ( *p && *p != ':' )
+                p++;
+
+            delim = *p;
+            if ( delim != 0 )
+                *p++ = 0;
+        }
+        else
+            break;
+    }
+
+    if ( l == 0 )
+    {
+        context->range.level[1].sens = context->range.level[0].sens;
+        rc = ebitmap_cpy(&context->range.level[1].cat,
+                 &context->range.level[0].cat);
+        if ( rc )
+            goto out;
+    }
+    *scontext = ++p;
+    rc = 0;
+out:
+    return rc;
+}
+
+/*
+ * Copies the effective MLS range from `src' into `dst'.
+ */
+static inline int mls_scopy_context(struct context *dst, struct context *src)
+{
+    int l, rc = 0;
+
+    /* Copy the MLS range from the source context */
+    for ( l = 0; l < 2; l++ )
+    {
+        dst->range.level[l].sens = src->range.level[0].sens;
+        rc = ebitmap_cpy(&dst->range.level[l].cat,
+                 &src->range.level[0].cat);
+        if ( rc )
+            break;
+    }
+
+    return rc;
+}
+
+/*
+ * Copies the MLS range `range' into `context'.
+ */
+static inline int mls_range_set(struct context *context,
+                                                    struct mls_range *range)
+{
+    int l, rc = 0;
+
+    /* Copy the MLS range into the  context */
+    for ( l = 0; l < 2; l++ )
+    {
+        context->range.level[l].sens = range->level[l].sens;
+        rc = ebitmap_cpy(&context->range.level[l].cat,
+                 &range->level[l].cat);
+        if ( rc )
+            break;
+    }
+
+    return rc;
+}
+
+int mls_setup_user_range(struct context *fromcon, struct user_datum *user,
+                                                        struct context *usercon)
+{
+    if ( flask_mls_enabled )
+    {
+        struct mls_level *fromcon_sen = &(fromcon->range.level[0]);
+        struct mls_level *fromcon_clr = &(fromcon->range.level[1]);
+        struct mls_level *user_low = &(user->range.level[0]);
+        struct mls_level *user_clr = &(user->range.level[1]);
+        struct mls_level *user_def = &(user->dfltlevel);
+        struct mls_level *usercon_sen = &(usercon->range.level[0]);
+        struct mls_level *usercon_clr = &(usercon->range.level[1]);
+
+        /* Honor the user's default level if we can */
+        if ( mls_level_between(user_def, fromcon_sen, fromcon_clr) )
+        {
+            *usercon_sen = *user_def;
+        }
+        else if ( mls_level_between(fromcon_sen, user_def, user_clr) )
+        {
+            *usercon_sen = *fromcon_sen;
+        }
+        else if ( mls_level_between(fromcon_clr, user_low, user_def) )
+        {
+            *usercon_sen = *user_low;
+        }
+        else
+            return -EINVAL;
+
+        /* Lower the clearance of available contexts
+           if the clearance of "fromcon" is lower than
+           that of the user's default clearance (but
+           only if the "fromcon" clearance dominates
+           the user's computed sensitivity level) */
+        if ( mls_level_dom(user_clr, fromcon_clr) )
+        {
+            *usercon_clr = *fromcon_clr;
+        }
+        else if ( mls_level_dom(fromcon_clr, user_clr) )
+        {
+            *usercon_clr = *user_clr;
+        }
+        else
+            return -EINVAL;
+    }
+
+    return 0;
+}
+
+/*
+ * Convert the MLS fields in the security context
+ * structure `c' from the values specified in the
+ * policy `oldp' to the values specified in the policy `newp'.
+ */
+int mls_convert_context(struct policydb *oldp, struct policydb *newp,
+                                                            struct context *c)
+{
+    struct level_datum *levdatum;
+    struct cat_datum *catdatum;
+    struct ebitmap bitmap;
+    struct ebitmap_node *node;
+    int l, i;
+
+    if ( !flask_mls_enabled )
+        return 0;
+
+    for ( l = 0; l < 2; l++ )
+    {
+        levdatum = hashtab_search(newp->p_levels.table,
+                        oldp->p_sens_val_to_name[c->range.level[l].sens - 1]);
+
+        if ( !levdatum )
+            return -EINVAL;
+        c->range.level[l].sens = levdatum->level->sens;
+
+        ebitmap_init(&bitmap);
+        ebitmap_for_each_bit(&c->range.level[l].cat, node, i)
+        {
+            if ( ebitmap_node_get_bit(node, i) )
+            {
+                int rc;
+
+                catdatum = hashtab_search(newp->p_cats.table,
+                             oldp->p_cat_val_to_name[i]);
+                if ( !catdatum )
+                    return -EINVAL;
+                rc = ebitmap_set_bit(&bitmap, catdatum->value - 1, 1);
+                if ( rc )
+                    return rc;
+            }
+        }
+        ebitmap_destroy(&c->range.level[l].cat);
+        c->range.level[l].cat = bitmap;
+    }
+
+    return 0;
+}
+
+int mls_compute_sid(struct context *scontext, struct context *tcontext,
+                        u16 tclass, u32 specified, struct context *newcontext)
+{
+    if ( !flask_mls_enabled )
+        return 0;
+
+    switch ( specified )
+    {
+        case AVTAB_TRANSITION:
+            if ( tclass == SECCLASS_DOMAIN )
+            {
+                struct range_trans *rangetr;
+                /* Look for a range transition rule. */
+                for ( rangetr = policydb.range_tr; rangetr;
+                                                    rangetr = rangetr->next)
+                {
+                    if ( rangetr->dom == scontext->type &&
+                                        rangetr->type == tcontext->type)
+                    {
+                        /* Set the range from the rule */
+                        return mls_range_set(newcontext, &rangetr->range);
+                    }
+                }
+            }
+            /* Fallthrough */
+        case AVTAB_CHANGE:
+            if ( tclass == SECCLASS_DOMAIN )
+                /* Use the process MLS attributes. */
+                return mls_copy_context(newcontext, scontext);
+            else
+            /* Use the process effective MLS attributes. */
+            return mls_scopy_context(newcontext, scontext);
+        case AVTAB_MEMBER:
+            /* Only polyinstantiate the MLS attributes if
+               the type is being polyinstantiated */
+            if ( newcontext->type != tcontext->type )
+            {
+                /* Use the process effective MLS attributes. */
+                return mls_scopy_context(newcontext, scontext);
+            }
+            else
+            {
+                /* Use the related object MLS attributes. */
+                return mls_copy_context(newcontext, tcontext);
+            }
+        default:
+            return -EINVAL;
+    }
+    return -EINVAL;
+}
+
diff -r cb2ecf48cf80 -r 8ae246493872 xen/xsm/flask/ss/mls.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/ss/mls.h	Mon Jun 04 11:06:52 2007 -0400
@@ -0,0 +1,37 @@
+/*
+ * Multi-level security (MLS) policy operations.
+ *
+ * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
+ */
+/*
+ * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
+ *
+ *    Support for enhanced MLS infrastructure.
+ *
+ * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
+ */
+
+#ifndef _SS_MLS_H_
+#define _SS_MLS_H_
+
+#include "context.h"
+#include "policydb.h"
+
+int mls_compute_context_len(struct context *context);
+void mls_sid_to_context(struct context *context, char **scontext);
+int mls_context_isvalid(struct policydb *p, struct context *c);
+
+int mls_context_to_sid(char oldc, char **scontext, struct context *context,
+                                               struct sidtab *s, u32 def_sid);
+
+int mls_convert_context(struct policydb *oldp, struct policydb *newp,
+                                                    struct context *context);
+
+int mls_compute_sid(struct context *scontext, struct context *tcontext,
+                        u16 tclass, u32 specified, struct context *newcontext);
+
+int mls_setup_user_range(struct context *fromcon, struct user_datum *user,
+                                                     struct context *usercon);
+
+#endif    /* _SS_MLS_H */
+
diff -r cb2ecf48cf80 -r 8ae246493872 xen/xsm/flask/ss/mls_types.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/ss/mls_types.h	Mon Jun 04 11:06:52 2007 -0400
@@ -0,0 +1,58 @@
+/*
+ * Type definitions for the multi-level security (MLS) policy.
+ *
+ * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
+ */
+/*
+ * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
+ *
+ *    Support for enhanced MLS infrastructure.
+ *
+ * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
+ */
+
+/* Ported to Xen 3.0, George Coker, <gscoker@alpha.ncsc.mil> */
+
+#ifndef _SS_MLS_TYPES_H_
+#define _SS_MLS_TYPES_H_
+
+#include "security.h"
+
+struct mls_level {
+    u32 sens;        /* sensitivity */
+    struct ebitmap cat;    /* category set */
+};
+
+struct mls_range {
+    struct mls_level level[2]; /* low == level[0], high == level[1] */
+};
+
+static inline int mls_level_eq(struct mls_level *l1, struct mls_level *l2)
+{
+    if ( !flask_mls_enabled )
+        return 1;
+
+    return ((l1->sens == l2->sens) &&
+            ebitmap_cmp(&l1->cat, &l2->cat));
+}
+
+static inline int mls_level_dom(struct mls_level *l1, struct mls_level *l2)
+{
+    if ( !flask_mls_enabled )
+        return 1;
+
+    return ((l1->sens >= l2->sens) &&
+            ebitmap_contains(&l1->cat, &l2->cat));
+}
+
+#define mls_level_incomp(l1, l2) \
+(!mls_level_dom((l1), (l2)) && !mls_level_dom((l2), (l1)))
+
+#define mls_level_between(l1, l2, l3) \
+(mls_level_dom((l1), (l2)) && mls_level_dom((l3), (l1)))
+
+#define mls_range_contains(r1, r2) \
+(mls_level_dom(&(r2).level[0], &(r1).level[0]) && \
+ mls_level_dom(&(r1).level[1], &(r2).level[1]))
+
+#endif    /* _SS_MLS_TYPES_H_ */
diff -r cb2ecf48cf80 -r 8ae246493872 xen/xsm/flask/ss/policydb.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/ss/policydb.c	Mon Jun 04 11:06:52 2007 -0400
@@ -0,0 +1,1798 @@
+/*
+ * Implementation of the policy database.
+ *
+ * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
+ */
+
+/*
+ * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
+ *
+ *    Support for enhanced MLS infrastructure.
+ *
+ * Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com>
+ *
+ *     Added conditional policy language extensions
+ *
+ * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
+ * Copyright (C) 2003 - 2004 Tresys Technology, LLC
+ *    This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation, version 2.
+ */
+
+/* Ported to Xen 3.0, George Coker, <gscoker@alpha.ncsc.mil> */
+
+#include <asm/byteorder.h>
+#include <xen/lib.h>
+#include <xen/types.h>
+#include <xen/xmalloc.h>
+#include <xen/string.h>
+#include <xen/errno.h>
+#include "security.h"
+
+#include "policydb.h"
+#include "conditional.h"
+#include "mls.h"
+
+#define _DEBUG_HASHES
+
+#ifdef DEBUG_HASHES
+static char *symtab_name[SYM_NUM] = {
+    "common prefixes",
+    "classes",
+    "roles",
+    "types",
+    "users",
+    "bools",
+    "levels",
+    "categories",
+};
+#endif
+
+int flask_mls_enabled = 0;
+
+static unsigned int symtab_sizes[SYM_NUM] = {
+    2,
+    32,
+    16,
+    512,
+    128,
+    16,
+    16,
+    16,
+};
+
+struct policydb_compat_info {
+    int version;
+    int sym_num;
+    int ocon_num;
+};
+
+/* These need to be updated if SYM_NUM or OCON_NUM changes */
+static struct policydb_compat_info policydb_compat[] = {
+    {
+        .version        = POLICYDB_VERSION_BASE,
+        .sym_num        = SYM_NUM - 3,
+        .ocon_num       = OCON_NUM - 1,
+    },
+    {
+        .version        = POLICYDB_VERSION_BOOL,
+        .sym_num        = SYM_NUM - 2,
+        .ocon_num       = OCON_NUM - 1,
+    },
+    {
+        .version        = POLICYDB_VERSION_IPV6,
+        .sym_num        = SYM_NUM - 2,
+        .ocon_num       = OCON_NUM,
+    },
+    {
+        .version        = POLICYDB_VERSION_NLCLASS,
+        .sym_num        = SYM_NUM - 2,
+        .ocon_num       = OCON_NUM,
+    },
+    {
+        .version        = POLICYDB_VERSION_MLS,
+        .sym_num        = SYM_NUM,
+        .ocon_num       = OCON_NUM,
+    },
+    {
+        .version        = POLICYDB_VERSION_AVTAB,
+        .sym_num        = SYM_NUM,
+        .ocon_num       = OCON_NUM,
+    },
+};
+
+static struct policydb_compat_info *policydb_lookup_compat(int version)
+{
+    int i;
+    struct policydb_compat_info *info = NULL;
+
+    for ( i = 0; i < sizeof(policydb_compat)/sizeof(*info); i++ )
+    {
+        if ( policydb_compat[i].version == version )
+        {
+            info = &policydb_compat[i];
+            break;
+        }
+    }
+    return info;
+}
+
+/*
+ * Initialize the role table.
+ */
+static int roles_init(struct policydb *p)
+{
+    char *key = NULL;
+    int rc;
+    struct role_datum *role;
+
+    role = xmalloc(struct role_datum);
+    if ( !role )
+    {
+        rc = -ENOMEM;
+        goto out;
+    }
+    memset(role, 0, sizeof(*role));
+    role->value = ++p->p_roles.nprim;
+    if ( role->value != OBJECT_R_VAL )
+    {
+        rc = -EINVAL;
+        goto out_free_role;
+    }
+    key = xmalloc_array(char, strlen(OBJECT_R)+1);
+    if ( !key )
+    {
+        rc = -ENOMEM;
+        goto out_free_role;
+    }
+    strlcpy(key, OBJECT_R, strlen(OBJECT_R)+1);
+    rc = hashtab_insert(p->p_roles.table, key, role);
+    if ( rc )
+        goto out_free_key;
+out:
+    return rc;
+
+out_free_key:
+    xfree(key);
+out_free_role:
+    xfree(role);
+    goto out;
+}
+
+/*
+ * Initialize a policy database structure.
+ */
+static int policydb_init(struct policydb *p)
+{
+    int i, rc;
+
+    memset(p, 0, sizeof(*p));
+
+    for ( i = 0; i < SYM_NUM; i++ )
+    {
+        rc = symtab_init(&p->symtab[i], symtab_sizes[i]);
+        if ( rc )
+            goto out_free_symtab;
+    }
+
+    rc = avtab_init(&p->te_avtab);
+    if ( rc )
+        goto out_free_symtab;
+
+    rc = roles_init(p);
+    if ( rc )
+        goto out_free_avtab;
+
+    rc = cond_policydb_init(p);
+    if ( rc )
+        goto out_free_avtab;
+
+out:
+    return rc;
+
+out_free_avtab:
+    avtab_destroy(&p->te_avtab);
+
+out_free_symtab:
+    for ( i = 0; i < SYM_NUM; i++ )
+        hashtab_destroy(p->symtab[i].table);
+    goto out;
+}
+
+/*
+ * The following *_index functions are used to
+ * define the val_to_name and val_to_struct arrays
+ * in a policy database structure.  The val_to_name
+ * arrays are used when converting security context
+ * structures into string representations.  The
+ * val_to_struct arrays are used when the attributes
+ * of a class, role, or user are needed.
+ */
+
+static int common_index(void *key, void *datum, void *datap)
+{
+    struct policydb *p;
+    struct common_datum *comdatum;
+
+    comdatum = datum;
+    p = datap;
+    if ( !comdatum->value || comdatum->value > p->p_commons.nprim )
+        return -EINVAL;
+    p->p_common_val_to_name[comdatum->value - 1] = key;
+    return 0;
+}
+
+static int class_index(void *key, void *datum, void *datap)
+{
+    struct policydb *p;
+    struct class_datum *cladatum;
+
+    cladatum = datum;
+    p = datap;
+    if ( !cladatum->value || cladatum->value > p->p_classes.nprim )
+        return -EINVAL;
+    p->p_class_val_to_name[cladatum->value - 1] = key;
+    p->class_val_to_struct[cladatum->value - 1] = cladatum;
+    return 0;
+}
+
+static int role_index(void *key, void *datum, void *datap)
+{
+    struct policydb *p;
+    struct role_datum *role;
+
+    role = datum;
+    p = datap;
+    if ( !role->value || role->value > p->p_roles.nprim )
+        return -EINVAL;
+    p->p_role_val_to_name[role->value - 1] = key;
+    p->role_val_to_struct[role->value - 1] = role;
+    return 0;
+}
+
+static int type_index(void *key, void *datum, void *datap)
+{
+    struct policydb *p;
+    struct type_datum *typdatum;
+
+    typdatum = datum;
+    p = datap;
+
+    if ( typdatum->primary )
+    {
+        if ( !typdatum->value || typdatum->value > p->p_types.nprim )
+            return -EINVAL;
+        p->p_type_val_to_name[typdatum->value - 1] = key;
+    }
+
+    return 0;
+}
+
+static int user_index(void *key, void *datum, void *datap)
+{
+    struct policydb *p;
+    struct user_datum *usrdatum;
+
+    usrdatum = datum;
+    p = datap;
+    if ( !usrdatum->value || usrdatum->value > p->p_users.nprim )
+        return -EINVAL;
+    p->p_user_val_to_name[usrdatum->value - 1] = key;
+    p->user_val_to_struct[usrdatum->value - 1] = usrdatum;
+    return 0;
+}
+
+static int sens_index(void *key, void *datum, void *datap)
+{
+    struct policydb *p;
+    struct level_datum *levdatum;
+
+    levdatum = datum;
+    p = datap;
+
+    if ( !levdatum->isalias )
+    {
+        if ( !levdatum->level->sens || levdatum->level->sens > 
+                                                        p->p_levels.nprim )
+            return -EINVAL;
+        p->p_sens_val_to_name[levdatum->level->sens - 1] = key;
+    }
+
+    return 0;
+}
+
+static int cat_index(void *key, void *datum, void *datap)
+{
+    struct policydb *p;
+    struct cat_datum *catdatum;
+
+    catdatum = datum;
+    p = datap;
+
+    if ( !catdatum->isalias )
+    {
+        if ( !catdatum->value || catdatum->value > p->p_cats.nprim )
+            return -EINVAL;
+        p->p_cat_val_to_name[catdatum->value - 1] = key;
+    }
+
+    return 0;
+}
+
+static int (*index_f[SYM_NUM]) (void *key, void *datum, void *datap) =
+{
+    common_index,
+    class_index,
+    role_index,
+    type_index,
+    user_index,
+    cond_index_bool,
+    sens_index,
+    cat_index,
+};
+
+/*
+ * Define the common val_to_name array and the class
+ * val_to_name and val_to_struct arrays in a policy
+ * database structure.
+ *
+ * Caller must clean up upon failure.
+ */
+static int policydb_index_classes(struct policydb *p)
+{
+    int rc;
+
+    p->p_common_val_to_name =
+        xmalloc_array(char *, p->p_commons.nprim);
+    if ( !p->p_common_val_to_name )
+    {
+        rc = -ENOMEM;
+        goto out;
+    }
+
+    rc = hashtab_map(p->p_commons.table, common_index, p);
+    if ( rc )
+        goto out;
+
+    p->class_val_to_struct =
+        (void *)xmalloc_array(struct class_datum, p->p_classes.nprim);
+    if ( !p->class_val_to_struct )
+    {
+        rc = -ENOMEM;
+        goto out;
+    }
+
+    p->p_class_val_to_name =
+        xmalloc_array(char *, p->p_classes.nprim);
+    if ( !p->p_class_val_to_name )
+    {
+        rc = -ENOMEM;
+        goto out;
+    }
+
+    rc = hashtab_map(p->p_classes.table, class_index, p);
+out:
+    return rc;
+}
+
+#ifdef DEBUG_HASHES
+static void symtab_hash_eval(struct symtab *s)
+{
+    int i;
+
+    for ( i = 0; i < SYM_NUM; i++ )
+    {
+        struct hashtab *h = s[i].table;
+        struct hashtab_info info;
+
+        hashtab_stat(h, &info);
+        printk(KERN_INFO "%s:  %d entries and %d/%d buckets used, "
+               "longest chain length %d\n", symtab_name[i], h->nel,
+               info.slots_used, h->size, info.max_chain_len);
+    }
+}
+#endif
+
+/*
+ * Define the other val_to_name and val_to_struct arrays
+ * in a policy database structure.
+ *
+ * Caller must clean up on failure.
+ */
+static int policydb_index_others(struct policydb *p)
+{
+    int i, rc = 0;
+
+    printk(KERN_INFO "security:  %d users, %d roles, %d types, %d bools",
+           p->p_users.nprim, p->p_roles.nprim, p->p_types.nprim, p->p_bools.nprim);
+    if ( flask_mls_enabled )
+        printk(", %d sens, %d cats", p->p_levels.nprim, p->p_cats.nprim);
+
+    printk("\n");
+
+    printk(KERN_INFO "security:  %d classes, %d rules\n",
+           p->p_classes.nprim, p->te_avtab.nel);
+
+#ifdef DEBUG_HASHES
+    avtab_hash_eval(&p->te_avtab, "rules");
+    symtab_hash_eval(p->symtab);
+#endif
+
+    p->role_val_to_struct =
+        (void *)xmalloc_array(struct role_datum, p->p_roles.nprim);
+    if ( !p->role_val_to_struct )
+    {
+        rc = -ENOMEM;
+        goto out;
+    }
+
+    p->user_val_to_struct =
+        (void *)xmalloc_array(struct user_datum, p->p_users.nprim);
+    if ( !p->user_val_to_struct )
+    {
+        rc = -ENOMEM;
+        goto out;
+    }
+
+    if ( cond_init_bool_indexes(p) )
+    {
+        rc = -ENOMEM;
+        goto out;
+    }
+
+    for ( i = SYM_ROLES; i < SYM_NUM; i++ )
+    {
+        p->sym_val_to_name[i] =
+            xmalloc_array(char *, p->symtab[i].nprim);
+        if ( !p->sym_val_to_name[i] )
+        {
+            rc = -ENOMEM;
+            goto out;
+        }
+        rc = hashtab_map(p->symtab[i].table, index_f[i], p);
+        if ( rc )
+            goto out;
+    }
+
+out:
+    return rc;
+}
+
+/*
+ * The following *_destroy functions are used to
+ * free any memory allocated for each kind of
+ * symbol data in the policy database.
+ */
+
+static int perm_destroy(void *key, void *datum, void *p)
+{
+    xfree(key);
+    xfree(datum);
+    return 0;
+}
+
+static int common_destroy(void *key, void *datum, void *p)
+{
+    struct common_datum *comdatum;
+
+    xfree(key);
+    comdatum = datum;
+    hashtab_map(comdatum->permissions.table, perm_destroy, NULL);
+    hashtab_destroy(comdatum->permissions.table);
+    xfree(datum);
+    return 0;
+}
+
+static int class_destroy(void *key, void *datum, void *p)
+{
+    struct class_datum *cladatum;
+    struct constraint_node *constraint, *ctemp;
+    struct constraint_expr *e, *etmp;
+
+    xfree(key);
+    cladatum = datum;
+    hashtab_map(cladatum->permissions.table, perm_destroy, NULL);
+    hashtab_destroy(cladatum->permissions.table);
+    constraint = cladatum->constraints;
+    while ( constraint )
+    {
+        e = constraint->expr;
+        while ( e )
+        {
+            ebitmap_destroy(&e->names);
+            etmp = e;
+            e = e->next;
+            xfree(etmp);
+        }
+        ctemp = constraint;
+        constraint = constraint->next;
+        xfree(ctemp);
+    }
+
+    constraint = cladatum->validatetrans;
+    while ( constraint )
+    {
+        e = constraint->expr;
+        while ( e )
+        {
+            ebitmap_destroy(&e->names);
+            etmp = e;
+            e = e->next;
+            xfree(etmp);
+        }
+        ctemp = constraint;
+        constraint = constraint->next;
+        xfree(ctemp);
+    }
+
+    xfree(cladatum->comkey);
+    xfree(datum);
+    return 0;
+}
+
+static int role_destroy(void *key, void *datum, void *p)
+{
+    struct role_datum *role;
+
+    xfree(key);
+    role = datum;
+    ebitmap_destroy(&role->dominates);
+    ebitmap_destroy(&role->types);
+    xfree(datum);
+    return 0;
+}
+
+static int type_destroy(void *key, void *datum, void *p)
+{
+    xfree(key);
+    xfree(datum);
+    return 0;
+}
+
+static int user_destroy(void *key, void *datum, void *p)
+{
+    struct user_datum *usrdatum;
+
+    xfree(key);
+    usrdatum = datum;
+    ebitmap_destroy(&usrdatum->roles);
+    ebitmap_destroy(&usrdatum->range.level[0].cat);
+    ebitmap_destroy(&usrdatum->range.level[1].cat);
+    ebitmap_destroy(&usrdatum->dfltlevel.cat);
+    xfree(datum);
+    return 0;
+}
+
+static int sens_destroy(void *key, void *datum, void *p)
+{
+    struct level_datum *levdatum;
+
+    xfree(key);
+    levdatum = datum;
+    ebitmap_destroy(&levdatum->level->cat);
+    xfree(levdatum->level);
+    xfree(datum);
+    return 0;
+}
+
+static int cat_destroy(void *key, void *datum, void *p)
+{
+    xfree(key);
+    xfree(datum);
+    return 0;
+}
+
+static int (*destroy_f[SYM_NUM]) (void *key, void *datum, void *datap) =
+{
+    common_destroy,
+    class_destroy,
+    role_destroy,
+    type_destroy,
+    user_destroy,
+    cond_destroy_bool,
+    sens_destroy,
+    cat_destroy,
+};
+
+static void ocontext_destroy(struct ocontext *c, int i)
+{
+    context_destroy(&c->context[0]);
+    context_destroy(&c->context[1]);
+    if ( i == OCON_ISID )
+        xfree(c->u.name);
+    xfree(c);
+}
+
+/*
+ * Free any memory allocated by a policy database structure.
+ */
+void policydb_destroy(struct policydb *p)
+{
+    struct ocontext *c, *ctmp;
+    int i;
+    struct role_allow *ra, *lra = NULL;
+    struct role_trans *tr, *ltr = NULL;
+    struct range_trans *rt, *lrt = NULL;
+
+    for ( i = 0; i < SYM_NUM; i++ )
+    {
+        hashtab_map(p->symtab[i].table, destroy_f[i], NULL);
+        hashtab_destroy(p->symtab[i].table);
+    }
+
+    for ( i = 0; i < SYM_NUM; i++ )
+        xfree(p->sym_val_to_name[i]);
+
+    xfree(p->class_val_to_struct);
+    xfree(p->role_val_to_struct);
+    xfree(p->user_val_to_struct);
+
+    avtab_destroy(&p->te_avtab);
+
+    for ( i = 0; i < OCON_NUM; i++ )
+    {
+        c = p->ocontexts[i];
+        while ( c )
+        {
+            ctmp = c;
+            c = c->next;
+            ocontext_destroy(ctmp,i);
+        }
+    }
+
+    cond_policydb_destroy(p);
+
+    for ( tr = p->role_tr; tr; tr = tr->next )
+    {
+        if ( ltr ) xfree(ltr);
+        ltr = tr;
+    }
+    if ( ltr ) xfree(ltr);
+
+    for ( ra = p->role_allow; ra; ra = ra -> next )
+    {
+        if ( lra ) xfree(lra);
+        lra = ra;
+    }
+    if ( lra ) xfree(lra);
+
+    for ( rt = p->range_tr; rt; rt = rt -> next )
+    {
+        if ( lrt ) xfree(lrt);
+        lrt = rt;
+    }
+    if ( lrt ) xfree(lrt);
+
+    for ( i = 0; i < p->p_types.nprim; i++ )
+        ebitmap_destroy(&p->type_attr_map[i]);
+    xfree(p->type_attr_map);
+
+    return;
+}
+
+/*
+ * Load the initial SIDs specified in a policy database
+ * structure into a SID table.
+ */
+int policydb_load_isids(struct policydb *p, struct sidtab *s)
+{
+    struct ocontext *head, *c;
+    int rc;
+
+    rc = sidtab_init(s);
+    if ( rc )
+    {
+        printk(KERN_ERR "security:  out of memory on SID table init\n");
+        goto out;
+    }
+
+    head = p->ocontexts[OCON_ISID];
+    for ( c = head; c; c = c->next )
+    {
+        if ( !c->context[0].user )
+        {
+            printk(KERN_ERR "security:  SID %s was never "
+                   "defined.\n", c->u.name);
+            rc = -EINVAL;
+            goto out;
+        }
+        if ( sidtab_insert(s, c->sid[0], &c->context[0]) )
+        {
+            printk(KERN_ERR "security:  unable to load initial "
+                   "SID %s.\n", c->u.name);
+            rc = -EINVAL;
+            goto out;
+        }
+    }
+out:
+    return rc;
+}
+
+/*
+ * Return 1 if the fields in the security context
+ * structure `c' are valid.  Return 0 otherwise.
+ */
+int policydb_context_isvalid(struct policydb *p, struct context *c)
+{
+    struct role_datum *role;
+    struct user_datum *usrdatum;
+
+    if ( !c->role || c->role > p->p_roles.nprim )
+        return 0;
+
+    if ( !c->user || c->user > p->p_users.nprim )
+        return 0;
+
+    if ( !c->type || c->type > p->p_types.nprim )
+        return 0;
+
+    if ( c->role != OBJECT_R_VAL )
+    {
+        /*
+         * Role must be authorized for the type.
+         */
+        role = p->role_val_to_struct[c->role - 1];
+        if ( !ebitmap_get_bit(&role->types, c->type - 1) )
+            /* role may not be associated with type */
+            return 0;
+
+        /*
+         * User must be authorized for the role.
+         */
+        usrdatum = p->user_val_to_struct[c->user - 1];
+        if ( !usrdatum )
+            return 0;
+
+        if ( !ebitmap_get_bit(&usrdatum->roles, c->role - 1) )
+            /* user may not be associated with role */
+            return 0;
+    }
+
+    if ( !mls_context_isvalid(p, c) )
+        return 0;
+
+    return 1;
+}
+
+/*
+ * Read a MLS range structure from a policydb binary
+ * representation file.
+ */
+static int mls_read_range_helper(struct mls_range *r, void *fp)
+{
+    __le32 buf[2];
+    u32 items;
+    int rc;
+
+    rc = next_entry(buf, fp, sizeof(u32));
+    if ( rc < 0 )
+        goto out;
+
+    items = le32_to_cpu(buf[0]);
+    if ( items > ARRAY_SIZE(buf) )
+    {
+        printk(KERN_ERR "security: mls:  range overflow\n");
+        rc = -EINVAL;
+        goto out;
+    }
+    rc = next_entry(buf, fp, sizeof(u32) * items);
+    if ( rc < 0 )
+    {
+        printk(KERN_ERR "security: mls:  truncated range\n");
+        goto out;
+    }
+    r->level[0].sens = le32_to_cpu(buf[0]);
+    if ( items > 1 )
+        r->level[1].sens = le32_to_cpu(buf[1]);
+    else
+        r->level[1].sens = r->level[0].sens;
+
+    rc = ebitmap_read(&r->level[0].cat, fp);
+    if ( rc )
+    {
+        printk(KERN_ERR "security: mls:  error reading low "
+               "categories\n");
+        goto out;
+    }
+    if ( items > 1 )
+    {
+        rc = ebitmap_read(&r->level[1].cat, fp);
+        if ( rc )
+        {
+            printk(KERN_ERR "security: mls:  error reading high "
+                   "categories\n");
+            goto bad_high;
+        }
+    }
+    else
+    {
+        rc = ebitmap_cpy(&r->level[1].cat, &r->level[0].cat);
+        if ( rc )
+        {
+            printk(KERN_ERR "security: mls:  out of memory\n");
+            goto bad_high;
+        }
+    }
+
+    rc = 0;
+out:
+    return rc;
+bad_high:
+    ebitmap_destroy(&r->level[0].cat);
+    goto out;
+}
+
+/*
+ * Read and validate a security context structure
+ * from a policydb binary representation file.
+ */
+static int context_read_and_validate(struct context *c, struct policydb *p,
+                                                                    void *fp)
+{
+    __le32 buf[3];
+    int rc;
+
+    rc = next_entry(buf, fp, sizeof buf);
+    if ( rc < 0 )
+    {
+        printk(KERN_ERR "security: context truncated\n");
+        goto out;
+    }
+    c->user = le32_to_cpu(buf[0]);
+    c->role = le32_to_cpu(buf[1]);
+    c->type = le32_to_cpu(buf[2]);
+    if ( p->policyvers >= POLICYDB_VERSION_MLS )
+    {
+        if ( mls_read_range_helper(&c->range, fp) )
+        {
+            printk(KERN_ERR "security: error reading MLS range of "
+                   "context\n");
+            rc = -EINVAL;
+            goto out;
+        }
+    }
+
+    if ( !policydb_context_isvalid(p, c) )
+    {
+        printk(KERN_ERR "security:  invalid security context\n");
+        context_destroy(c);
+        rc = -EINVAL;
+    }
+out:
+    return rc;
+}
+
+/*
+ * The following *_read functions are used to
+ * read the symbol data from a policy database
+ * binary representation file.
+ */
+
+static int perm_read(struct policydb *p, struct hashtab *h, void *fp)
+{
+    char *key = NULL;
+    struct perm_datum *perdatum;
+    int rc;
+    __le32 buf[2];
+    u32 len;
+
+    perdatum = xmalloc(struct perm_datum);
+    if ( !perdatum )
+    {
+        rc = -ENOMEM;
+        goto out;
+    }
+    memset(perdatum, 0, sizeof(*perdatum));
+
+    rc = next_entry(buf, fp, sizeof buf);
+    if ( rc < 0 )
+        goto bad;
+
+    len = le32_to_cpu(buf[0]);
+    perdatum->value = le32_to_cpu(buf[1]);
+
+    key = xmalloc_array(char, len + 1);
+    if ( !key )
+    {
+        rc = -ENOMEM;
+        goto bad;
+    }
+    rc = next_entry(key, fp, len);
+    if ( rc < 0 )
+        goto bad;
+    key[len] = 0;
+
+    rc = hashtab_insert(h, key, perdatum);
+    if ( rc )
+        goto bad;
+out:
+    return rc;
+bad:
+    perm_destroy(key, perdatum, NULL);
+    goto out;
+}
+
+static int common_read(struct policydb *p, struct hashtab *h, void *fp)
+{
+    char *key = NULL;
+    struct common_datum *comdatum;
+    __le32 buf[4];
+    u32 len, nel;
+    int i, rc;
+
+    comdatum = xmalloc(struct common_datum);
+    if ( !comdatum )
+    {
+        rc = -ENOMEM;
+        goto out;
+    }
+    memset(comdatum, 0, sizeof(*comdatum));
+
+    rc = next_entry(buf, fp, sizeof buf);
+    if ( rc < 0 )
+        goto bad;
+
+    len = le32_to_cpu(buf[0]);
+    comdatum->value = le32_to_cpu(buf[1]);
+
+    rc = symtab_init(&comdatum->permissions, PERM_SYMTAB_SIZE);
+    if ( rc )
+        goto bad;
+    comdatum->permissions.nprim = le32_to_cpu(buf[2]);
+    nel = le32_to_cpu(buf[3]);
+
+    key = xmalloc_array(char, len + 1);
+    if ( !key )
+    {
+        rc = -ENOMEM;
+        goto bad;
+    }
+    rc = next_entry(key, fp, len);
+    if ( rc < 0 )
+        goto bad;
+    key[len] = 0;
+
+    for ( i = 0; i < nel; i++ )
+    {
+        rc = perm_read(p, comdatum->permissions.table, fp);
+        if ( rc )
+            goto bad;
+    }
+
+    rc = hashtab_insert(h, key, comdatum);
+    if ( rc )
+        goto bad;
+out:
+    return rc;
+bad:
+    common_destroy(key, comdatum, NULL);
+    goto out;
+}
+
+static int read_cons_helper(struct constraint_node **nodep, int ncons,
+                                                    int allowxtarget, void *fp)
+{
+    struct constraint_node *c, *lc;
+    struct constraint_expr *e, *le;
+    __le32 buf[3];
+    u32 nexpr;
+    int rc, i, j, depth;
+
+    lc = NULL;
+    for ( i = 0; i < ncons; i++ )
+    {
+        c = xmalloc(struct constraint_node);
+        if ( !c )
+            return -ENOMEM;
+        memset(c, 0, sizeof(*c));
+
+        if ( lc )
+        {
+            lc->next = c;
+        }
+        else
+        {
+            *nodep = c;
+        }
+
+        rc = next_entry(buf, fp, (sizeof(u32) * 2));
+        if ( rc < 0 )
+            return rc;
+        c->permissions = le32_to_cpu(buf[0]);
+        nexpr = le32_to_cpu(buf[1]);
+        le = NULL;
+        depth = -1;
+        for ( j = 0; j < nexpr; j++ )
+        {
+            e = xmalloc(struct constraint_expr);
+            if ( !e )
+                return -ENOMEM;
+            memset(e, 0, sizeof(*e));
+
+            if ( le )
+                le->next = e;
+            else
+                c->expr = e;
+
+            rc = next_entry(buf, fp, (sizeof(u32) * 3));
+            if ( rc < 0 )
+                return rc;
+            e->expr_type = le32_to_cpu(buf[0]);
+            e->attr = le32_to_cpu(buf[1]);
+            e->op = le32_to_cpu(buf[2]);
+
+            switch ( e->expr_type )
+            {
+                case CEXPR_NOT:
+                    if ( depth < 0 )
+                        return -EINVAL;
+                break;
+                case CEXPR_AND:
+                case CEXPR_OR:
+                    if ( depth < 1 )
+                        return -EINVAL;
+                    depth--;
+                break;
+                case CEXPR_ATTR:
+                    if ( depth == (CEXPR_MAXDEPTH - 1) )
+                        return -EINVAL;
+                    depth++;
+                break;
+                case CEXPR_NAMES:
+                    if ( !allowxtarget && (e->attr & CEXPR_XTARGET) )
+                        return -EINVAL;
+                    if ( depth == (CEXPR_MAXDEPTH - 1) )
+                        return -EINVAL;
+                    depth++;
+                    if ( ebitmap_read(&e->names, fp) )
+                        return -EINVAL;
+                break;
+                default:
+                    return -EINVAL;
+            }
+            le = e;
+        }
+        if ( depth != 0 )
+            return -EINVAL;
+        lc = c;
+    }
+
+    return 0;
+}
+
+static int class_read(struct policydb *p, struct hashtab *h, void *fp)
+{
+    char *key = NULL;
+    struct class_datum *cladatum;
+    __le32 buf[6];
+    u32 len, len2, ncons, nel;
+    int i, rc;
+
+    cladatum = xmalloc(struct class_datum);
+    if ( !cladatum )
+    {
+        rc = -ENOMEM;
+        goto out;
+    }
+    memset(cladatum, 0, sizeof(*cladatum));
+
+    rc = next_entry(buf, fp, sizeof(u32)*6);
+    if ( rc < 0 )
+        goto bad;
+
+    len = le32_to_cpu(buf[0]);
+    len2 = le32_to_cpu(buf[1]);
+    cladatum->value = le32_to_cpu(buf[2]);
+
+    rc = symtab_init(&cladatum->permissions, PERM_SYMTAB_SIZE);
+    if ( rc )
+        goto bad;
+    cladatum->permissions.nprim = le32_to_cpu(buf[3]);
+    nel = le32_to_cpu(buf[4]);
+
+    ncons = le32_to_cpu(buf[5]);
+
+    key = xmalloc_array(char, len + 1);
+    if ( !key )
+    {
+        rc = -ENOMEM;
+        goto bad;
+    }
+    rc = next_entry(key, fp, len);
+    if ( rc < 0 )
+        goto bad;
+    key[len] = 0;
+
+    if ( len2 )
+    {
+        cladatum->comkey = xmalloc_array(char, len2 + 1);
+        if ( !cladatum->comkey )
+        {
+            rc = -ENOMEM;
+            goto bad;
+        }
+        rc = next_entry(cladatum->comkey, fp, len2);
+        if ( rc < 0 )
+            goto bad;
+        cladatum->comkey[len2] = 0;
+
+        cladatum->comdatum = hashtab_search(p->p_commons.table,
+                            cladatum->comkey);
+        if ( !cladatum->comdatum )
+        {
+            printk(KERN_ERR "security:  unknown common %s\n",
+                   cladatum->comkey);
+            rc = -EINVAL;
+            goto bad;
+        }
+    }
+    for ( i = 0; i < nel; i++ )
+    {
+        rc = perm_read(p, cladatum->permissions.table, fp);
+        if ( rc )
+            goto bad;
+    }
+
+    rc = read_cons_helper(&cladatum->constraints, ncons, 0, fp);
+    if ( rc )
+        goto bad;
+
+    if ( p->policyvers >= POLICYDB_VERSION_VALIDATETRANS )
+    {
+        /* grab the validatetrans rules */
+        rc = next_entry(buf, fp, sizeof(u32));
+        if ( rc < 0 )
+            goto bad;
+        ncons = le32_to_cpu(buf[0]);
+        rc = read_cons_helper(&cladatum->validatetrans, ncons, 1, fp);
+        if ( rc )
+            goto bad;
+    }
+
+    rc = hashtab_insert(h, key, cladatum);
+    if ( rc )
+        goto bad;
+
+    rc = 0;
+out:
+    return rc;
+bad:
+    class_destroy(key, cladatum, NULL);
+    goto out;
+}
+
+static int role_read(struct policydb *p, struct hashtab *h, void *fp)
+{
+    char *key = NULL;
+    struct role_datum *role;
+    int rc;
+    __le32 buf[2];
+    u32 len;
+
+    role = xmalloc(struct role_datum);
+    if ( !role )
+    {
+        rc = -ENOMEM;
+        goto out;
+    }
+    memset(role, 0, sizeof(*role));
+
+    rc = next_entry(buf, fp, sizeof buf);
+    if ( rc < 0 )
+        goto bad;
+
+    len = le32_to_cpu(buf[0]);
+    role->value = le32_to_cpu(buf[1]);
+
+    key = xmalloc_array(char, len + 1);
+    if ( !key )
+    {
+        rc = -ENOMEM;
+        goto bad;
+    }
+    rc = next_entry(key, fp, len);
+    if ( rc < 0 )
+        goto bad;
+    key[len] = 0;
+
+    rc = ebitmap_read(&role->dominates, fp);
+    if ( rc )
+        goto bad;
+
+    rc = ebitmap_read(&role->types, fp);
+    if ( rc )
+        goto bad;
+
+    if ( strcmp(key, OBJECT_R) == 0 )
+    {
+        if ( role->value != OBJECT_R_VAL )
+        {
+            printk(KERN_ERR "Role %s has wrong value %d\n", OBJECT_R,
+                                                                role->value);
+            rc = -EINVAL;
+            goto bad;
+        }
+        rc = 0;
+        goto bad;
+    }
+
+    rc = hashtab_insert(h, key, role);
+    if ( rc )
+        goto bad;
+out:
+    return rc;
+bad:
+    role_destroy(key, role, NULL);
+    goto out;
+}
+
+static int type_read(struct policydb *p, struct hashtab *h, void *fp)
+{
+    char *key = NULL;
+    struct type_datum *typdatum;
+    int rc;
+    __le32 buf[3];
+    u32 len;
+
+    typdatum = xmalloc(struct type_datum);
+    if ( !typdatum )
+    {
+        rc = -ENOMEM;
+        return rc;
+    }
+    memset(typdatum, 0, sizeof(*typdatum));
+
+    rc = next_entry(buf, fp, sizeof buf);
+    if ( rc < 0 )
+        goto bad;
+
+    len = le32_to_cpu(buf[0]);
+    typdatum->value = le32_to_cpu(buf[1]);
+    typdatum->primary = le32_to_cpu(buf[2]);
+
+    key = xmalloc_array(char, len + 1);
+    if ( !key )
+    {
+        rc = -ENOMEM;
+        goto bad;
+    }
+    rc = next_entry(key, fp, len);
+    if ( rc < 0 )
+        goto bad;
+    key[len] = 0;
+
+    rc = hashtab_insert(h, key, typdatum);
+    if ( rc )
+        goto bad;
+out:
+    return rc;
+bad:
+    type_destroy(key, typdatum, NULL);
+    goto out;
+}
+
+
+/*
+ * Read a MLS level structure from a policydb binary
+ * representation file.
+ */
+static int mls_read_level(struct mls_level *lp, void *fp)
+{
+    __le32 buf[1];
+    int rc;
+
+    memset(lp, 0, sizeof(*lp));
+
+    rc = next_entry(buf, fp, sizeof buf);
+    if ( rc < 0 )
+    {
+        printk(KERN_ERR "security: mls: truncated level\n");
+        goto bad;
+    }
+    lp->sens = le32_to_cpu(buf[0]);
+
+    if ( ebitmap_read(&lp->cat, fp) )
+    {
+        printk(KERN_ERR "security: mls:  error reading level categories\n");
+        goto bad;
+    }
+    return 0;
+
+bad:
+    return -EINVAL;
+}
+
+static int user_read(struct policydb *p, struct hashtab *h, void *fp)
+{
+    char *key = NULL;
+    struct user_datum *usrdatum;
+    int rc;
+    __le32 buf[2];
+    u32 len;
+
+    usrdatum = xmalloc(struct user_datum);
+    if ( !usrdatum )
+    {
+        rc = -ENOMEM;
+        goto out;
+    }
+    memset(usrdatum, 0, sizeof(*usrdatum));
+
+    rc = next_entry(buf, fp, sizeof buf);
+    if ( rc < 0 )
+        goto bad;
+
+    len = le32_to_cpu(buf[0]);
+    usrdatum->value = le32_to_cpu(buf[1]);
+
+    key = xmalloc_array(char, len + 1);
+    if ( !key )
+    {
+        rc = -ENOMEM;
+        goto bad;
+    }
+    rc = next_entry(key, fp, len);
+    if ( rc < 0 )
+        goto bad;
+    key[len] = 0;
+
+    rc = ebitmap_read(&usrdatum->roles, fp);
+    if ( rc )
+        goto bad;
+
+    if ( p->policyvers >= POLICYDB_VERSION_MLS )
+    {
+        rc = mls_read_range_helper(&usrdatum->range, fp);
+        if ( rc )
+            goto bad;
+        rc = mls_read_level(&usrdatum->dfltlevel, fp);
+        if ( rc )
+            goto bad;
+    }
+
+    rc = hashtab_insert(h, key, usrdatum);
+    if ( rc )
+        goto bad;
+out:
+    return rc;
+bad:
+    user_destroy(key, usrdatum, NULL);
+    goto out;
+}
+
+static int sens_read(struct policydb *p, struct hashtab *h, void *fp)
+{
+    char *key = NULL;
+    struct level_datum *levdatum;
+    int rc;
+    __le32 buf[2];
+    u32 len;
+
+    levdatum = xmalloc(struct level_datum);
+    if ( !levdatum )
+    {
+        rc = -ENOMEM;
+        goto out;
+    }
+    memset(levdatum, 0, sizeof(*levdatum));
+
+    rc = next_entry(buf, fp, sizeof buf);
+    if ( rc < 0 )
+        goto bad;
+
+    len = le32_to_cpu(buf[0]);
+    levdatum->isalias = le32_to_cpu(buf[1]);
+
+    key = xmalloc_array(char, len + 1);
+    if ( !key )
+    {
+        rc = -ENOMEM;
+        goto bad;
+    }
+    rc = next_entry(key, fp, len);
+    if ( rc < 0 )
+        goto bad;
+    key[len] = 0;
+
+    levdatum->level = xmalloc(struct mls_level);
+    if ( !levdatum->level )
+    {
+        rc = -ENOMEM;
+        goto bad;
+    }
+    if ( mls_read_level(levdatum->level, fp) )
+    {
+        rc = -EINVAL;
+        goto bad;
+    }
+
+    rc = hashtab_insert(h, key, levdatum);
+    if ( rc )
+        goto bad;
+out:
+    return rc;
+bad:
+    sens_destroy(key, levdatum, NULL);
+    goto out;
+}
+
+static int cat_read(struct policydb *p, struct hashtab *h, void *fp)
+{
+    char *key = NULL;
+    struct cat_datum *catdatum;
+    int rc;
+    __le32 buf[3];
+    u32 len;
+
+    catdatum = xmalloc(struct cat_datum);
+    if ( !catdatum )
+    {
+        rc = -ENOMEM;
+        goto out;
+    }
+    memset(catdatum, 0, sizeof(*catdatum));
+
+    rc = next_entry(buf, fp, sizeof buf);
+    if ( rc < 0 )
+        goto bad;
+
+    len = le32_to_cpu(buf[0]);
+    catdatum->value = le32_to_cpu(buf[1]);
+    catdatum->isalias = le32_to_cpu(buf[2]);
+
+    key = xmalloc_array(char, len + 1);
+    if ( !key )
+    {
+        rc = -ENOMEM;
+        goto bad;
+    }
+    rc = next_entry(key, fp, len);
+    if ( rc < 0 )
+        goto bad;
+    key[len] = 0;
+
+    rc = hashtab_insert(h, key, catdatum);
+    if ( rc )
+        goto bad;
+out:
+    return rc;
+
+bad:
+    cat_destroy(key, catdatum, NULL);
+    goto out;
+}
+
+static int (*read_f[SYM_NUM]) (struct policydb *p, struct hashtab *h, void *fp) =
+{
+    common_read,
+    class_read,
+    role_read,
+    type_read,
+    user_read,
+    cond_read_bool,
+    sens_read,
+    cat_read,
+};
+
+extern int ss_initialized;
+
+/*
+ * Read the configuration data from a policy database binary
+ * representation file into a policy database structure.
+ */
+int policydb_read(struct policydb *p, void *fp)
+{
+    struct role_allow *ra, *lra;
+    struct role_trans *tr, *ltr;
+    struct ocontext *l, *c /*, *newc*/;
+    int i, j, rc;
+    __le32 buf[8];
+    u32 len, /*len2,*/ config, nprim, nel /*, nel2*/;
+    char *policydb_str;
+    struct policydb_compat_info *info;
+    struct range_trans *rt, *lrt;
+
+    config = 0;
+    rc = policydb_init(p);
+    if ( rc )
+        goto out;
+
+    /* Read the magic number and string length. */
+    rc = next_entry(buf, fp, sizeof(u32)* 2);
+    if ( rc < 0 )
+        goto bad;
+
+    if ( le32_to_cpu(buf[0]) != POLICYDB_MAGIC )
+    {
+        printk(KERN_ERR "security:  policydb magic number 0x%x does "
+               "not match expected magic number 0x%x\n",
+               le32_to_cpu(buf[0]), POLICYDB_MAGIC);
+        goto bad;
+    }
+
+    len = le32_to_cpu(buf[1]);
+    if ( len != strlen(POLICYDB_STRING) )
+    {
+        printk(KERN_ERR "security:  policydb string length %d does not "
+               "match expected length %Zu\n",
+               len, (u32) strlen(POLICYDB_STRING));
+        goto bad;
+    }
+    policydb_str = xmalloc_array(char, len + 1);
+    if ( !policydb_str )
+    {
+        printk(KERN_ERR "security:  unable to allocate memory for policydb "
+               "string of length %d\n", len);
+        rc = -ENOMEM;
+        goto bad;
+    }
+    rc = next_entry(policydb_str, fp, len);
+    if ( rc < 0 )
+    {
+        printk(KERN_ERR "security:  truncated policydb string identifier\n");
+        xfree(policydb_str);
+        goto bad;
+    }
+    policydb_str[len] = 0;
+    if ( strcmp(policydb_str, POLICYDB_STRING) )
+    {
+        printk(KERN_ERR "security:  policydb string %s does not match "
+               "my string %s\n", policydb_str, POLICYDB_STRING);
+        xfree(policydb_str);
+        goto bad;
+    }
+    /* Done with policydb_str. */
+    xfree(policydb_str);
+    policydb_str = NULL;
+
+    /* Read the version, config, and table sizes. */
+    rc = next_entry(buf, fp, sizeof(u32)*4);
+    if ( rc < 0 )
+        goto bad;
+
+    p->policyvers = le32_to_cpu(buf[0]);
+    if ( p->policyvers < POLICYDB_VERSION_MIN ||
+                                        p->policyvers > POLICYDB_VERSION_MAX )
+    {
+            printk(KERN_ERR "security:  policydb version %d does not match "
+                   "my version range %d-%d\n",
+                   le32_to_cpu(buf[0]), POLICYDB_VERSION_MIN, POLICYDB_VERSION_MAX);
+            goto bad;
+    }
+
+    if ( (le32_to_cpu(buf[1]) & POLICYDB_CONFIG_MLS) )
+    {
+        if ( ss_initialized && !flask_mls_enabled )
+        {
+            printk(KERN_ERR "Cannot switch between non-MLS and MLS "
+                   "policies\n");
+            goto bad;
+        }
+        flask_mls_enabled = 1;
+        config |= POLICYDB_CONFIG_MLS;
+
+        if ( p->policyvers < POLICYDB_VERSION_MLS )
+        {
+            printk(KERN_ERR "security policydb version %d (MLS) "
+                   "not backwards compatible\n", p->policyvers);
+            goto bad;
+        }
+    }
+    else
+    {
+        if ( ss_initialized && flask_mls_enabled )
+        {
+            printk(KERN_ERR "Cannot switch between MLS and non-MLS "
+                   "policies\n");
+            goto bad;
+        }
+    }
+
+    info = policydb_lookup_compat(p->policyvers);
+    if ( !info )
+    {
+        printk(KERN_ERR "security:  unable to find policy compat info "
+               "for version %d\n", p->policyvers);
+        goto bad;
+    }
+
+    if ( le32_to_cpu(buf[2]) != info->sym_num ||
+                                        le32_to_cpu(buf[3]) != info->ocon_num )
+    {
+        printk(KERN_ERR "security:  policydb table sizes (%d,%d) do "
+               "not match mine (%d,%d)\n", le32_to_cpu(buf[2]),
+            le32_to_cpu(buf[3]),
+               info->sym_num, info->ocon_num);
+        goto bad;
+    }
+
+    for ( i = 0; i < info->sym_num; i++ )
+    {
+        rc = next_entry(buf, fp, sizeof(u32)*2);
+        if ( rc < 0 )
+            goto bad;
+        nprim = le32_to_cpu(buf[0]);
+        nel = le32_to_cpu(buf[1]);
+        for ( j = 0; j < nel; j++ )
+        {
+            rc = read_f[i](p, p->symtab[i].table, fp);
+            if ( rc )
+                goto bad;
+        }
+
+        p->symtab[i].nprim = nprim;
+    }
+
+    rc = avtab_read(&p->te_avtab, fp, p->policyvers);
+    if ( rc )
+        goto bad;
+
+    if ( p->policyvers >= POLICYDB_VERSION_BOOL )
+    {
+        rc = cond_read_list(p, fp);
+        if ( rc )
+            goto bad;
+    }
+
+    rc = next_entry(buf, fp, sizeof(u32));
+    if ( rc < 0 )
+        goto bad;
+    nel = le32_to_cpu(buf[0]);
+    ltr = NULL;
+    for ( i = 0; i < nel; i++ )
+    {
+        tr = xmalloc(struct role_trans);
+        if ( !tr )
+        {
+            rc = -ENOMEM;
+            goto bad;
+        }
+        memset(tr, 0, sizeof(*tr));
+        if ( ltr )
+            ltr->next = tr;
+        else
+            p->role_tr = tr;
+        rc = next_entry(buf, fp, sizeof(u32)*3);
+        if ( rc < 0 )
+            goto bad;
+        tr->role = le32_to_cpu(buf[0]);
+        tr->type = le32_to_cpu(buf[1]);
+        tr->new_role = le32_to_cpu(buf[2]);
+        ltr = tr;
+    }
+
+    rc = next_entry(buf, fp, sizeof(u32));
+    if ( rc < 0 )
+        goto bad;
+    nel = le32_to_cpu(buf[0]);
+    lra = NULL;
+    for ( i = 0; i < nel; i++ )
+    {
+        ra = xmalloc(struct role_allow);
+        if ( !ra )
+        {
+            rc = -ENOMEM;
+            goto bad;
+        }
+        memset(ra, 0, sizeof(*ra));
+        if ( lra )
+            lra->next = ra;
+        else
+            p->role_allow = ra;
+        rc = next_entry(buf, fp, sizeof(u32)*2);
+        if ( rc < 0 )
+            goto bad;
+        ra->role = le32_to_cpu(buf[0]);
+        ra->new_role = le32_to_cpu(buf[1]);
+        lra = ra;
+    }
+
+    rc = policydb_index_classes(p);
+    if ( rc )
+        goto bad;
+
+    rc = policydb_index_others(p);
+    if ( rc )
+        goto bad;
+
+    for ( i = 0; i < info->ocon_num; i++ )
+    {
+        rc = next_entry(buf, fp, sizeof(u32));
+        if ( rc < 0 )
+            goto bad;
+        nel = le32_to_cpu(buf[0]);
+        l = NULL;
+        for ( j = 0; j < nel; j++ )
+        {
+            c = xmalloc(struct ocontext);
+            if ( !c )
+            {
+                rc = -ENOMEM;
+                goto bad;
+            }
+            memset(c, 0, sizeof(*c));
+            if ( l )
+                l->next = c;
+            else
+                p->ocontexts[i] = c;
+            l = c;
+            rc = -EINVAL;
+            switch ( i )
+            {
+                case OCON_ISID:
+                    rc = next_entry(buf, fp, sizeof(u32));
+                    if ( rc < 0 )
+                        goto bad;
+                    c->sid[0] = le32_to_cpu(buf[0]);
+                    rc = context_read_and_validate(&c->context[0], p, fp);
+                    if ( rc )
+                        goto bad;
+                break;
+            }
+        }
+    }
+
+    rc = next_entry(buf, fp, sizeof(u32));
+    if ( rc < 0 )
+        goto bad;
+    nel = le32_to_cpu(buf[0]);
+
+    if ( p->policyvers >= POLICYDB_VERSION_MLS )
+    {
+        rc = next_entry(buf, fp, sizeof(u32));
+        if ( rc < 0 )
+            goto bad;
+        nel = le32_to_cpu(buf[0]);
+        lrt = NULL;
+        for ( i = 0; i < nel; i++ )
+        {
+            rt = xmalloc(struct range_trans);
+            if ( !rt )
+            {
+                rc = -ENOMEM;
+                goto bad;
+            }
+            memset(rt, 0, sizeof(*rt));
+            if ( lrt )
+                lrt->next = rt;
+            else
+                p->range_tr = rt;
+            rc = next_entry(buf, fp, (sizeof(u32) * 2));
+            if ( rc < 0 )
+                goto bad;
+            rt->dom = le32_to_cpu(buf[0]);
+            rt->type = le32_to_cpu(buf[1]);
+            rc = mls_read_range_helper(&rt->range, fp);
+            if ( rc )
+                goto bad;
+            lrt = rt;
+        }
+    }
+
+    p->type_attr_map = xmalloc_array(struct ebitmap, p->p_types.nprim);
+    if ( !p->type_attr_map )
+        goto bad;
+
+    for ( i = 0; i < p->p_types.nprim; i++ )
+    {
+        ebitmap_init(&p->type_attr_map[i]);
+        if ( p->policyvers >= POLICYDB_VERSION_AVTAB )
+        {
+            if ( ebitmap_read(&p->type_attr_map[i], fp) )
+                goto bad;
+        }
+        /* add the type itself as the degenerate case */
+        if ( ebitmap_set_bit(&p->type_attr_map[i], i, 1) )
+                goto bad;
+    }
+
+    rc = 0;
+out:
+    return rc;
+bad:
+    if ( !rc )
+        rc = -EINVAL;
+    policydb_destroy(p);
+    goto out;
+}
diff -r cb2ecf48cf80 -r 8ae246493872 xen/xsm/flask/ss/policydb.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/ss/policydb.h	Mon Jun 04 11:06:52 2007 -0400
@@ -0,0 +1,257 @@
+/*
+ * A policy database (policydb) specifies the
+ * configuration data for the security policy.
+ *
+ * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
+ */
+
+/*
+ * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
+ *
+ *    Support for enhanced MLS infrastructure.
+ *
+ * Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com>
+ *
+ *     Added conditional policy language extensions
+ *
+ * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
+ * Copyright (C) 2003 - 2004 Tresys Technology, LLC
+ *    This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation, version 2.
+ */
+
+/* Ported to Xen 3.0, George Coker, <gscoker@alpha.ncsc.mil> */
+
+#ifndef _SS_POLICYDB_H_
+#define _SS_POLICYDB_H_
+
+#include "symtab.h"
+#include "avtab.h"
+#include "sidtab.h"
+#include "context.h"
+#include "constraint.h"
+
+/*
+ * A datum type is defined for each kind of symbol
+ * in the configuration data:  individual permissions,
+ * common prefixes for access vectors, classes,
+ * users, roles, types, sensitivities, categories, etc.
+ */
+
+/* Permission attributes */
+struct perm_datum {
+    u32 value;        /* permission bit + 1 */
+};
+
+/* Attributes of a common prefix for access vectors */
+struct common_datum {
+    u32 value;            /* internal common value */
+    struct symtab permissions;    /* common permissions */
+};
+
+/* Class attributes */
+struct class_datum {
+    u32 value;            /* class value */
+    char *comkey;            /* common name */
+    struct common_datum *comdatum;    /* common datum */
+    struct symtab permissions;    /* class-specific permission symbol table */
+    struct constraint_node *constraints;    /* constraints on class permissions */
+    struct constraint_node *validatetrans;    /* special transition rules */
+};
+
+/* Role attributes */
+struct role_datum {
+    u32 value;            /* internal role value */
+    struct ebitmap dominates;    /* set of roles dominated by this role */
+    struct ebitmap types;        /* set of authorized types for role */
+};
+
+struct role_trans {
+    u32 role;        /* current role */
+    u32 type;        /* program executable type */
+    u32 new_role;        /* new role */
+    struct role_trans *next;
+};
+
+struct role_allow {
+    u32 role;        /* current role */
+    u32 new_role;        /* new role */
+    struct role_allow *next;
+};
+
+/* Type attributes */
+struct type_datum {
+    u32 value;        /* internal type value */
+    unsigned char primary;    /* primary name? */
+};
+
+/* User attributes */
+struct user_datum {
+    u32 value;            /* internal user value */
+    struct ebitmap roles;        /* set of authorized roles for user */
+    struct mls_range range;        /* MLS range (min - max) for user */
+    struct mls_level dfltlevel;    /* default login MLS level for user */
+};
+
+
+/* Sensitivity attributes */
+struct level_datum {
+    struct mls_level *level;    /* sensitivity and associated categories */
+    unsigned char isalias;    /* is this sensitivity an alias for another? */
+};
+
+/* Category attributes */
+struct cat_datum {
+    u32 value;        /* internal category bit + 1 */
+    unsigned char isalias;  /* is this category an alias for another? */
+};
+
+struct range_trans {
+    u32 dom;            /* current process domain */
+    u32 type;            /* program executable type */
+    struct mls_range range;        /* new range */
+    struct range_trans *next;
+};
+
+/* Boolean data type */
+struct cond_bool_datum {
+    __u32 value;        /* internal type value */
+    int state;
+};
+
+struct cond_node;
+
+/*
+ * The configuration data includes security contexts for
+ * initial SIDs, unlabeled file systems, TCP and UDP port numbers,
+ * network interfaces, and nodes.  This structure stores the
+ * relevant data for one such entry.  Entries of the same kind
+ * (e.g. all initial SIDs) are linked together into a list.
+ */
+struct ocontext {
+    union {
+        char *name;    /* name of initial SID, fs, netif, fstype, path */
+        int pirq;
+        int virq;
+        int vcpu;
+        u32 ioport;
+        unsigned long iomem;
+    } u;
+    struct context context[2];    /* security context(s) */
+    u32 sid[2];    /* SID(s) */
+    struct ocontext *next;
+};
+
+/* symbol table array indices */
+#define SYM_COMMONS 0
+#define SYM_CLASSES 1
+#define SYM_ROLES   2
+#define SYM_TYPES   3
+#define SYM_USERS   4
+#define SYM_BOOLS   5
+#define SYM_LEVELS  6
+#define SYM_CATS    7
+#define SYM_NUM     8
+
+/* object context array indices */
+#define OCON_ISID    0    /* initial SIDs */
+#define OCON_PIRQ    1    /* physical irqs */
+#define OCON_VIRQ    2    /* virtual irqs */
+#define OCON_VCPU    3    /* virtual cpus */
+#define OCON_IOPORT  4    /* io ports */
+#define OCON_IOMEM   5    /* io memory */
+#define OCON_DUMMY   6
+#define OCON_NUM     7
+
+/* The policy database */
+struct policydb {
+    /* symbol tables */
+    struct symtab symtab[SYM_NUM];
+#define p_commons symtab[SYM_COMMONS]
+#define p_classes symtab[SYM_CLASSES]
+#define p_roles symtab[SYM_ROLES]
+#define p_types symtab[SYM_TYPES]
+#define p_users symtab[SYM_USERS]
+#define p_bools symtab[SYM_BOOLS]
+#define p_levels symtab[SYM_LEVELS]
+#define p_cats symtab[SYM_CATS]
+
+    /* symbol names indexed by (value - 1) */
+    char **sym_val_to_name[SYM_NUM];
+#define p_common_val_to_name sym_val_to_name[SYM_COMMONS]
+#define p_class_val_to_name sym_val_to_name[SYM_CLASSES]
+#define p_role_val_to_name sym_val_to_name[SYM_ROLES]
+#define p_type_val_to_name sym_val_to_name[SYM_TYPES]
+#define p_user_val_to_name sym_val_to_name[SYM_USERS]
+#define p_bool_val_to_name sym_val_to_name[SYM_BOOLS]
+#define p_sens_val_to_name sym_val_to_name[SYM_LEVELS]
+#define p_cat_val_to_name sym_val_to_name[SYM_CATS]
+
+    /* class, role, and user attributes indexed by (value - 1) */
+    struct class_datum **class_val_to_struct;
+    struct role_datum **role_val_to_struct;
+    struct user_datum **user_val_to_struct;
+
+    /* type enforcement access vectors and transitions */
+    struct avtab te_avtab;
+
+    /* role transitions */
+    struct role_trans *role_tr;
+
+    /* bools indexed by (value - 1) */
+    struct cond_bool_datum **bool_val_to_struct;
+    /* type enforcement conditional access vectors and transitions */
+    struct avtab te_cond_avtab;
+    /* linked list indexing te_cond_avtab by conditional */
+    struct cond_node* cond_list;
+
+    /* role allows */
+    struct role_allow *role_allow;
+
+    /* security contexts of initial SIDs, unlabeled file systems,
+       TCP or UDP port numbers, network interfaces and nodes */
+    struct ocontext *ocontexts[OCON_NUM];
+
+    /* range transitions */
+    struct range_trans *range_tr;
+
+    /* type -> attribute reverse mapping */
+    struct ebitmap *type_attr_map;
+
+    unsigned int policyvers;
+};
+
+extern void policydb_destroy(struct policydb *p);
+extern int policydb_load_isids(struct policydb *p, struct sidtab *s);
+extern int policydb_context_isvalid(struct policydb *p, struct context *c);
+extern int policydb_read(struct policydb *p, void *fp);
+
+#define PERM_SYMTAB_SIZE 32
+
+#define POLICYDB_CONFIG_MLS    1
+
+#define OBJECT_R "object_r"
+#define OBJECT_R_VAL 1
+
+#define POLICYDB_MAGIC FLASK_MAGIC
+#define POLICYDB_STRING "SE Linux"
+
+struct policy_file {
+    char *data;
+    size_t len;
+};
+
+static inline int next_entry(void *buf, struct policy_file *fp, size_t bytes)
+{
+    if ( bytes > fp->len )
+        return -EINVAL;
+
+    memcpy(buf, fp->data, bytes);
+    fp->data += bytes;
+    fp->len -= bytes;
+    return 0;
+}
+
+#endif    /* _SS_POLICYDB_H_ */
+
diff -r cb2ecf48cf80 -r 8ae246493872 xen/xsm/flask/ss/services.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/ss/services.c	Mon Jun 04 11:06:52 2007 -0400
@@ -0,0 +1,1657 @@
+/*
+ * Implementation of the security services.
+ *
+ * Authors : Stephen Smalley, <sds@epoch.ncsc.mil>
+ *           James Morris <jmorris@redhat.com>
+ *
+ * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
+ *
+ *    Support for enhanced MLS infrastructure.
+ *
+ * Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com>
+ *
+ *     Added conditional policy language extensions
+ *
+ * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
+ * Copyright (C) 2003 - 2004 Tresys Technology, LLC
+ * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com>
+ *    This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation, version 2.
+ */
+
+/* Ported to Xen 3.0, George Coker, <gscoker@alpha.ncsc.mil> */
+
+#include <xen/lib.h>
+#include <xen/xmalloc.h>
+#include <xen/string.h>
+#include <xen/spinlock.h>
+#include <xen/errno.h>
+#include "flask.h"
+#include "avc.h"
+#include "avc_ss.h"
+#include "security.h"
+#include "context.h"
+#include "policydb.h"
+#include "sidtab.h"
+#include "services.h"
+#include "conditional.h"
+#include "mls.h"
+
+unsigned int policydb_loaded_version;
+
+static DEFINE_RWLOCK(policy_rwlock);
+#define POLICY_RDLOCK read_lock(&policy_rwlock)
+#define POLICY_WRLOCK write_lock_irq(&policy_rwlock)
+#define POLICY_RDUNLOCK read_unlock(&policy_rwlock)
+#define POLICY_WRUNLOCK write_unlock_irq(&policy_rwlock)
+
+static DEFINE_SPINLOCK(load_sem);
+#define LOAD_LOCK spin_lock(&load_sem)
+#define LOAD_UNLOCK spin_unlock(&load_sem)
+
+static struct sidtab sidtab;
+struct policydb policydb;
+int ss_initialized = 0;
+
+/*
+ * The largest sequence number that has been used when
+ * providing an access decision to the access vector cache.
+ * The sequence number only changes when a policy change
+ * occurs.
+ */
+static u32 latest_granting = 0;
+
+/* Forward declaration. */
+static int context_struct_to_string(struct context *context, char **scontext,
+                                                            u32 *scontext_len);
+
+/*
+ * Return the boolean value of a constraint expression
+ * when it is applied to the specified source and target
+ * security contexts.
+ *
+ * xcontext is a special beast...  It is used by the validatetrans rules
+ * only.  For these rules, scontext is the context before the transition,
+ * tcontext is the context after the transition, and xcontext is the context
+ * of the process performing the transition.  All other callers of
+ * constraint_expr_eval should pass in NULL for xcontext.
+ */
+static int constraint_expr_eval(struct context *scontext,
+                            struct context *tcontext, struct context *xcontext, 
+                                                struct constraint_expr *cexpr)
+{
+    u32 val1, val2;
+    struct context *c;
+    struct role_datum *r1, *r2;
+    struct mls_level *l1, *l2;
+    struct constraint_expr *e;
+    int s[CEXPR_MAXDEPTH];
+    int sp = -1;
+
+    for ( e = cexpr; e; e = e->next )
+    {
+        switch ( e->expr_type )
+        {
+            case CEXPR_NOT:
+                BUG_ON(sp < 0);
+                s[sp] = !s[sp];
+            break;
+            case CEXPR_AND:
+                BUG_ON(sp < 1);
+                sp--;
+                s[sp] &= s[sp+1];
+            break;
+            case CEXPR_OR:
+                BUG_ON(sp < 1);
+                sp--;
+                s[sp] |= s[sp+1];
+            break;
+            case CEXPR_ATTR:
+                if ( sp == (CEXPR_MAXDEPTH-1) )
+                    return 0;
+            switch ( e->attr )
+            {
+                case CEXPR_USER:
+                    val1 = scontext->user;
+                    val2 = tcontext->user;
+                    break;
+                case CEXPR_TYPE:
+                    val1 = scontext->type;
+                    val2 = tcontext->type;
+                    break;
+                case CEXPR_ROLE:
+                    val1 = scontext->role;
+                    val2 = tcontext->role;
+                    r1 = policydb.role_val_to_struct[val1 - 1];
+                    r2 = policydb.role_val_to_struct[val2 - 1];
+                switch ( e->op )
+                {
+                    case CEXPR_DOM:
+                        s[++sp] = ebitmap_get_bit(&r1->dominates, val2 - 1);
+                    continue;
+                    case CEXPR_DOMBY:
+                        s[++sp] = ebitmap_get_bit(&r2->dominates, val1 - 1);
+                    continue;
+                    case CEXPR_INCOMP:
+                        s[++sp] = ( !ebitmap_get_bit(&r1->dominates,
+                                         val2 - 1) &&
+                                !ebitmap_get_bit(&r2->dominates,
+                                         val1 - 1) );
+                    continue;
+                    default:
+                    break;
+                }
+                break;
+                case CEXPR_L1L2:
+                    l1 = &(scontext->range.level[0]);
+                    l2 = &(tcontext->range.level[0]);
+                    goto mls_ops;
+                case CEXPR_L1H2:
+                    l1 = &(scontext->range.level[0]);
+                    l2 = &(tcontext->range.level[1]);
+                    goto mls_ops;
+                case CEXPR_H1L2:
+                    l1 = &(scontext->range.level[1]);
+                    l2 = &(tcontext->range.level[0]);
+                    goto mls_ops;
+                case CEXPR_H1H2:
+                    l1 = &(scontext->range.level[1]);
+                    l2 = &(tcontext->range.level[1]);
+                    goto mls_ops;
+                case CEXPR_L1H1:
+                    l1 = &(scontext->range.level[0]);
+                    l2 = &(scontext->range.level[1]);
+                    goto mls_ops;
+                case CEXPR_L2H2:
+                    l1 = &(tcontext->range.level[0]);
+                    l2 = &(tcontext->range.level[1]);
+                    goto mls_ops;
+mls_ops:
+            switch ( e->op )
+            {
+                case CEXPR_EQ:
+                    s[++sp] = mls_level_eq(l1, l2);
+                continue;
+                case CEXPR_NEQ:
+                    s[++sp] = !mls_level_eq(l1, l2);
+                continue;
+                case CEXPR_DOM:
+                    s[++sp] = mls_level_dom(l1, l2);
+                continue;
+                case CEXPR_DOMBY:
+                    s[++sp] = mls_level_dom(l2, l1);
+                continue;
+                case CEXPR_INCOMP:
+                    s[++sp] = mls_level_incomp(l2, l1);
+                continue;
+                default:
+                    BUG();
+                    return 0;
+            }
+            break;
+            default:
+                BUG();
+                return 0;
+            }
+
+            switch ( e->op )
+            {
+                case CEXPR_EQ:
+                    s[++sp] = (val1 == val2);
+                break;
+                case CEXPR_NEQ:
+                    s[++sp] = (val1 != val2);
+                break;
+                default:
+                    BUG();
+                    return 0;
+            }
+            break;
+            case CEXPR_NAMES:
+                if ( sp == (CEXPR_MAXDEPTH-1) )
+                    return 0;
+                c = scontext;
+                if ( e->attr & CEXPR_TARGET )
+                    c = tcontext;
+                else if ( e->attr & CEXPR_XTARGET )
+                {
+                    c = xcontext;
+                    if ( !c )
+                    {
+                        BUG();
+                        return 0;
+                    }
+                }
+                if ( e->attr & CEXPR_USER )
+                    val1 = c->user;
+                else if ( e->attr & CEXPR_ROLE )
+                    val1 = c->role;
+                else if ( e->attr & CEXPR_TYPE )
+                    val1 = c->type;
+                else
+                {
+                    BUG();
+                    return 0;
+                }
+
+            switch ( e->op )
+            {
+                case CEXPR_EQ:
+                    s[++sp] = ebitmap_get_bit(&e->names, val1 - 1);
+                break;
+                case CEXPR_NEQ:
+                    s[++sp] = !ebitmap_get_bit(&e->names, val1 - 1);
+                break;
+                default:
+                    BUG();
+                    return 0;
+            }
+            break;
+            default:
+                BUG();
+                return 0;
+        }
+    }
+
+    BUG_ON(sp != 0);
+    return s[0];
+}
+
+/*
+ * Compute access vectors based on a context structure pair for
+ * the permissions in a particular class.
+ */
+static int context_struct_compute_av(struct context *scontext,
+                            struct context *tcontext, u16 tclass, u32 requested, 
+                                                        struct av_decision *avd)
+{
+    struct constraint_node *constraint;
+    struct role_allow *ra;
+    struct avtab_key avkey;
+    struct avtab_node *node;
+    struct class_datum *tclass_datum;
+    struct ebitmap *sattr, *tattr;
+    struct ebitmap_node *snode, *tnode;
+    unsigned int i, j;
+
+    if ( !tclass || tclass > policydb.p_classes.nprim )
+    {
+        printk(KERN_ERR "security_compute_av:  unrecognized class %d\n",
+               tclass);
+        return -EINVAL;
+    }
+    tclass_datum = policydb.class_val_to_struct[tclass - 1];
+
+    /*
+     * Initialize the access vectors to the default values.
+     */
+    avd->allowed = 0;
+    avd->decided = 0xffffffff;
+    avd->auditallow = 0;
+    avd->auditdeny = 0xffffffff;
+    avd->seqno = latest_granting;
+
+    /*
+     * If a specific type enforcement rule was defined for
+     * this permission check, then use it.
+     */
+    avkey.target_class = tclass;
+    avkey.specified = AVTAB_AV;
+    sattr = &policydb.type_attr_map[scontext->type - 1];
+    tattr = &policydb.type_attr_map[tcontext->type - 1];
+    ebitmap_for_each_bit(sattr, snode, i)
+    {
+        if ( !ebitmap_node_get_bit(snode, i) )
+            continue;
+        ebitmap_for_each_bit(tattr, tnode, j)
+        {
+            if ( !ebitmap_node_get_bit(tnode, j) )
+                continue;
+            avkey.source_type = i + 1;
+            avkey.target_type = j + 1;
+            for ( node = avtab_search_node(&policydb.te_avtab, &avkey);
+                 node != NULL;
+                 node = avtab_search_node_next(node, avkey.specified) )
+            {
+                if ( node->key.specified == AVTAB_ALLOWED )
+                    avd->allowed |= node->datum.data;
+                else if ( node->key.specified == AVTAB_AUDITALLOW )
+                    avd->auditallow |= node->datum.data;
+                else if ( node->key.specified == AVTAB_AUDITDENY )
+                    avd->auditdeny &= node->datum.data;
+            }
+
+            /* Check conditional av table for additional permissions */
+            cond_compute_av(&policydb.te_cond_avtab, &avkey, avd);
+
+        }
+    }
+
+    /*
+     * Remove any permissions prohibited by a constraint (this includes
+     * the MLS policy).
+     */
+    constraint = tclass_datum->constraints;
+    while ( constraint )
+    {
+        if ( (constraint->permissions & (avd->allowed) ) &&
+            !constraint_expr_eval(scontext, tcontext, NULL, constraint->expr))
+        {
+            avd->allowed = (avd->allowed) & ~(constraint->permissions);
+        }
+        constraint = constraint->next;
+    }
+
+    /*
+     * If checking process transition permission and the
+     * role is changing, then check the (current_role, new_role)
+     * pair.
+     */
+    if ( tclass == SECCLASS_DOMAIN &&
+/* removed until future dynamic domain capability
+        (avd->allowed & (DOMAIN__TRANSITION | DOMAIN__DYNTRANSITION)) &&
+*/
+                                            scontext->role != tcontext->role )
+        {
+        for ( ra = policydb.role_allow; ra; ra = ra->next )
+        {
+            if ( scontext->role == ra->role && tcontext->role == ra->new_role )
+                break;
+        }
+/* removed until future dynamic domain capability    
+        if (!ra)
+            avd->allowed = (avd->allowed) & ~(DOMAIN__TRANSITION |
+                                            DOMAIN__DYNTRANSITION);
+*/
+    }
+
+    return 0;
+}
+
+static int security_validtrans_handle_fail(struct context *ocontext,
+                struct context *ncontext, struct context *tcontext, u16 tclass)
+{
+    char *o = NULL, *n = NULL, *t = NULL;
+    u32 olen, nlen, tlen;
+
+    if ( context_struct_to_string(ocontext, &o, &olen) < 0 )
+        goto out;
+    if ( context_struct_to_string(ncontext, &n, &nlen) < 0 )
+        goto out;
+    if ( context_struct_to_string(tcontext, &t, &tlen) < 0 )
+        goto out;
+    printk("security_validate_transition:  denied for"
+              " oldcontext=%s newcontext=%s taskcontext=%s tclass=%s",
+              o, n, t, policydb.p_class_val_to_name[tclass-1]);
+out:
+    xfree(o);
+    xfree(n);
+    xfree(t);
+
+    if ( !flask_enforcing )
+        return 0;
+    return -EPERM;
+}
+
+int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid,
+                                 u16 tclass)
+{
+    struct context *ocontext;
+    struct context *ncontext;
+    struct context *tcontext;
+    struct class_datum *tclass_datum;
+    struct constraint_node *constraint;
+    int rc = 0;
+
+    if ( !ss_initialized )
+        return 0;
+
+    POLICY_RDLOCK;
+
+    if ( !tclass || tclass > policydb.p_classes.nprim )
+    {
+        printk(KERN_ERR "security_validate_transition: "
+                                            "unrecognized class %d\n", tclass);
+        rc = -EINVAL;
+        goto out;
+    }
+    tclass_datum = policydb.class_val_to_struct[tclass - 1];
+
+    ocontext = sidtab_search(&sidtab, oldsid);
+    if ( !ocontext )
+    {
+        printk(KERN_ERR "security_validate_transition: "
+               " unrecognized SID %d\n", oldsid);
+        rc = -EINVAL;
+        goto out;
+    }
+
+    ncontext = sidtab_search(&sidtab, newsid);
+    if ( !ncontext )
+    {
+        printk(KERN_ERR "security_validate_transition: "
+               " unrecognized SID %d\n", newsid);
+        rc = -EINVAL;
+        goto out;
+    }
+
+    tcontext = sidtab_search(&sidtab, tasksid);
+    if ( !tcontext )
+    {
+        printk(KERN_ERR "security_validate_transition: "
+               " unrecognized SID %d\n", tasksid);
+        rc = -EINVAL;
+        goto out;
+    }
+
+    constraint = tclass_datum->validatetrans;
+    while ( constraint )
+    {
+        if ( !constraint_expr_eval(ocontext, ncontext, tcontext,
+                                                            constraint->expr) )
+        {
+            rc = security_validtrans_handle_fail(ocontext, ncontext,
+                                                 tcontext, tclass);
+            goto out;
+        }
+        constraint = constraint->next;
+    }
+
+out:
+    POLICY_RDUNLOCK;
+    return rc;
+}
+
+/**
+ * security_compute_av - Compute access vector decisions.
+ * @ssid: source security identifier
+ * @tsid: target security identifier
+ * @tclass: target security class
+ * @requested: requested permissions
+ * @avd: access vector decisions
+ *
+ * Compute a set of access vector decisions based on the
+ * SID pair (@ssid, @tsid) for the permissions in @tclass.
+ * Return -%EINVAL if any of the parameters are invalid or %0
+ * if the access vector decisions were computed successfully.
+ */
+int security_compute_av(u32 ssid, u32 tsid, u16 tclass, u32 requested,
+                                                    struct av_decision *avd)
+{
+    struct context *scontext = NULL, *tcontext = NULL;
+    int rc = 0;
+
+    if ( !ss_initialized )
+    {
+        avd->allowed = 0xffffffff;
+        avd->decided = 0xffffffff;
+        avd->auditallow = 0;
+        avd->auditdeny = 0xffffffff;
+        avd->seqno = latest_granting;
+        return 0;
+    }
+
+    POLICY_RDLOCK;
+
+    scontext = sidtab_search(&sidtab, ssid);
+    if ( !scontext )
+    {
+        printk("security_compute_av:  unrecognized SID %d\n", ssid);
+        rc = -EINVAL;
+        goto out;
+    }
+    tcontext = sidtab_search(&sidtab, tsid);
+    if ( !tcontext )
+    {
+        printk("security_compute_av:  unrecognized SID %d\n", tsid);
+        rc = -EINVAL;
+        goto out;
+    }
+
+    rc = context_struct_compute_av(scontext, tcontext, tclass, requested, avd);
+out:
+    POLICY_RDUNLOCK;
+    return rc;
+}
+
+/*
+ * Write the security context string representation of
+ * the context structure `context' into a dynamically
+ * allocated string of the correct size.  Set `*scontext'
+ * to point to this string and set `*scontext_len' to
+ * the length of the string.
+ */
+static int context_struct_to_string(struct context *context, char **scontext, u32 *scontext_len)
+{
+    char *scontextp;
+
+    *scontext = NULL;
+    *scontext_len = 0;
+
+    /* Compute the size of the context. */
+    *scontext_len += strlen(policydb.p_user_val_to_name[context->user - 1]) + 1;
+    *scontext_len += strlen(policydb.p_role_val_to_name[context->role - 1]) + 1;
+    *scontext_len += strlen(policydb.p_type_val_to_name[context->type - 1]) + 1;
+    *scontext_len += mls_compute_context_len(context);
+
+    /* Allocate space for the context; caller must free this space. */
+    scontextp = xmalloc_array(char, *scontext_len);
+    if ( !scontextp )
+        return -ENOMEM;
+
+    *scontext = scontextp;
+
+    /*
+     * Copy the user name, role name and type name into the context.
+     */
+    snprintf(scontextp, *scontext_len, "%s:%s:%s",
+        policydb.p_user_val_to_name[context->user - 1],
+        policydb.p_role_val_to_name[context->role - 1],
+        policydb.p_type_val_to_name[context->type - 1]);
+    scontextp += strlen(policydb.p_user_val_to_name[context->user - 1]) +
+                 1 + strlen(policydb.p_role_val_to_name[context->role - 1]) +
+                 1 + strlen(policydb.p_type_val_to_name[context->type - 1]);
+
+    mls_sid_to_context(context, &scontextp);
+
+    *scontextp = 0;
+
+    return 0;
+}
+
+#include "initial_sid_to_string.h"
+
+/**
+ * security_sid_to_context - Obtain a context for a given SID.
+ * @sid: security identifier, SID
+ * @scontext: security context
+ * @scontext_len: length in bytes
+ *
+ * Write the string representation of the context associated with @sid
+ * into a dynamically allocated string of the correct size.  Set @scontext
+ * to point to this string and set @scontext_len to the length of the string.
+ */
+int security_sid_to_context(u32 sid, char **scontext, u32 *scontext_len)
+{
+    struct context *context;
+    int rc = 0;
+
+    if ( !ss_initialized )
+    {
+        if ( sid <= SECINITSID_NUM )
+        {
+            char *scontextp;
+
+            *scontext_len = strlen(initial_sid_to_string[sid]) + 1;
+            scontextp = xmalloc_array(char, *scontext_len);
+            strlcpy(scontextp, initial_sid_to_string[sid], *scontext_len);
+            *scontext = scontextp;
+            goto out;
+        }
+        printk(KERN_ERR "security_sid_to_context:  called before initial "
+               "load_policy on unknown SID %d\n", sid);
+        rc = -EINVAL;
+        goto out;
+    }
+    POLICY_RDLOCK;
+    context = sidtab_search(&sidtab, sid);
+    if ( !context )
+    {
+        printk(KERN_ERR "security_sid_to_context:  unrecognized SID "
+               "%d\n", sid);
+        rc = -EINVAL;
+        goto out_unlock;
+    }
+    rc = context_struct_to_string(context, scontext, scontext_len);
+out_unlock:
+    POLICY_RDUNLOCK;
+out:
+    return rc;
+
+}
+
+static int security_context_to_sid_core(char *scontext, u32 scontext_len, u32 *sid, u32 def_sid)
+{
+    char *scontext2;
+    struct context context;
+    struct role_datum *role;
+    struct type_datum *typdatum;
+    struct user_datum *usrdatum;
+    char *scontextp, *p, oldc;
+    int rc = 0;
+
+    if ( !ss_initialized )
+    {
+        int i;
+
+        for ( i = 1; i < SECINITSID_NUM; i++ )
+        {
+            if ( !strcmp(initial_sid_to_string[i], scontext) )
+            {
+                *sid = i;
+                goto out;
+            }
+        }
+        *sid = SECINITSID_XEN;
+        goto out;
+    }
+    *sid = SECSID_NULL;
+
+    /* Copy the string so that we can modify the copy as we parse it.
+       The string should already by null terminated, but we append a
+       null suffix to the copy to avoid problems with the existing
+       attr package, which doesn't view the null terminator as part
+       of the attribute value. */
+    scontext2 = xmalloc_array(char, scontext_len+1);
+    if ( !scontext2 )
+    {
+        rc = -ENOMEM;
+        goto out;
+    }
+    memcpy(scontext2, scontext, scontext_len);
+    scontext2[scontext_len] = 0;
+
+    context_init(&context);
+    *sid = SECSID_NULL;
+
+    POLICY_RDLOCK;
+
+    /* Parse the security context. */
+
+    rc = -EINVAL;
+    scontextp = (char *) scontext2;
+
+    /* Extract the user. */
+    p = scontextp;
+    while ( *p && *p != ':' )
+        p++;
+
+    if (*p == 0)
+        goto out_unlock;
+
+    *p++ = 0;
+
+    usrdatum = hashtab_search(policydb.p_users.table, scontextp);
+    if ( !usrdatum )
+        goto out_unlock;
+
+    context.user = usrdatum->value;
+
+    /* Extract role. */
+    scontextp = p;
+    while ( *p && *p != ':' )
+        p++;
+
+    if ( *p == 0 )
+        goto out_unlock;
+
+    *p++ = 0;
+
+    role = hashtab_search(policydb.p_roles.table, scontextp);
+    if ( !role )
+        goto out_unlock;
+    context.role = role->value;
+
+    /* Extract type. */
+    scontextp = p;
+    while ( *p && *p != ':' )
+        p++;
+    oldc = *p;
+    *p++ = 0;
+
+    typdatum = hashtab_search(policydb.p_types.table, scontextp);
+    if ( !typdatum )
+        goto out_unlock;
+
+    context.type = typdatum->value;
+
+    rc = mls_context_to_sid(oldc, &p, &context, &sidtab, def_sid);
+    if ( rc )
+        goto out_unlock;
+
+    if ( (p - scontext2) < scontext_len )
+    {
+        rc = -EINVAL;
+        goto out_unlock;
+    }
+
+    /* Check the validity of the new context. */
+    if ( !policydb_context_isvalid(&policydb, &context) )
+    {
+        rc = -EINVAL;
+        goto out_unlock;
+    }
+    /* Obtain the new sid. */
+    rc = sidtab_context_to_sid(&sidtab, &context, sid);
+out_unlock:
+    POLICY_RDUNLOCK;
+    context_destroy(&context);
+    xfree(scontext2);
+out:
+    return rc;
+}
+
+/**
+ * security_context_to_sid - Obtain a SID for a given security context.
+ * @scontext: security context
+ * @scontext_len: length in bytes
+ * @sid: security identifier, SID
+ *
+ * Obtains a SID associated with the security context that
+ * has the string representation specified by @scontext.
+ * Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient
+ * memory is available, or 0 on success.
+ */
+int security_context_to_sid(char *scontext, u32 scontext_len, u32 *sid)
+{
+    return security_context_to_sid_core(scontext, scontext_len,
+                                                            sid, SECSID_NULL);
+}
+
+/**
+ * security_context_to_sid_default - Obtain a SID for a given security context,
+ * falling back to specified default if needed.
+ *
+ * @scontext: security context
+ * @scontext_len: length in bytes
+ * @sid: security identifier, SID
+ * @def_sid: default SID to assign on errror
+ *
+ * Obtains a SID associated with the security context that
+ * has the string representation specified by @scontext.
+ * The default SID is passed to the MLS layer to be used to allow
+ * kernel labeling of the MLS field if the MLS field is not present
+ * (for upgrading to MLS without full relabel).
+ * Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient
+ * memory is available, or 0 on success.
+ */
+int security_context_to_sid_default(char *scontext, u32 scontext_len, u32 *sid, u32 def_sid)
+{
+    return security_context_to_sid_core(scontext, scontext_len, sid, def_sid);
+}
+
+static int compute_sid_handle_invalid_context(
+                struct context *scontext, struct context *tcontext, u16 tclass,
+                                                    struct context *newcontext)
+{
+    char *s = NULL, *t = NULL, *n = NULL;
+    u32 slen, tlen, nlen;
+
+    if ( context_struct_to_string(scontext, &s, &slen) < 0 )
+        goto out;
+    if ( context_struct_to_string(tcontext, &t, &tlen) < 0 )
+        goto out;
+    if ( context_struct_to_string(newcontext, &n, &nlen) < 0 )
+        goto out;
+    printk("security_compute_sid:  invalid context %s"
+          " for scontext=%s"
+          " tcontext=%s"
+          " tclass=%s",
+          n, s, t, policydb.p_class_val_to_name[tclass-1]);
+out:
+    xfree(s);
+    xfree(t);
+    xfree(n);
+    if ( !flask_enforcing )
+        return 0;
+    return -EACCES;
+}
+
+static int security_compute_sid(u32 ssid,
+                u32 tsid,
+                u16 tclass,
+                u32 specified,
+                u32 *out_sid)
+{
+    struct context *scontext = NULL, *tcontext = NULL, newcontext;
+    struct role_trans *roletr = NULL;
+    struct avtab_key avkey;
+    struct avtab_datum *avdatum;
+    struct avtab_node *node;
+    int rc = 0;
+
+    if ( !ss_initialized )
+    {
+        switch ( tclass )
+        {
+            case SECCLASS_DOMAIN:
+                *out_sid = ssid;
+            break;
+            default:
+                *out_sid = tsid;
+            break;
+        }
+        goto out;
+    }
+
+    POLICY_RDLOCK;
+
+    scontext = sidtab_search(&sidtab, ssid);
+    if ( !scontext )
+    {
+        printk(KERN_ERR "security_compute_sid:  unrecognized SID %d\n", ssid);
+        rc = -EINVAL;
+        goto out_unlock;
+    }
+    tcontext = sidtab_search(&sidtab, tsid);
+    if ( !tcontext )
+    {
+        printk(KERN_ERR "security_compute_sid:  unrecognized SID %d\n", tsid);
+        rc = -EINVAL;
+        goto out_unlock;
+    }
+
+    context_init(&newcontext);
+
+    /* Set the user identity. */
+    switch ( specified )
+    {
+        case AVTAB_TRANSITION:
+        case AVTAB_CHANGE:
+            /* Use the process user identity. */
+            newcontext.user = scontext->user;
+        break;
+        case AVTAB_MEMBER:
+            /* Use the related object owner. */
+            newcontext.user = tcontext->user;
+        break;
+    }
+
+    /* Set the role and type to default values. */
+    switch ( tclass )
+    {
+        case SECCLASS_DOMAIN:
+            /* Use the current role and type of process. */
+            newcontext.role = scontext->role;
+            newcontext.type = scontext->type;
+        break;
+        default:
+            /* Use the well-defined object role. */
+            newcontext.role = OBJECT_R_VAL;
+            /* Use the type of the related object. */
+            newcontext.type = tcontext->type;
+    }
+
+    /* Look for a type transition/member/change rule. */
+    avkey.source_type = scontext->type;
+    avkey.target_type = tcontext->type;
+    avkey.target_class = tclass;
+    avkey.specified = specified;
+    avdatum = avtab_search(&policydb.te_avtab, &avkey);
+
+    /* If no permanent rule, also check for enabled conditional rules */
+    if ( !avdatum )
+    {
+        node = avtab_search_node(&policydb.te_cond_avtab, &avkey);
+        for ( ; node != NULL; node = avtab_search_node_next(node, specified) )
+        {
+            if ( node->key.specified & AVTAB_ENABLED )
+            {
+                avdatum = &node->datum;
+                break;
+            }
+        }
+    }
+
+    if ( avdatum )
+    {
+        /* Use the type from the type transition/member/change rule. */
+        newcontext.type = avdatum->data;
+    }
+
+    /* Check for class-specific changes. */
+    switch ( tclass )
+    {
+        case SECCLASS_DOMAIN:
+            if ( specified & AVTAB_TRANSITION )
+            {
+                /* Look for a role transition rule. */
+                for ( roletr = policydb.role_tr; roletr; roletr = roletr->next )
+                {
+                    if ( roletr->role == scontext->role && 
+                                            roletr->type == tcontext->type )
+                    {
+                        /* Use the role transition rule. */
+                        newcontext.role = roletr->new_role;
+                        break;
+                    }
+                }
+            }
+        break;
+        default:
+        break;
+    }
+
+    /* Set the MLS attributes.
+       This is done last because it may allocate memory. */
+    rc = mls_compute_sid(scontext, tcontext, tclass, specified, &newcontext);
+    if ( rc )
+        goto out_unlock;
+
+    /* Check the validity of the context. */
+    if ( !policydb_context_isvalid(&policydb, &newcontext) )
+    {
+        rc = compute_sid_handle_invalid_context(scontext, tcontext, tclass,
+                                                                &newcontext);
+        if ( rc )
+            goto out_unlock;
+    }
+    /* Obtain the sid for the context. */
+    rc = sidtab_context_to_sid(&sidtab, &newcontext, out_sid);
+out_unlock:
+    POLICY_RDUNLOCK;
+    context_destroy(&newcontext);
+out:
+    return rc;
+}
+
+/**
+ * security_transition_sid - Compute the SID for a new subject/object.
+ * @ssid: source security identifier
+ * @tsid: target security identifier
+ * @tclass: target security class
+ * @out_sid: security identifier for new subject/object
+ *
+ * Compute a SID to use for labeling a new subject or object in the
+ * class @tclass based on a SID pair (@ssid, @tsid).
+ * Return -%EINVAL if any of the parameters are invalid, -%ENOMEM
+ * if insufficient memory is available, or %0 if the new SID was
+ * computed successfully.
+ */
+int security_transition_sid(u32 ssid, u32 tsid, u16 tclass, u32 *out_sid)
+{
+    return security_compute_sid(ssid, tsid, tclass, AVTAB_TRANSITION, out_sid);
+}
+
+/**
+ * security_member_sid - Compute the SID for member selection.
+ * @ssid: source security identifier
+ * @tsid: target security identifier
+ * @tclass: target security class
+ * @out_sid: security identifier for selected member
+ *
+ * Compute a SID to use when selecting a member of a polyinstantiated
+ * object of class @tclass based on a SID pair (@ssid, @tsid).
+ * Return -%EINVAL if any of the parameters are invalid, -%ENOMEM
+ * if insufficient memory is available, or %0 if the SID was
+ * computed successfully.
+ */
+int security_member_sid(u32 ssid, u32 tsid, u16 tclass, u32 *out_sid)
+{
+    return security_compute_sid(ssid, tsid, tclass, AVTAB_MEMBER, out_sid);
+}
+
+/**
+ * security_change_sid - Compute the SID for object relabeling.
+ * @ssid: source security identifier
+ * @tsid: target security identifier
+ * @tclass: target security class
+ * @out_sid: security identifier for selected member
+ *
+ * Compute a SID to use for relabeling an object of class @tclass
+ * based on a SID pair (@ssid, @tsid).
+ * Return -%EINVAL if any of the parameters are invalid, -%ENOMEM
+ * if insufficient memory is available, or %0 if the SID was
+ * computed successfully.
+ */
+int security_change_sid(u32 ssid, u32 tsid, u16 tclass, u32 *out_sid)
+{
+    return security_compute_sid(ssid, tsid, tclass, AVTAB_CHANGE, out_sid);
+}
+
+/*
+ * Verify that each permission that is defined under the
+ * existing policy is still defined with the same value
+ * in the new policy.
+ */
+static int validate_perm(void *key, void *datum, void *p)
+{
+    struct hashtab *h;
+    struct perm_datum *perdatum, *perdatum2;
+    int rc = 0;
+
+    h = p;
+    perdatum = datum;
+
+    perdatum2 = hashtab_search(h, key);
+    if ( !perdatum2 )
+    {
+        printk(KERN_ERR "security:  permission %s disappeared", (char *)key);
+        rc = -ENOENT;
+        goto out;
+    }
+    if ( perdatum->value != perdatum2->value )
+    {
+        printk(KERN_ERR "security:  the value of permission %s changed",
+                                                                (char *)key);
+        rc = -EINVAL;
+    }
+out:
+    return rc;
+}
+
+/*
+ * Verify that each class that is defined under the
+ * existing policy is still defined with the same
+ * attributes in the new policy.
+ */
+static int validate_class(void *key, void *datum, void *p)
+{
+    struct policydb *newp;
+    struct class_datum *cladatum, *cladatum2;
+    int rc;
+
+    newp = p;
+    cladatum = datum;
+
+    cladatum2 = hashtab_search(newp->p_classes.table, key);
+    if ( !cladatum2 )
+    {
+        printk(KERN_ERR "security:  class %s disappeared\n", (char *)key);
+        rc = -ENOENT;
+        goto out;
+    }
+    if (cladatum->value != cladatum2->value) {
+        printk(KERN_ERR "security:  the value of class %s changed\n",
+                                                                (char *)key);
+        rc = -EINVAL;
+        goto out;
+    }
+    if ( (cladatum->comdatum && !cladatum2->comdatum) ||
+                                (!cladatum->comdatum && cladatum2->comdatum) )
+    {
+        printk(KERN_ERR "security:  the inherits clause for the access "
+               "vector definition for class %s changed\n", (char *)key);
+        rc = -EINVAL;
+        goto out;
+    }
+    if ( cladatum->comdatum )
+    {
+        rc = hashtab_map(cladatum->comdatum->permissions.table, validate_perm,
+                                     cladatum2->comdatum->permissions.table);
+        if ( rc )
+        {
+            printk(" in the access vector definition for class %s\n", 
+                                                                (char *)key);
+            goto out;
+        }
+    }
+    rc = hashtab_map(cladatum->permissions.table, validate_perm,
+                                                cladatum2->permissions.table);
+    if ( rc )
+        printk(" in access vector definition for class %s\n", (char *)key);
+out:
+    return rc;
+}
+
+/* Clone the SID into the new SID table. */
+static int clone_sid(u32 sid, struct context *context, void *arg)
+{
+    struct sidtab *s = arg;
+
+    return sidtab_insert(s, sid, context);
+}
+
+static inline int convert_context_handle_invalid_context(struct context *context)
+{
+    int rc = 0;
+
+    if ( flask_enforcing )
+        rc = -EINVAL;
+    else
+    {
+        char *s;
+        u32 len;
+
+        context_struct_to_string(context, &s, &len);
+        printk(KERN_ERR "security:  context %s is invalid\n", s);
+        xfree(s);
+    }
+    return rc;
+}
+
+struct convert_context_args {
+    struct policydb *oldp;
+    struct policydb *newp;
+};
+
+/*
+ * Convert the values in the security context
+ * structure `c' from the values specified
+ * in the policy `p->oldp' to the values specified
+ * in the policy `p->newp'.  Verify that the
+ * context is valid under the new policy.
+ */
+static int convert_context(u32 key, struct context *c, void *p)
+{
+    struct convert_context_args *args;
+    struct context oldc;
+    struct role_datum *role;
+    struct type_datum *typdatum;
+    struct user_datum *usrdatum;
+    char *s;
+    u32 len;
+    int rc;
+
+    args = p;
+
+    rc = context_cpy(&oldc, c);
+    if ( rc )
+        goto out;
+
+    rc = -EINVAL;
+
+    /* Convert the user. */
+    usrdatum = hashtab_search(args->newp->p_users.table,
+                              args->oldp->p_user_val_to_name[c->user - 1]);
+    if ( !usrdatum )
+        goto bad;
+
+    c->user = usrdatum->value;
+
+    /* Convert the role. */
+    role = hashtab_search(args->newp->p_roles.table,
+                          args->oldp->p_role_val_to_name[c->role - 1]);
+    if ( !role )
+        goto bad;
+
+    c->role = role->value;
+
+    /* Convert the type. */
+    typdatum = hashtab_search(args->newp->p_types.table,
+                              args->oldp->p_type_val_to_name[c->type - 1]);
+    if ( !typdatum )
+        goto bad;
+
+    c->type = typdatum->value;
+
+    rc = mls_convert_context(args->oldp, args->newp, c);
+    if ( rc )
+        goto bad;
+
+    /* Check the validity of the new context. */
+    if ( !policydb_context_isvalid(args->newp, c) )
+    {
+        rc = convert_context_handle_invalid_context(&oldc);
+        if ( rc )
+            goto bad;
+    }
+
+    context_destroy(&oldc);
+out:
+    return rc;
+bad:
+    context_struct_to_string(&oldc, &s, &len);
+    context_destroy(&oldc);
+    printk(KERN_ERR "security:  invalidating context %s\n", s);
+    xfree(s);
+    goto out;
+}
+
+extern void flask_complete_init(void);
+
+/**
+ * security_load_policy - Load a security policy configuration.
+ * @data: binary policy data
+ * @len: length of data in bytes
+ *
+ * Load a new set of security policy configuration data,
+ * validate it and convert the SID table as necessary.
+ * This function will flush the access vector cache after
+ * loading the new policy.
+ */
+int security_load_policy(void *data, size_t len)
+{
+    struct policydb oldpolicydb, newpolicydb;
+    struct sidtab oldsidtab, newsidtab;
+    struct convert_context_args args;
+    u32 seqno;
+    int rc = 0;
+    struct policy_file file = { data, len }, *fp = &file;
+
+    LOAD_LOCK;
+
+    if ( !ss_initialized )
+    {
+        if ( policydb_read(&policydb, fp) )
+        {
+            LOAD_UNLOCK;
+            return -EINVAL;
+        }
+        if ( policydb_load_isids(&policydb, &sidtab) )
+        {
+            LOAD_UNLOCK;
+            policydb_destroy(&policydb);
+            return -EINVAL;
+        }
+        policydb_loaded_version = policydb.policyvers;
+        ss_initialized = 1;
+        seqno = ++latest_granting;
+        LOAD_UNLOCK;
+        avc_ss_reset(seqno);
+        return 0;
+    }
+
+#if 0
+    sidtab_hash_eval(&sidtab, "sids");
+#endif
+
+    if ( policydb_read(&newpolicydb, fp) )
+    {
+        LOAD_UNLOCK;
+        return -EINVAL;
+    }
+
+    sidtab_init(&newsidtab);
+
+    /* Verify that the existing classes did not change. */
+    if ( hashtab_map(policydb.p_classes.table, validate_class, &newpolicydb) )
+    {
+        printk(KERN_ERR "security:  the definition of an existing "
+                                                            "class changed\n");
+        rc = -EINVAL;
+        goto err;
+    }
+
+    /* Clone the SID table. */
+    sidtab_shutdown(&sidtab);
+    if ( sidtab_map(&sidtab, clone_sid, &newsidtab) )
+    {
+        rc = -ENOMEM;
+        goto err;
+    }
+
+    /* Convert the internal representations of contexts
+       in the new SID table and remove invalid SIDs. */
+    args.oldp = &policydb;
+    args.newp = &newpolicydb;
+    sidtab_map_remove_on_error(&newsidtab, convert_context, &args);
+
+    /* Save the old policydb and SID table to free later. */
+    memcpy(&oldpolicydb, &policydb, sizeof policydb);
+    sidtab_set(&oldsidtab, &sidtab);
+
+    /* Install the new policydb and SID table. */
+    POLICY_WRLOCK;
+    memcpy(&policydb, &newpolicydb, sizeof policydb);
+    sidtab_set(&sidtab, &newsidtab);
+    seqno = ++latest_granting;
+    policydb_loaded_version = policydb.policyvers;
+    POLICY_WRUNLOCK;
+    LOAD_UNLOCK;
+
+    /* Free the old policydb and SID table. */
+    policydb_destroy(&oldpolicydb);
+    sidtab_destroy(&oldsidtab);
+
+    avc_ss_reset(seqno);
+
+    return 0;
+
+err:
+    LOAD_UNLOCK;
+    sidtab_destroy(&newsidtab);
+    policydb_destroy(&newpolicydb);
+    return rc;
+
+}
+
+/**
+ * security_pirq_sid - Obtain the SID for a physical irq.
+ * @pirq: physical irq
+ * @out_sid: security identifier
+ */
+int security_pirq_sid(int pirq, u32 *out_sid)
+{
+    int rc = 0;
+    struct ocontext *c;
+
+    POLICY_RDLOCK;
+
+    c = policydb.ocontexts[OCON_PIRQ];
+    
+    while ( c )
+    {
+        if ( c->u.pirq == pirq )
+            break;
+        c = c->next;
+    }
+
+    if ( c )
+    {
+        if ( !c->sid[0] )
+        {
+            rc = sidtab_context_to_sid(&sidtab, &c->context[0], &c->sid[0]);
+            if ( rc )
+                goto out;
+        }
+        *out_sid = c->sid[0];
+    }
+    else
+    {
+        *out_sid = SECINITSID_PIRQ;
+    }
+
+out:
+    POLICY_RDUNLOCK;
+    return rc;
+}
+
+/**
+ * security_iomem_sid - Obtain the SID for a page of iomem.
+ * @mfn: iomem mfn
+ * @out_sid: security identifier
+ */
+int security_iomem_sid(unsigned long mfn, u32 *out_sid)
+{
+    struct ocontext *c;
+    int rc = 0;
+
+    POLICY_RDLOCK;
+
+    c = policydb.ocontexts[OCON_IOMEM];
+    while ( c )
+    {
+        if ( c->u.iomem == mfn )
+            break;
+        c = c->next;
+    }
+
+    if ( c )
+    {
+        if ( !c->sid[0] )
+        {
+            rc = sidtab_context_to_sid(&sidtab, &c->context[0], &c->sid[0]);
+            if ( rc )
+                goto out;
+        }
+        *out_sid = c->sid[0];
+    }
+    else
+    {
+        *out_sid = SECINITSID_IOMEM;
+    }
+
+out:
+    POLICY_RDUNLOCK;
+    return rc;
+}
+
+/**
+ * security_ioport_sid - Obtain the SID for an ioport.
+ * @ioport: ioport
+ * @out_sid: security identifier
+ */
+int security_ioport_sid(u32 ioport, u32 *out_sid)
+{
+    struct ocontext *c;
+    int rc = 0;
+
+    POLICY_RDLOCK;
+
+    c = policydb.ocontexts[OCON_IOPORT];
+    while ( c )
+    {
+        if ( c->u.ioport == ioport )
+            break;
+        c = c->next;
+    }
+
+    if ( c )
+    {
+        if ( !c->sid[0] )
+        {
+            rc = sidtab_context_to_sid(&sidtab, &c->context[0], &c->sid[0]);
+            if ( rc )
+                goto out;
+        }
+        *out_sid = c->sid[0];
+    }
+    else
+    {
+        *out_sid = SECINITSID_IOPORT;
+    }
+
+out:
+    POLICY_RDUNLOCK;
+    return rc;
+}
+
+#define SIDS_NEL 25
+
+/**
+ * security_get_user_sids - Obtain reachable SIDs for a user.
+ * @fromsid: starting SID
+ * @username: username
+ * @sids: array of reachable SIDs for user
+ * @nel: number of elements in @sids
+ *
+ * Generate the set of SIDs for legal security contexts
+ * for a given user that can be reached by @fromsid.
+ * Set *@sids to point to a dynamically allocated
+ * array containing the set of SIDs.  Set *@nel to the
+ * number of elements in the array.
+ */
+
+int security_get_user_sids(u32 fromsid, char *username, u32 **sids, u32 *nel)
+{
+    struct context *fromcon, usercon;
+    u32 *mysids, *mysids2, sid;
+    u32 mynel = 0, maxnel = SIDS_NEL;
+    struct user_datum *user;
+    struct role_datum *role;
+    struct av_decision avd;
+    struct ebitmap_node *rnode, *tnode;
+    int rc = 0, i, j;
+
+    if ( !ss_initialized )
+    {
+        *sids = NULL;
+        *nel = 0;
+        goto out;
+    }
+
+    POLICY_RDLOCK;
+
+    fromcon = sidtab_search(&sidtab, fromsid);
+    if ( !fromcon )
+    {
+        rc = -EINVAL;
+        goto out_unlock;
+    }
+
+    user = hashtab_search(policydb.p_users.table, username);
+    if ( !user )
+    {
+        rc = -EINVAL;
+        goto out_unlock;
+    }
+    usercon.user = user->value;
+
+    mysids = xmalloc_array(u32, maxnel);
+    if ( !mysids )
+    {
+        rc = -ENOMEM;
+        goto out_unlock;
+    }
+    memset(mysids, 0, maxnel*sizeof(*mysids));
+
+    ebitmap_for_each_bit(&user->roles, rnode, i)
+    {
+        if ( !ebitmap_node_get_bit(rnode, i) )
+            continue;
+        role = policydb.role_val_to_struct[i];
+        usercon.role = i+1;
+        ebitmap_for_each_bit(&role->types, tnode, j) {
+            if ( !ebitmap_node_get_bit(tnode, j) )
+                continue;
+            usercon.type = j+1;
+
+            if ( mls_setup_user_range(fromcon, user, &usercon) )
+                continue;
+
+            rc = context_struct_compute_av(fromcon, &usercon,
+                               SECCLASS_DOMAIN,
+                               DOMAIN__TRANSITION,
+                               &avd);
+            if ( rc ||  !(avd.allowed & DOMAIN__TRANSITION) )
+                continue;
+            rc = sidtab_context_to_sid(&sidtab, &usercon, &sid);
+            if ( rc )
+            {
+                xfree(mysids);
+                goto out_unlock;
+            }
+            if ( mynel < maxnel )
+            {
+                mysids[mynel++] = sid;
+            }
+            else
+            {
+                maxnel += SIDS_NEL;
+                mysids2 = xmalloc_array(u32, maxnel);
+                if ( !mysids2 )
+                {
+                    rc = -ENOMEM;
+                    xfree(mysids);
+                    goto out_unlock;
+                }
+                memset(mysids2, 0, maxnel*sizeof(*mysids2));
+                memcpy(mysids2, mysids, mynel * sizeof(*mysids2));
+                xfree(mysids);
+                mysids = mysids2;
+                mysids[mynel++] = sid;
+            }
+        }
+    }
+
+    *sids = mysids;
+    *nel = mynel;
+
+out_unlock:
+    POLICY_RDUNLOCK;
+out:
+    return rc;
+}
+
+int security_get_bools(int *len, char ***names, int **values)
+{
+    int i, rc = -ENOMEM;
+
+    POLICY_RDLOCK;
+    *names = NULL;
+    *values = NULL;
+
+    *len = policydb.p_bools.nprim;
+    if ( !*len )
+    {
+        rc = 0;
+        goto out;
+    }
+
+    *names = (char**)xmalloc_array(char*, *len);
+    if ( !*names )
+        goto err;
+    memset(*names, 0, sizeof(char*) * *len);
+
+    *values = (int*)xmalloc_array(int, *len);
+    if ( !*values )
+        goto err;
+
+    for ( i = 0; i < *len; i++ )
+    {
+        size_t name_len;
+        (*values)[i] = policydb.bool_val_to_struct[i]->state;
+        name_len = strlen(policydb.p_bool_val_to_name[i]) + 1;
+        (*names)[i] = (char*)xmalloc_array(char, name_len);
+        if ( !(*names)[i] )
+            goto err;
+        strlcpy((*names)[i], policydb.p_bool_val_to_name[i], name_len);
+        (*names)[i][name_len - 1] = 0;
+    }
+    rc = 0;
+out:
+    POLICY_RDUNLOCK;
+    return rc;
+err:
+    if ( *names )
+    {
+        for ( i = 0; i < *len; i++ )
+            xfree((*names)[i]);
+    }
+    xfree(*values);
+    goto out;
+}
+
+
+int security_set_bools(int len, int *values)
+{
+    int i, rc = 0;
+    int lenp, seqno = 0;
+    struct cond_node *cur;
+
+    POLICY_WRLOCK;
+
+    lenp = policydb.p_bools.nprim;
+    if ( len != lenp )
+    {
+        rc = -EFAULT;
+        goto out;
+    }
+
+    printk(KERN_INFO "security: committed booleans { ");
+    for ( i = 0; i < len; i++ )
+    {
+        if ( values[i] )
+        {
+            policydb.bool_val_to_struct[i]->state = 1;
+        }
+        else
+        {
+            policydb.bool_val_to_struct[i]->state = 0;
+        }
+        if ( i != 0 )
+            printk(", ");
+        printk("%s:%d", policydb.p_bool_val_to_name[i],
+               policydb.bool_val_to_struct[i]->state);
+    }
+    printk(" }\n");
+
+    for ( cur = policydb.cond_list; cur != NULL; cur = cur->next )
+    {
+        rc = evaluate_cond_node(&policydb, cur);
+        if ( rc )
+            goto out;
+    }
+
+    seqno = ++latest_granting;
+
+out:
+    POLICY_WRUNLOCK;
+    if ( !rc )
+    {
+        avc_ss_reset(seqno);
+    }
+    return rc;
+}
+
+int security_get_bool_value(int bool)
+{
+    int rc = 0;
+    int len;
+
+    POLICY_RDLOCK;
+
+    len = policydb.p_bools.nprim;
+    if ( bool >= len )
+    {
+        rc = -EFAULT;
+        goto out;
+    }
+
+    rc = policydb.bool_val_to_struct[bool]->state;
+out:
+    POLICY_RDUNLOCK;
+    return rc;
+}
diff -r cb2ecf48cf80 -r 8ae246493872 xen/xsm/flask/ss/services.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/ss/services.h	Mon Jun 04 11:06:52 2007 -0400
@@ -0,0 +1,15 @@
+/*
+ * Implementation of the security services.
+ *
+ * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
+ */
+#ifndef _SS_SERVICES_H_
+#define _SS_SERVICES_H_
+
+#include "policydb.h"
+#include "sidtab.h"
+
+extern struct policydb policydb;
+
+#endif    /* _SS_SERVICES_H_ */
+
diff -r cb2ecf48cf80 -r 8ae246493872 xen/xsm/flask/ss/sidtab.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/ss/sidtab.c	Mon Jun 04 11:06:52 2007 -0400
@@ -0,0 +1,327 @@
+/*
+ * Implementation of the SID table type.
+ *
+ * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
+ */
+ 
+/* Ported to Xen 3.0, George Coker, <gscoker@alpha.ncsc.mil> */
+ 
+#include <xen/lib.h>
+#include <xen/xmalloc.h>
+#include <xen/errno.h>
+#include <xen/spinlock.h>
+#include "flask.h"
+#include "security.h"
+#include "sidtab.h"
+
+#define SIDTAB_HASH(sid) (sid & SIDTAB_HASH_MASK)
+
+#define INIT_SIDTAB_LOCK(s) spin_lock_init(&s->lock)
+#define SIDTAB_LOCK(s, x) spin_lock_irqsave(&s->lock, x)
+#define SIDTAB_UNLOCK(s, x) spin_unlock_irqrestore(&s->lock, x)
+
+int sidtab_init(struct sidtab *s)
+{
+    int i;
+
+    s->htable = (void *)xmalloc_array(struct sidtab_node, SIDTAB_SIZE);
+    if ( !s->htable )
+        return -ENOMEM;
+    for ( i = 0; i < SIDTAB_SIZE; i++ )
+        s->htable[i] = NULL;
+    s->nel = 0;
+    s->next_sid = 1;
+    s->shutdown = 0;
+    INIT_SIDTAB_LOCK(s);
+    return 0;
+}
+
+int sidtab_insert(struct sidtab *s, u32 sid, struct context *context)
+{
+    int hvalue, rc = 0;
+    struct sidtab_node *prev, *cur, *newnode;
+
+    if ( !s )
+    {
+        rc = -ENOMEM;
+        goto out;
+    }
+
+    hvalue = SIDTAB_HASH(sid);
+    prev = NULL;
+    cur = s->htable[hvalue];
+    while ( cur != NULL && sid > cur->sid )
+    {
+        prev = cur;
+        cur = cur->next;
+    }
+
+    if ( cur && sid == cur->sid )
+    {
+        rc = -EEXIST;
+        goto out;
+    }
+
+    newnode = xmalloc(struct sidtab_node);
+    if ( newnode == NULL )
+    {
+        rc = -ENOMEM;
+        goto out;
+    }
+    newnode->sid = sid;
+    if ( context_cpy(&newnode->context, context) )
+    {
+        xfree(newnode);
+        rc = -ENOMEM;
+        goto out;
+    }
+
+    if ( prev )
+    {
+        newnode->next = prev->next;
+        wmb();
+        prev->next = newnode;
+    }
+    else
+    {
+        newnode->next = s->htable[hvalue];
+        wmb();
+        s->htable[hvalue] = newnode;
+    }
+
+    s->nel++;
+    if ( sid >= s->next_sid )
+        s->next_sid = sid + 1;
+out:
+    return rc;
+}
+
+struct context *sidtab_search(struct sidtab *s, u32 sid)
+{
+    int hvalue;
+    struct sidtab_node *cur;
+
+    if ( !s )
+        return NULL;
+
+    hvalue = SIDTAB_HASH(sid);
+    cur = s->htable[hvalue];
+    while ( cur != NULL && sid > cur->sid )
+        cur = cur->next;
+
+    if ( cur == NULL || sid != cur->sid )
+    {
+        /* Remap invalid SIDs to the unlabeled SID. */
+        sid = SECINITSID_UNLABELED;
+        hvalue = SIDTAB_HASH(sid);
+        cur = s->htable[hvalue];
+        while ( cur != NULL && sid > cur->sid )
+            cur = cur->next;
+        if ( !cur || sid != cur->sid )
+            return NULL;
+    }
+
+    return &cur->context;
+}
+
+int sidtab_map(struct sidtab *s, 
+        int (*apply) (u32 sid, struct context *context, void *args), void *args)
+{
+    int i, rc = 0;
+    struct sidtab_node *cur;
+
+    if ( !s )
+        goto out;
+
+    for ( i = 0; i < SIDTAB_SIZE; i++ )
+    {
+        cur = s->htable[i];
+        while ( cur != NULL )
+        {
+            rc = apply(cur->sid, &cur->context, args);
+            if ( rc )
+                goto out;
+            cur = cur->next;
+        }
+    }
+out:
+    return rc;
+}
+
+void sidtab_map_remove_on_error(struct sidtab *s,
+        int (*apply) (u32 sid, struct context *context, void *args), void *args)
+{
+    int i, ret;
+    struct sidtab_node *last, *cur, *temp;
+
+    if ( !s )
+        return;
+
+    for ( i = 0; i < SIDTAB_SIZE; i++ )
+    {
+        last = NULL;
+        cur = s->htable[i];
+        while ( cur != NULL )
+        {
+            ret = apply(cur->sid, &cur->context, args);
+            if ( ret )
+            {
+                if ( last )
+                {
+                    last->next = cur->next;
+                }
+                else
+                {
+                    s->htable[i] = cur->next;
+                }
+
+                temp = cur;
+                cur = cur->next;
+                context_destroy(&temp->context);
+                xfree(temp);
+                s->nel--;
+            }
+            else
+            {
+                last = cur;
+                cur = cur->next;
+            }
+        }
+    }
+
+    return;
+}
+
+static inline u32 sidtab_search_context(struct sidtab *s, 
+                                                        struct context *context)
+{
+    int i;
+    struct sidtab_node *cur;
+
+    for ( i = 0; i < SIDTAB_SIZE; i++ )
+    {
+        cur = s->htable[i];
+        while ( cur != NULL )
+        {
+            if ( context_cmp(&cur->context, context) )
+                return cur->sid;
+            cur = cur->next;
+        }
+    }
+    return 0;
+}
+
+int sidtab_context_to_sid(struct sidtab *s, struct context *context,
+                                                                u32 *out_sid)
+{
+    u32 sid;
+    int ret = 0;
+    unsigned long flags;
+
+    *out_sid = SECSID_NULL;
+
+    sid = sidtab_search_context(s, context);
+    if ( !sid )
+    {
+        SIDTAB_LOCK(s, flags);
+        /* Rescan now that we hold the lock. */
+        sid = sidtab_search_context(s, context);
+        if ( sid )
+            goto unlock_out;
+        /* No SID exists for the context.  Allocate a new one. */
+        if ( s->next_sid == UINT_MAX || s->shutdown )
+        {
+            ret = -ENOMEM;
+            goto unlock_out;
+        }
+        sid = s->next_sid++;
+        ret = sidtab_insert(s, sid, context);
+        if ( ret )
+            s->next_sid--;
+unlock_out:
+        SIDTAB_UNLOCK(s, flags);
+    }
+
+    if ( ret )
+        return ret;
+
+    *out_sid = sid;
+    return 0;
+}
+
+void sidtab_hash_eval(struct sidtab *h, char *tag)
+{
+    int i, chain_len, slots_used, max_chain_len;
+    struct sidtab_node *cur;
+
+    slots_used = 0;
+    max_chain_len = 0;
+    for ( i = 0; i < SIDTAB_SIZE; i++ )
+    {
+        cur = h->htable[i];
+        if ( cur )
+        {
+            slots_used++;
+            chain_len = 0;
+            while ( cur )
+            {
+                chain_len++;
+                cur = cur->next;
+            }
+
+            if ( chain_len > max_chain_len )
+                max_chain_len = chain_len;
+        }
+    }
+
+    printk(KERN_INFO "%s:  %d entries and %d/%d buckets used, longest "
+           "chain length %d\n", tag, h->nel, slots_used, SIDTAB_SIZE,
+           max_chain_len);
+}
+
+void sidtab_destroy(struct sidtab *s)
+{
+    int i;
+    struct sidtab_node *cur, *temp;
+
+    if ( !s )
+        return;
+
+    for ( i = 0; i < SIDTAB_SIZE; i++ )
+    {
+        cur = s->htable[i];
+        while ( cur != NULL )
+        {
+            temp = cur;
+            cur = cur->next;
+            context_destroy(&temp->context);
+            xfree(temp);
+        }
+        s->htable[i] = NULL;
+    }
+    xfree(s->htable);
+    s->htable = NULL;
+    s->nel = 0;
+    s->next_sid = 1;
+}
+
+void sidtab_set(struct sidtab *dst, struct sidtab *src)
+{
+    unsigned long flags;
+
+    SIDTAB_LOCK(src, flags);
+    dst->htable = src->htable;
+    dst->nel = src->nel;
+    dst->next_sid = src->next_sid;
+    dst->shutdown = 0;
+    SIDTAB_UNLOCK(src, flags);
+}
+
+void sidtab_shutdown(struct sidtab *s)
+{
+    unsigned long flags;
+
+    SIDTAB_LOCK(s, flags);
+    s->shutdown = 1;
+    SIDTAB_UNLOCK(s, flags);
+}
diff -r cb2ecf48cf80 -r 8ae246493872 xen/xsm/flask/ss/sidtab.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/ss/sidtab.h	Mon Jun 04 11:06:52 2007 -0400
@@ -0,0 +1,53 @@
+/*
+ * A security identifier table (sidtab) is a hash table
+ * of security context structures indexed by SID value.
+ *
+ * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
+ */
+
+/* Ported to Xen 3.0, George Coker, <gscoker@alpha.ncsc.mil> */
+
+#ifndef _SS_SIDTAB_H_
+#define _SS_SIDTAB_H_
+
+#include "context.h"
+#include <xen/spinlock.h>
+
+struct sidtab_node {
+    u32 sid;        /* security identifier */
+    struct context context;    /* security context structure */
+    struct sidtab_node *next;
+};
+
+#define SIDTAB_HASH_BITS 7
+#define SIDTAB_HASH_BUCKETS (1 << SIDTAB_HASH_BITS)
+#define SIDTAB_HASH_MASK (SIDTAB_HASH_BUCKETS-1)
+
+#define SIDTAB_SIZE SIDTAB_HASH_BUCKETS
+
+struct sidtab {
+    struct sidtab_node **htable;
+    unsigned int nel;    /* number of elements */
+    unsigned int next_sid;    /* next SID to allocate */
+    unsigned char shutdown;
+    spinlock_t lock;
+};
+
+int sidtab_init(struct sidtab *s);
+int sidtab_insert(struct sidtab *s, u32 sid, struct context *context);
+struct context *sidtab_search(struct sidtab *s, u32 sid);
+
+int sidtab_map(struct sidtab *s,
+    int (*apply) (u32 sid, struct context *context, void *args), void *args);
+
+void sidtab_map_remove_on_error(struct sidtab *s,
+    int (*apply) (u32 sid, struct context *context, void *args), void *args);
+
+int sidtab_context_to_sid(struct sidtab *s, struct context *context, u32 *sid);
+
+void sidtab_hash_eval(struct sidtab *h, char *tag);
+void sidtab_destroy(struct sidtab *s);
+void sidtab_set(struct sidtab *dst, struct sidtab *src);
+void sidtab_shutdown(struct sidtab *s);
+
+#endif    /* _SS_SIDTAB_H_ */
diff -r cb2ecf48cf80 -r 8ae246493872 xen/xsm/flask/ss/symtab.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/ss/symtab.c	Mon Jun 04 11:06:52 2007 -0400
@@ -0,0 +1,47 @@
+/*
+ * Implementation of the symbol table type.
+ *
+ * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
+ */
+
+/* Ported to Xen 3.0, George Coker, <gscoker@alpha.ncsc.mil> */
+
+#include <xen/lib.h>
+#include <xen/xmalloc.h>
+#include <xen/string.h>
+#include <xen/errno.h>
+#include "symtab.h"
+
+static unsigned int symhash(struct hashtab *h, void *key)
+{
+    char *p, *keyp;
+    unsigned int size;
+    unsigned int val;
+
+    val = 0;
+    keyp = key;
+    size = strlen(keyp);
+    for ( p = keyp; (p - keyp) < size; p++ )
+        val = (val << 4 | (val >> (8*sizeof(unsigned int)-4))) ^ (*p);
+    return val & (h->size - 1);
+}
+
+static int symcmp(struct hashtab *h, void *key1, void *key2)
+{
+    char *keyp1, *keyp2;
+
+    keyp1 = key1;
+    keyp2 = key2;
+    return strcmp(keyp1, keyp2);
+}
+
+
+int symtab_init(struct symtab *s, unsigned int size)
+{
+    s->table = hashtab_create(symhash, symcmp, size);
+    if ( !s->table )
+        return -1;
+    s->nprim = 0;
+    return 0;
+}
+
diff -r cb2ecf48cf80 -r 8ae246493872 xen/xsm/flask/ss/symtab.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/ss/symtab.h	Mon Jun 04 11:06:52 2007 -0400
@@ -0,0 +1,23 @@
+/*
+ * A symbol table (symtab) maintains associations between symbol
+ * strings and datum values.  The type of the datum values
+ * is arbitrary.  The symbol table type is implemented
+ * using the hash table type (hashtab).
+ *
+ * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
+ */
+#ifndef _SS_SYMTAB_H_
+#define _SS_SYMTAB_H_
+
+#include "hashtab.h"
+
+struct symtab {
+    struct hashtab *table;    /* hash table (keyed on a string) */
+    u32 nprim;        /* number of primary names in table */
+};
+
+int symtab_init(struct symtab *s, unsigned int size);
+
+#endif    /* _SS_SYMTAB_H_ */
+
+

[-- Attachment #3: Type: text/plain, Size: 138 bytes --]

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xensource.com
http://lists.xensource.com/xen-devel

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [Xense-devel][PATCH][2/4] Xen Securtiy Modules: FLASK
@ 2007-06-04 19:06 George S. Coker, II
  2007-06-14 18:14 ` George S. Coker, II
  0 siblings, 1 reply; 5+ messages in thread
From: George S. Coker, II @ 2007-06-04 19:06 UTC (permalink / raw)
  To: xen-devel, xense-devel

[-- Attachment #1: Type: text/plain, Size: 167 bytes --]

Updates in this patch set include:
    - coding style cleanups
    - track xsm changes
    - remove patch cruft

Signed-off-by: George Coker <gscoker@alpha.ncsc.mil>


[-- Attachment #2: flask-xsm-060407-xen-15200.diff --]
[-- Type: text/x-patch, Size: 82122 bytes --]

diff -r 8ae246493872 -r 12213351ff5d tools/Makefile
--- a/tools/Makefile	Mon Jun 04 11:06:52 2007 -0400
+++ b/tools/Makefile	Mon Jun 04 11:09:10 2007 -0400
@@ -3,6 +3,9 @@ include $(XEN_ROOT)/tools/Rules.mk
 
 SUBDIRS-y :=
 SUBDIRS-y += libxc
+ifeq ($(FLASK_ENABLE),y)
+SUBDIRS-y += flask
+endif
 SUBDIRS-y += xenstore
 SUBDIRS-y += misc
 SUBDIRS-y += examples
diff -r 8ae246493872 -r 12213351ff5d tools/flask/Makefile
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/flask/Makefile	Mon Jun 04 11:09:10 2007 -0400
@@ -0,0 +1,26 @@
+XEN_ROOT = ../..
+include $(XEN_ROOT)/tools/Rules.mk
+
+SUBDIRS :=
+SUBDIRS += libflask
+SUBDIRS += loadpolicy
+
+.PHONY: all
+all:
+	@set -e; for subdir in $(SUBDIRS); do \
+		$(MAKE) -C $$subdir $@; \
+	done
+
+.PHONY: install
+install:
+	@set -e; for subdir in $(SUBDIRS); do \
+		$(MAKE) -C $$subdir $@; \
+	done
+
+.PHONY: clean
+clean:
+	@set -e; for subdir in $(SUBDIRS); do \
+		$(MAKE) -C $$subdir $@; \
+	done
+
+
diff -r 8ae246493872 -r 12213351ff5d tools/flask/libflask/Makefile
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/flask/libflask/Makefile	Mon Jun 04 11:09:10 2007 -0400
@@ -0,0 +1,65 @@
+MAJOR    = 1.0
+MINOR    = 0
+
+XEN_ROOT = ../../..
+include $(XEN_ROOT)/tools/Rules.mk
+
+XEN_LIBXC = $(XEN_ROOT)/tools/libxc
+
+SRCS       :=
+SRCS       += flask_op.c
+
+CFLAGS   += -Werror
+CFLAGS   += -fno-strict-aliasing
+CFLAGS   += $(INCLUDES) -I./include -I$(XEN_LIBXC) 
+
+# Get gcc to generate the dependencies for us.
+CFLAGS   += -Wp,-MD,.$(@F).d
+LDFLAGS  += -L.
+DEPS     = .*.d
+
+LIB_OBJS := $(patsubst %.c,%.o,$(SRCS))
+PIC_OBJS := $(patsubst %.c,%.opic,$(SRCS))
+
+LIB := libflask.a
+LIB += libflask.so libflask.so.$(MAJOR) libflask.so.$(MAJOR).$(MINOR)
+
+.PHONY: all
+all: build
+
+.PHONY: build
+build:
+	$(MAKE) $(LIB)
+
+.PHONY: install
+install: build
+	[ -d $(DESTDIR)/usr/$(LIBDIR) ] || $(INSTALL_DIR) $(DESTDIR)/usr/$(LIBDIR)
+	[ -d $(DESTDIR)/usr/include ] || $(INSTALL_DIR) $(DESTDIR)/usr/include
+	$(INSTALL_PROG) libflask.so.$(MAJOR).$(MINOR) $(DESTDIR)/usr/$(LIBDIR)
+	$(INSTALL_DATA) libflask.a $(DESTDIR)/usr/$(LIBDIR)
+	ln -sf libflask.so.$(MAJOR).$(MINOR) $(DESTDIR)/usr/$(LIBDIR)/libflask.so.$(MAJOR)
+	ln -sf libflask.so.$(MAJOR) $(DESTDIR)/usr/$(LIBDIR)/libflask.so
+	$(INSTALL_DATA) include/flask_op.h $(DESTDIR)/usr/include
+
+.PHONY: TAGS
+TAGS:
+	etags -t *.c *.h
+
+.PHONY: clean
+clean:
+	rm -rf *.a *.so* *.o *.opic *.rpm $(LIB) *~ $(DEPS) xen
+
+# libflask
+
+libflask.a: $(LIB_OBJS)
+	$(AR) rc $@ $^
+
+libflask.so: libflask.so.$(MAJOR)
+	ln -sf $< $@
+libflask.so.$(MAJOR): libflask.so.$(MAJOR).$(MINOR)
+	ln -sf $< $@
+
+libflask.so.$(MAJOR).$(MINOR): $(PIC_OBJS)
+	$(CC) $(CFLAGS) $(LDFLAGS) -Wl,-soname -Wl,libflask.so.$(MAJOR) -shared -o $@ $^
+
+-include $(DEPS)
diff -r 8ae246493872 -r 12213351ff5d tools/flask/libflask/flask_op.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/flask/libflask/flask_op.c	Mon Jun 04 11:09:10 2007 -0400
@@ -0,0 +1,104 @@
+/*
+ *
+ *  Authors:  Michael LeMay, <mdlemay@epoch.ncsc.mil>
+ *            George Coker, <gscoker@alpha.ncsc.mil>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2,
+ *  as published by the Free Software Foundation.
+ */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+
+#include <xc_private.h>
+
+#include <flask_op.h>
+
+int flask_load(int xc_handle, char *buf, int size)
+{
+    int err;
+    int cmd;
+    flask_op_t op;
+    
+    cmd = FLASK_LOAD;
+    op.buf = buf;
+    op.size = size;
+    
+    if ( (err = do_flask_op(xc_handle, cmd, &op)) != 0 )
+        return err;
+
+    return 0;
+}
+
+int flask_context_to_sid(int xc_handle, char *buf, int size, uint32_t *sid)
+{
+    int err;
+    int cmd;
+    flask_op_t op;
+    
+    cmd = FLASK_CONTEXT_TO_SID;
+    op.buf = buf;
+    op.size = size;
+    
+    if ( (err = do_flask_op(xc_handle, cmd, &op)) != 0 )
+        return err;
+    
+    sscanf(buf, "%u", sid);
+
+    return 0;
+}
+
+int flask_sid_to_context(int xc_handle, int sid, char *buf, int size)
+{
+    int err;
+    int cmd;
+    flask_op_t op;
+    
+    cmd = FLASK_SID_TO_CONTEXT;
+    op.buf = buf;
+    op.size = size;
+    
+    snprintf(buf, size, "%u", sid);
+
+    if ( (err = do_flask_op(xc_handle, cmd, &op)) != 0 )
+        return err;
+
+    return 0;
+}
+
+int do_flask_op(int xc_handle, int cmd, flask_op_t *op)
+{
+    int ret = -1;
+    DECLARE_HYPERCALL;
+
+    hypercall.op     = __HYPERVISOR_xsm_op;
+    hypercall.arg[0] = cmd;
+    hypercall.arg[1] = (unsigned long)op;
+
+    if ( mlock(op, sizeof(*op)) != 0 )
+    {
+        PERROR("Could not lock memory for Xen hypercall");
+        goto out;
+    }
+
+    if ( (ret = do_xen_hypercall(xc_handle, &hypercall)) < 0 )
+    {
+        if ( errno == EACCES )
+            fprintf(stderr, "XSM operation failed!\n");
+    }
+
+    safe_munlock(op, sizeof(*op));
+
+ out:
+    return ret;
+}
+
diff -r 8ae246493872 -r 12213351ff5d tools/flask/libflask/include/flask_op.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/flask/libflask/include/flask_op.h	Mon Jun 04 11:09:10 2007 -0400
@@ -0,0 +1,45 @@
+/*
+ *
+ *  Authors:  Michael LeMay, <mdlemay@epoch.ncsc.mil>
+ *            George Coker, <gscoker@alpha.ncsc.mil>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2,
+ *  as published by the Free Software Foundation.
+ */
+
+#ifndef __FLASK_OP_H
+#define __FLASK_OP_H
+
+#define FLASK_LOAD              1
+#define FLASK_GETENFORCE        2
+#define FLASK_SETENFORCE        3
+#define FLASK_CONTEXT_TO_SID    4
+#define FLASK_SID_TO_CONTEXT    5
+#define FLASK_ACCESS            6
+#define FLASK_CREATE            7
+#define FLASK_RELABEL           8
+#define FLASK_USER              9
+#define FLASK_POLICYVERS        10
+#define FLASK_GETBOOL           11
+#define FLASK_SETBOOL           12
+#define FLASK_COMMITBOOLS       13
+#define FLASK_MLS               14
+#define FLASK_DISABLE           15
+#define FLASK_GETAVC_THRESHOLD  16
+#define FLASK_SETAVC_THRESHOLD  17
+#define FLASK_AVC_HASHSTATS     18
+#define FLASK_AVC_CACHESTATS    19
+#define FLASK_MEMBER            20
+
+typedef struct flask_op {
+    int   size;
+    char *buf;
+} flask_op_t;
+
+int flask_load(int xc_handle, char *buf, int size);
+int flask_context_to_sid(int xc_handle, char *buf, int size, u_int32_t *sid);
+int flask_sid_to_context(int xc_handle, int sid, char *buf, int size);
+int do_flask_op(int xc_handle, int cmd, flask_op_t *op);
+
+#endif
diff -r 8ae246493872 -r 12213351ff5d tools/flask/loadpolicy/Makefile
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/flask/loadpolicy/Makefile	Mon Jun 04 11:09:10 2007 -0400
@@ -0,0 +1,61 @@
+XEN_ROOT=../../..
+include $(XEN_ROOT)/tools/Rules.mk
+XEN_LIBXC          = $(XEN_ROOT)/tools/libxc
+
+INSTALL         = install
+INSTALL_DATA    = $(INSTALL) -m0644
+INSTALL_PROG    = $(INSTALL) -m0755
+INSTALL_DIR     = $(INSTALL) -d -m0755
+
+LIBXC_ROOT = $(XEN_ROOT)/tools/libxc
+LIBFLASK_ROOT = $(XEN_ROOT)/tools/flask/libflask
+
+PROFILE=#-pg
+BASECFLAGS=-Wall -g -Werror
+# Make gcc generate dependencies.
+BASECFLAGS += -Wp,-MD,.$(@F).d
+PROG_DEP = .*.d
+BASECFLAGS+= $(PROFILE)
+#BASECFLAGS+= -I$(XEN_ROOT)/tools
+BASECFLAGS+= -I$(LIBXC_ROOT)
+BASECFLAGS+= -I$(LIBFLASK_ROOT)/include
+BASECFLAGS+= -I.
+
+CFLAGS  += $(BASECFLAGS)
+LDFLAGS += $(PROFILE) -L$(XEN_LIBXC) -L$(LIBFLASK_ROOT)
+TESTDIR  = testsuite/tmp
+TESTFLAGS= -DTESTING
+TESTENV  = XENSTORED_ROOTDIR=$(TESTDIR) XENSTORED_RUNDIR=$(TESTDIR)
+
+CLIENTS := flask-loadpolicy
+CLIENTS_OBJS := $(patsubst flask-%,%.o,$(CLIENTS))
+
+.PHONY: all
+all: $(CLIENTS)
+
+$(CLIENTS): flask-%: %.o
+	$(LINK.o) $< $(LOADLIBES) $(LDLIBS) -L. -lflask -lxenctrl -o $@
+
+.PHONY: clean
+clean: 
+	rm -f *.o *.opic *.so
+	rm -f $(CLIENTS)
+	$(RM) $(PROG_DEP)
+
+.PHONY: print-dir
+print-dir:
+	@echo -n tools/flask/loadpolicy: 
+
+.PHONY: print-end
+print-end:
+	@echo
+
+.PHONY: install
+install: all
+	$(INSTALL_DIR) -p $(DESTDIR)/usr/sbin
+	$(INSTALL_PROG) $(CLIENTS) $(DESTDIR)/usr/sbin
+
+-include $(PROG_DEP)
+
+# never delete any intermediate files.
+.SECONDARY:
diff -r 8ae246493872 -r 12213351ff5d tools/flask/loadpolicy/loadpolicy.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/flask/loadpolicy/loadpolicy.c	Mon Jun 04 11:09:10 2007 -0400
@@ -0,0 +1,130 @@
+/*
+ *
+ *  Authors:  Michael LeMay, <mdlemay@epoch.ncsc.mil>
+ *            George Coker, <gscoker@alpha.ncsc.mil>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License version 2,
+ *      as published by the Free Software Foundation.
+ */
+
+#include <stdlib.h>
+#include <errno.h>
+#include <stdio.h>
+#include <xenctrl.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <flask_op.h>
+
+#define USE_MMAP
+
+static void usage (int argCnt, const char *args[])
+{
+    fprintf(stderr, "Usage: %s <policy.file>\n", args[0]);
+    exit(1);
+}
+
+int main (int argCnt, const char *args[])
+{
+    const char *polFName;
+    int polFd = 0;
+    void *polMem = NULL;
+    void *polMemCp = NULL;
+    struct stat info;
+    int ret;
+    int xch = 0;
+
+    if (argCnt != 2)
+        usage(argCnt, args);
+
+    polFName = args[1];
+    polFd = open(polFName, O_RDONLY);
+    if ( polFd < 0 )
+    {
+        fprintf(stderr, "Error occurred opening policy file '%s': %s\n",
+                polFName, strerror(errno));
+        ret = -1;
+        goto cleanup;
+    }
+    
+    ret = stat(polFName, &info);
+    if ( ret < 0 )
+    {
+        fprintf(stderr, "Error occurred retrieving information about"
+                "policy file '%s': %s\n", polFName, strerror(errno));
+        goto cleanup;
+    }
+
+    polMemCp = malloc(info.st_size);
+
+#ifdef USE_MMAP
+    polMem = mmap(NULL, info.st_size, PROT_READ, MAP_SHARED, polFd, 0);
+    if ( !polMem )
+    {
+        fprintf(stderr, "Error occurred mapping policy file in memory: %s\n",
+                strerror(errno));
+        ret = -1;
+        goto cleanup;
+    }
+
+    xch = xc_interface_open();
+    if ( xch < 0 )
+    {
+        fprintf(stderr, "Unable to create interface to xenctrl: %s\n",
+                strerror(errno));
+        ret = -1;
+        goto cleanup;
+    }
+
+    memcpy(polMemCp, polMem, info.st_size);
+#else
+    ret = read(polFd, polMemCp, info.st_size);
+    if ( ret < 0 )
+    {
+        fprintf(stderr, "Unable to read new Flask policy file: %s\n",
+                strerror(errno));
+        goto cleanup;
+    }
+    else
+    {
+        printf("Read %d bytes from policy file '%s'.\n", ret, polFName);
+    }
+#endif
+
+    ret = flask_load(xch, polMemCp, info.st_size);
+    if ( ret < 0 )
+    {
+        errno = -ret;
+        fprintf(stderr, "Unable to load new Flask policy: %s\n",
+                strerror(errno));
+        ret = -1;
+        goto cleanup;
+    }
+    else
+    {
+        printf("Successfully loaded policy.\n");
+    }
+
+done:
+    if ( polMemCp )
+        free(polMemCp);
+    if ( polMem )
+    {
+        ret = munmap(polMem, info.st_size);
+        if ( ret < 0 )
+            fprintf(stderr, "Unable to unmap policy memory: %s\n", strerror(errno));
+    }
+    if ( polFd )
+        close(polFd);
+    if ( xch )
+        xc_interface_close(xch);
+
+    return ret;
+
+cleanup:
+    goto done;
+}
diff -r 8ae246493872 -r 12213351ff5d tools/misc/xenperf.c
--- a/tools/misc/xenperf.c	Mon Jun 04 11:06:52 2007 -0400
+++ b/tools/misc/xenperf.c	Mon Jun 04 11:09:10 2007 -0400
@@ -46,7 +46,7 @@ const char *hypercall_name_table[64] =
     X(vcpu_op),
     X(set_segment_base),
     X(mmuext_op),
-    X(acm_op),
+    X(xsm_op),
     X(nmi_op),
     X(sched_op),
     X(callback_op),
diff -r 8ae246493872 -r 12213351ff5d tools/python/Makefile
--- a/tools/python/Makefile	Mon Jun 04 11:06:52 2007 -0400
+++ b/tools/python/Makefile	Mon Jun 04 11:09:10 2007 -0400
@@ -1,5 +1,13 @@ XEN_ROOT = ../..
 XEN_ROOT = ../..
 include $(XEN_ROOT)/tools/Rules.mk
+
+XEN_SECURITY_MODULE = dummy
+ifeq ($(FLASK_ENABLE),y)
+XEN_SECURITY_MODULE = flask
+endif
+ifeq ($(ACM_SECURITY),y)
+XEN_SECURITY_MODULE = acm
+endif
 
 .PHONY: all
 all: build
@@ -16,9 +24,9 @@ NLSDIR = /usr/share/locale
 
 .PHONY: build buildpy
 buildpy:
-	CC="$(CC)" CFLAGS="$(CFLAGS)" python setup.py build
+	CC="$(CC)" CFLAGS="$(CFLAGS)" XEN_SECURITY_MODULE="$(XEN_SECURITY_MODULE)" python setup.py build
 
-build: buildpy refresh-pot refresh-po $(CATALOGS)
+build: xsm.py buildpy refresh-pot refresh-po $(CATALOGS)
 
 # NB we take care to only update the .pot file it strings have
 # actually changed. This is complicated by the embedded date
@@ -53,6 +61,18 @@ refresh-po: $(POTFILE)
 %.mo: %.po
 	$(MSGFMT) -c -o $@ $<
 
+xsm.py:
+	@(set -e; \
+	  echo "XEN_SECURITY_MODULE = \""$(XEN_SECURITY_MODULE)"\""; \
+	  echo "from xsm_core import *"; \
+	  echo ""; \
+	  echo "import xen.util.xsm."$(XEN_SECURITY_MODULE)"."$(XEN_SECURITY_MODULE)" as xsm_module"; \
+	  echo ""; \
+	  echo "xsm_init(xsm_module)"; \
+	  echo "from xen.util.xsm."$(XEN_SECURITY_MODULE)"."$(XEN_SECURITY_MODULE)" import *"; \
+	  echo "del xsm_module"; \
+	  echo "") >xen/util/xsm/$@
+
 .PHONY: install
 ifndef XEN_PYTHON_NATIVE_INSTALL
 install: LIBPATH=$(shell PYTHONPATH=xen/util python -c "import auxbin; print auxbin.libpath()")
@@ -84,4 +104,4 @@ test:
 
 .PHONY: clean
 clean:
-	rm -rf build *.pyc *.pyo *.o *.a *~ $(CATALOGS)
+	rm -rf build *.pyc *.pyo *.o *.a *~ $(CATALOGS) xen/util/xsm/xsm.py
diff -r 8ae246493872 -r 12213351ff5d tools/python/setup.py
--- a/tools/python/setup.py	Mon Jun 04 11:06:52 2007 -0400
+++ b/tools/python/setup.py	Mon Jun 04 11:09:10 2007 -0400
@@ -44,6 +44,14 @@ acm = Extension("acm",
                libraries          = libraries,
                sources            = [ "xen/lowlevel/acm/acm.c" ])
 
+flask = Extension("flask",
+               extra_compile_args = extra_compile_args,
+               include_dirs       = include_dirs + [ "xen/lowlevel/flask" ] + 
+                                        [ "../flask/libflask/include" ],
+               library_dirs       = library_dirs + [ "../flask/libflask" ],
+               libraries          = libraries + [ "flask" ],
+               sources            = [ "xen/lowlevel/flask/flask.c" ])
+
 ptsname = Extension("ptsname",
                extra_compile_args = extra_compile_args,
                include_dirs       = include_dirs + [ "ptsname" ],
@@ -51,9 +59,14 @@ ptsname = Extension("ptsname",
                libraries          = libraries,
                sources            = [ "ptsname/ptsname.c" ])
 
-modules = [ xc, xs, acm, ptsname ]
+modules = [ xc, xs, ptsname ]
 if os.uname()[0] == 'SunOS':
     modules.append(scf)
+
+if os.environ.get('XEN_SECURITY_MODULE') == 'acm':
+    modules.append(acm)
+if os.environ.get('XEN_SECURITY_MODULE') == 'flask':
+    modules.append(flask)
 
 setup(name            = 'xen',
       version         = '3.0',
@@ -61,6 +74,10 @@ setup(name            = 'xen',
       packages        = ['xen',
                          'xen.lowlevel',
                          'xen.util',
+                         'xen.util.xsm',
+                         'xen.util.xsm.dummy',
+                         'xen.util.xsm.flask',
+                         'xen.util.xsm.acm',
                          'xen.xend',
                          'xen.xend.server',
                          'xen.xend.xenstore',
diff -r 8ae246493872 -r 12213351ff5d tools/python/xen/lowlevel/flask/flask.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/python/xen/lowlevel/flask/flask.c	Mon Jun 04 11:09:10 2007 -0400
@@ -0,0 +1,139 @@
+/******************************************************************************
+ * flask.c
+ * 
+ * Authors: George Coker, <gscoker@alpha.ncsc.mil>
+ *          Michael LeMay, <mdlemay@epoch.ncsc.mil>
+ *
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License version 2,
+ *    as published by the Free Software Foundation.
+ */
+
+#include <Python.h>
+#include <xenctrl.h>
+
+#include <flask_op.h>
+
+#define PKG "xen.lowlevel.flask"
+#define CLS "flask"
+
+#define CTX_LEN 1024
+
+static PyObject *xc_error_obj;
+
+typedef struct {
+    PyObject_HEAD;
+    int xc_handle;
+} XcObject;
+
+static PyObject *pyflask_context_to_sid(PyObject *self, PyObject *args,
+                                                                 PyObject *kwds)
+{
+    int xc_handle;
+    char *ctx;
+    char *buf;
+    uint32_t len;
+    uint32_t sid;
+    int ret;
+
+    static char *kwd_list[] = { "context", NULL };
+
+    if ( !PyArg_ParseTupleAndKeywords(args, kwds, "s", kwd_list,
+                                      &ctx) )
+        return NULL;
+
+    len = strlen(ctx);
+
+    buf = malloc(len);
+    if (!buf) {
+        errno = -ENOMEM;
+        PyErr_SetFromErrno(xc_error_obj);
+    }
+    
+    memcpy(buf, ctx, len);
+    
+    xc_handle = xc_interface_open();
+    if (xc_handle < 0) {
+        errno = xc_handle;
+        return PyErr_SetFromErrno(xc_error_obj);
+    }
+    
+    ret = flask_context_to_sid(xc_handle, buf, len, &sid);
+        
+    xc_interface_close(xc_handle);
+
+    free(buf);
+    
+    if ( ret != 0 ) {
+        errno = -ret;
+        return PyErr_SetFromErrno(xc_error_obj);
+    }
+
+    return PyInt_FromLong(sid);
+}
+
+static PyObject *pyflask_sid_to_context(PyObject *self, PyObject *args,
+                                                                 PyObject *kwds)
+{
+    int xc_handle;
+    uint32_t sid;
+    char ctx[CTX_LEN];
+    uint32_t ctx_len = CTX_LEN;
+    int ret;
+
+    static char *kwd_list[] = { "sid", NULL };
+
+    if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i", kwd_list,
+                                      &sid) )
+        return NULL;
+
+    xc_handle = xc_interface_open();
+    if (xc_handle < 0) {
+        errno = xc_handle;
+        return PyErr_SetFromErrno(xc_error_obj);
+    }
+    
+    ret = flask_sid_to_context(xc_handle, sid, ctx, ctx_len);
+    
+    xc_interface_close(xc_handle);
+    
+    if ( ret != 0 ) {
+        errno = -ret;
+        return PyErr_SetFromErrno(xc_error_obj);
+    }
+
+    return Py_BuildValue("s", ctx, ctx_len);
+}
+
+
+static PyMethodDef pyflask_methods[] = {
+    { "flask_context_to_sid",
+      (PyCFunction)pyflask_context_to_sid,
+      METH_KEYWORDS, "\n"
+      "Convert a context string to a dynamic SID.\n"
+      " context [str]: String specifying context to be converted\n"
+      "Returns: [int]: Numeric SID on success; -1 on error.\n" },
+
+    { "flask_sid_to_context",
+      (PyCFunction)pyflask_sid_to_context,
+      METH_KEYWORDS, "\n"
+      "Convert a dynamic SID to context string.\n"
+      " context [int]: SID to be converted\n"
+      "Returns: [str]: Numeric SID on success; -1 on error.\n" },
+
+    { NULL, NULL, 0, NULL }
+};
+
+PyMODINIT_FUNC initflask(void)
+{
+    Py_InitModule("flask", pyflask_methods);
+}
+
+
+/*
+ * Local variables:
+ *  c-indent-level: 4
+ *  c-basic-offset: 4
+ * End:
+ */
diff -r 8ae246493872 -r 12213351ff5d tools/python/xen/util/security.py
--- a/tools/python/xen/util/security.py	Mon Jun 04 11:06:52 2007 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,670 +0,0 @@
-#===========================================================================
-# This library is free software; you can redistribute it and/or
-# modify it under the terms of version 2.1 of the GNU Lesser General Public
-# License as published by the Free Software Foundation.
-#
-# This library is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-# Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this library; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-#============================================================================
-# Copyright (C) 2006 International Business Machines Corp.
-# Author: Reiner Sailer
-# Author: Bryan D. Payne <bdpayne@us.ibm.com>
-#============================================================================
-
-import commands
-import logging
-import sys, os, string, re
-import traceback
-import shutil
-from xen.lowlevel import acm
-from xen.xend import sxp
-from xen.xend.XendLogging import log
-from xen.util import dictio
-
-#global directories and tools for security management
-policy_dir_prefix = "/etc/xen/acm-security/policies"
-res_label_filename = policy_dir_prefix + "/resource_labels"
-boot_filename = "/boot/grub/menu.lst"
-altboot_filename = "/boot/grub/grub.conf"
-xensec_xml2bin = "/usr/sbin/xensec_xml2bin"
-xensec_tool = "/usr/sbin/xensec_tool"
-
-#global patterns for map file
-#police_reference_tagname = "POLICYREFERENCENAME"
-primary_entry_re = re.compile("\s*PRIMARY\s+.*", re.IGNORECASE)
-secondary_entry_re = re.compile("\s*SECONDARY\s+.*", re.IGNORECASE)
-label_template_re =  re.compile(".*security_label_template.xml", re.IGNORECASE)
-mapping_filename_re = re.compile(".*\.map", re.IGNORECASE)
-policy_reference_entry_re = re.compile("\s*POLICYREFERENCENAME\s+.*", re.IGNORECASE)
-vm_label_re = re.compile("\s*LABEL->SSID\s+VM\s+.*", re.IGNORECASE)
-res_label_re = re.compile("\s*LABEL->SSID\s+RES\s+.*", re.IGNORECASE)
-all_label_re = re.compile("\s*LABEL->SSID\s+.*", re.IGNORECASE)
-access_control_re = re.compile("\s*access_control\s*=", re.IGNORECASE)
-
-#global patterns for boot configuration file
-xen_title_re = re.compile("\s*title\s+XEN", re.IGNORECASE)
-any_title_re = re.compile("\s*title\s", re.IGNORECASE)
-xen_kernel_re = re.compile("\s*kernel.*xen.*\.gz", re.IGNORECASE)
-kernel_ver_re = re.compile("\s*module.*vmlinuz", re.IGNORECASE)
-any_module_re = re.compile("\s*module\s", re.IGNORECASE)
-empty_line_re = re.compile("^\s*$")
-binary_name_re = re.compile(".*[chwall|ste|chwall_ste].*\.bin", re.IGNORECASE)
-policy_name_re = re.compile(".*[chwall|ste|chwall_ste].*", re.IGNORECASE)
-
-#other global variables
-NULL_SSIDREF = 0
-
-log = logging.getLogger("xend.util.security")
-
-# Our own exception definition. It is masked (pass) if raised and
-# whoever raises this exception must provide error information.
-class ACMError(Exception):
-    def __init__(self,value):
-        self.value = value
-    def __str__(self):
-        return repr(self.value)
-
-
-
-def err(msg):
-    """Raise ACM exception.
-    """
-    sys.stderr.write("ACMError: " + msg + "\n")
-    raise ACMError(msg)
-
-
-
-active_policy = None
-
-
-def refresh_security_policy():
-    """
-    retrieves security policy
-    """
-    global active_policy
-
-    try:
-        active_policy = acm.policy()
-    except:
-        active_policy = "INACTIVE"
-
-# now set active_policy
-refresh_security_policy()
-
-def on():
-    """
-    returns none if security policy is off (not compiled),
-    any string otherwise, use it: if not security.on() ...
-    """
-    refresh_security_policy()
-    return (active_policy not in ['INACTIVE', 'NULL'])
-
-
-
-# Assumes a 'security' info  [security access_control ...] [ssidref ...]
-def get_security_info(info, field):
-    """retrieves security field from self.info['security'])
-    allowed search fields: ssidref, label, policy
-    """
-    if isinstance(info, dict):
-        security = info['security']
-    elif isinstance(info, list):
-        security = sxp.child_value(info, 'security')
-    if not security:
-        if field == 'ssidref':
-            #return default ssid
-            return 0
-        else:
-            err("Security information not found in info struct.")
-
-    if field == 'ssidref':
-        search = 'ssidref'
-    elif field in ['policy', 'label']:
-            search = 'access_control'
-    else:
-        err("Illegal field in get_security_info.")
-
-    for idx in range(0, len(security)):
-        if search != security[idx][0]:
-            continue
-        if search == 'ssidref':
-            return int(security[idx][1])
-        else:
-            for aidx in range(0, len(security[idx])):
-                if security[idx][aidx][0] == field:
-                    return str(security[idx][aidx][1])
-
-    if search == 'ssidref':
-        return 0
-    else:
-        return None
-
-
-
-def get_security_printlabel(info):
-    """retrieves printable security label from self.info['security']),
-    preferably the label name and otherwise (if label is not specified
-    in config and cannot be found in mapping file) a hex string of the
-    ssidref or none if both not available
-    """
-    try:
-        if not on():
-            return "INACTIVE"
-        if active_policy in ["DEFAULT"]:
-            return "DEFAULT"
-
-        printlabel = get_security_info(info, 'label')
-        if printlabel:
-            return printlabel
-        ssidref = get_security_info(info, 'ssidref')
-        if not ssidref:
-            return None
-        #try to translate ssidref to a label
-        result = ssidref2label(ssidref)
-        if not result:
-            printlabel = "0x%08x" % ssidref
-        else:
-            printlabel = result
-        return printlabel
-    except ACMError:
-        #don't throw an exception in xm list
-        return "ERROR"
-
-
-
-def getmapfile(policyname):
-    """
-    in: if policyname is None then the currently
-    active hypervisor policy is used
-    out: 1. primary policy, 2. secondary policy,
-    3. open file descriptor for mapping file, and
-    4. True if policy file is available, False otherwise
-    """
-    if not policyname:
-        policyname = active_policy
-    map_file_ok = False
-    primary = None
-    secondary = None
-    #strip last part of policy as file name part
-    policy_dir_list = string.split(policyname, ".")
-    policy_file = policy_dir_list.pop()
-    if len(policy_dir_list) > 0:
-        policy_dir = string.join(policy_dir_list, "/") + "/"
-    else:
-        policy_dir = ""
-
-    map_filename = policy_dir_prefix + "/" + policy_dir + policy_file + ".map"
-    # check if it is there, if not check if policy file is there
-    if not os.path.isfile(map_filename):
-        policy_filename =  policy_dir_prefix + "/" + policy_dir + policy_file + "-security_policy.xml"
-        if not os.path.isfile(policy_filename):
-            err("Policy file \'" + policy_filename + "\' not found.")
-        else:
-            err("Mapping file \'" + map_filename + "\' not found." +
-                " Use xm makepolicy to create it.")
-
-    f = open(map_filename)
-    for line in f:
-        if policy_reference_entry_re.match(line):
-            l = line.split()
-            if (len(l) == 2) and (l[1] == policyname):
-                map_file_ok = True
-        elif primary_entry_re.match(line):
-            l = line.split()
-            if len(l) == 2:
-                primary = l[1]
-        elif secondary_entry_re.match(line):
-            l = line.split()
-            if len(l) == 2:
-                secondary = l[1]
-    f.close()
-    f = open(map_filename)
-    if map_file_ok and primary and secondary:
-        return (primary, secondary, f, True)
-    else:
-        err("Mapping file inconsistencies found. Try makepolicy to create a new one.")
-
-
-
-def ssidref2label(ssidref_var):
-    """
-    returns labelname corresponding to ssidref;
-    maps current policy to default directory
-    to find mapping file
-    """
-    #1. translated permitted input formats
-    if isinstance(ssidref_var, str):
-        ssidref_var.strip()
-        if ssidref_var[0:2] == "0x":
-            ssidref = int(ssidref_var[2:], 16)
-        else:
-            ssidref = int(ssidref_var)
-    elif isinstance(ssidref_var, int):
-        ssidref = ssidref_var
-    else:
-        err("Instance type of ssidref not supported (must be of type 'str' or 'int')")
-
-    (primary, secondary, f, pol_exists) = getmapfile(None)
-    if not f:
-        if (pol_exists):
-            err("Mapping file for policy \'" + policyname + "\' not found.\n" +
-                "Please use makepolicy command to create mapping file!")
-        else:
-            err("Policy file for \'" + active_policy + "\' not found.")
-
-    #2. get labelnames for both ssidref parts
-    pri_ssid = ssidref & 0xffff
-    sec_ssid = ssidref >> 16
-    pri_null_ssid = NULL_SSIDREF & 0xffff
-    sec_null_ssid = NULL_SSIDREF >> 16
-    pri_labels = []
-    sec_labels = []
-    labels = []
-
-    for line in f:
-        l = line.split()
-        if (len(l) < 5) or (l[0] != "LABEL->SSID"):
-            continue
-        if primary and (l[2] == primary) and (int(l[4], 16) == pri_ssid):
-            pri_labels.append(l[3])
-        if secondary and (l[2] == secondary) and (int(l[4], 16) == sec_ssid):
-            sec_labels.append(l[3])
-    f.close()
-
-    #3. get the label that is in both lists (combination must be a single label)
-    if (primary == "CHWALL") and (pri_ssid == pri_null_ssid) and (sec_ssid != sec_null_ssid):
-        labels = sec_labels
-    elif (secondary == "CHWALL") and (pri_ssid != pri_null_ssid) and (sec_ssid == sec_null_ssid):
-        labels = pri_labels
-    elif secondary == "NULL":
-        labels = pri_labels
-    else:
-        for i in pri_labels:
-            for j in sec_labels:
-                if (i==j):
-                    labels.append(i)
-    if len(labels) != 1:
-        err("Label for ssidref \'" +  str(ssidref) +
-            "\' unknown or not unique in policy \'" + active_policy + "\'")
-
-    return labels[0]
-
-
-
-def label2ssidref(labelname, policyname, type):
-    """
-    returns ssidref corresponding to labelname;
-    maps current policy to default directory
-    to find mapping file    """
-
-    if policyname in ['NULL', 'INACTIVE', 'DEFAULT']:
-        err("Cannot translate labels for \'" + policyname + "\' policy.")
-
-    allowed_types = ['ANY']
-    if type == 'dom':
-        allowed_types.append('VM')
-    elif type == 'res':
-        allowed_types.append('RES')
-    else:
-        err("Invalid type.  Must specify 'dom' or 'res'.")
-
-    (primary, secondary, f, pol_exists) = getmapfile(policyname)
-
-    #2. get labelnames for ssidref parts and find a common label
-    pri_ssid = []
-    sec_ssid = []
-    for line in f:
-        l = line.split()
-        if (len(l) < 5) or (l[0] != "LABEL->SSID"):
-            continue
-        if primary and (l[1] in allowed_types) and (l[2] == primary) and (l[3] == labelname):
-            pri_ssid.append(int(l[4], 16))
-        if secondary and (l[1] in allowed_types) and (l[2] == secondary) and (l[3] == labelname):
-            sec_ssid.append(int(l[4], 16))
-    f.close()
-    if (type == 'res') and (primary == "CHWALL") and (len(pri_ssid) == 0):
-        pri_ssid.append(NULL_SSIDREF)
-    elif (type == 'res') and (secondary == "CHWALL") and (len(sec_ssid) == 0):
-        sec_ssid.append(NULL_SSIDREF)
-
-    #3. sanity check and composition of ssidref
-    if (len(pri_ssid) == 0) or ((len(sec_ssid) == 0) and (secondary != "NULL")):
-        err("Label \'" + labelname + "\' not found.")
-    elif (len(pri_ssid) > 1) or (len(sec_ssid) > 1):
-        err("Label \'" + labelname + "\' not unique in policy (policy error)")
-    if secondary == "NULL":
-        return pri_ssid[0]
-    else:
-        return (sec_ssid[0] << 16) | pri_ssid[0]
-
-
-
-def refresh_ssidref(config):
-    """
-    looks up ssidref from security field
-    and refreshes the value if label exists
-    """
-    #called by dom0, policy could have changed after xen.utils.security was initialized
-    refresh_security_policy()
-
-    security = None
-    if isinstance(config, dict):
-        security = config['security']
-    elif isinstance(config, list):
-        security = sxp.child_value(config, 'security')
-    else:
-        err("Instance type of config parameter not supported.")
-    if not security:
-        #nothing to do (no security label attached)
-        return config
-
-    policyname = None
-    labelname = None
-    # compose new security field
-    for idx in range(0, len(security)):
-        if security[idx][0] == 'ssidref':
-            security.pop(idx)
-            break
-        elif security[idx][0] == 'access_control':
-            for jdx in [1, 2]:
-                if security[idx][jdx][0] == 'label':
-                    labelname = security[idx][jdx][1]
-                elif security[idx][jdx][0] == 'policy':
-                    policyname = security[idx][jdx][1]
-                else:
-                    err("Illegal field in access_control")
-    #verify policy is correct
-    if active_policy != policyname:
-        err("Policy \'" + policyname + "\' in label does not match active policy \'"
-            + active_policy +"\'!")
-
-    new_ssidref = label2ssidref(labelname, policyname, 'dom')
-    if not new_ssidref:
-        err("SSIDREF refresh failed!")
-
-    security.append([ 'ssidref',str(new_ssidref)])
-    security = ['security', security ]
-
-    for idx in range(0,len(config)):
-        if config[idx][0] == 'security':
-            config.pop(idx)
-            break
-        config.append(security)
-
-
-
-def get_ssid(domain):
-    """
-    enables domains to retrieve the label / ssidref of a running domain
-    """
-    if not on():
-        err("No policy active.")
-
-    if isinstance(domain, str):
-        domain_int = int(domain)
-    elif isinstance(domain, int):
-        domain_int = domain
-    else:
-        err("Illegal parameter type.")
-    try:
-        ssid_info = acm.getssid(int(domain_int))
-    except:
-        err("Cannot determine security information.")
-
-    if active_policy in ["DEFAULT"]:
-        label = "DEFAULT"
-    else:
-        label = ssidref2label(ssid_info["ssidref"])
-    return(ssid_info["policyreference"],
-           label,
-           ssid_info["policytype"],
-           ssid_info["ssidref"])
-
-
-
-def get_decision(arg1, arg2):
-    """
-    enables domains to retrieve access control decisions from
-    the hypervisor Access Control Module.
-    IN: args format = ['domid', id] or ['ssidref', ssidref]
-    or ['access_control', ['policy', policy], ['label', label], ['type', type]]
-    """
-
-    if not on():
-        err("No policy active.")
-
-    #translate labels before calling low-level function
-    if arg1[0] == 'access_control':
-        if (arg1[1][0] != 'policy') or (arg1[2][0] != 'label') or (arg1[3][0] != 'type'):
-            err("Argument type not supported.")
-        ssidref = label2ssidref(arg1[2][1], arg1[1][1], arg1[3][1])
-        arg1 = ['ssidref', str(ssidref)]
-    if arg2[0] == 'access_control':
-        if (arg2[1][0] != 'policy') or (arg2[2][0] != 'label') or (arg2[3][0] != 'type'):
-            err("Argument type not supported.")
-        ssidref = label2ssidref(arg2[2][1], arg2[1][1], arg2[3][1])
-        arg2 = ['ssidref', str(ssidref)]
-
-    # accept only int or string types for domid and ssidref
-    if isinstance(arg1[1], int):
-        arg1[1] = str(arg1[1])
-    if isinstance(arg2[1], int):
-        arg2[1] = str(arg2[1])
-    if not isinstance(arg1[1], str) or not isinstance(arg2[1], str):
-        err("Invalid id or ssidref type, string or int required")
-
-    try:
-        decision = acm.getdecision(arg1[0], arg1[1], arg2[0], arg2[1])
-    except:
-        err("Cannot determine decision.")
-
-    if decision:
-        return decision
-    else:
-        err("Cannot determine decision (Invalid parameter).")
-
-
-
-def make_policy(policy_name):
-    policy_file = string.join(string.split(policy_name, "."), "/")
-    if not os.path.isfile(policy_dir_prefix + "/" + policy_file + "-security_policy.xml"):
-        err("Unknown policy \'" + policy_name + "\'")
-
-    (ret, output) = commands.getstatusoutput(xensec_xml2bin + " -d " + policy_dir_prefix + " " + policy_file)
-    if ret:
-        err("Creating policy failed:\n" + output)
-
-
-
-def load_policy(policy_name):
-    global active_policy
-    policy_file = policy_dir_prefix + "/" + string.join(string.split(policy_name, "."), "/")
-    if not os.path.isfile(policy_file + ".bin"):
-        if os.path.isfile(policy_file + "-security_policy.xml"):
-            err("Binary file does not exist." +
-                "Please use makepolicy to build the policy binary.")
-        else:
-            err("Unknown Policy " + policy_name)
-
-    #require this policy to be the first or the same as installed
-    if active_policy not in ['DEFAULT', policy_name]:
-        err("Active policy \'" + active_policy +
-            "\' incompatible with new policy \'" + policy_name + "\'")
-    (ret, output) = commands.getstatusoutput(xensec_tool + " loadpolicy " + policy_file + ".bin")
-    if ret:
-        err("Loading policy failed:\n" + output)
-    else:
-        # refresh active policy
-        refresh_security_policy()
-
-
-
-def dump_policy():
-    if active_policy in ['NULL', 'INACTIVE']:
-        err("\'" + active_policy + "\' policy. Nothing to dump.")
-
-    (ret, output) = commands.getstatusoutput(xensec_tool + " getpolicy")
-    if ret:
-       err("Dumping hypervisor policy failed:\n" + output)
-    print output
-
-
-
-def list_labels(policy_name, condition):
-    if (not policy_name) and (active_policy) in ["NULL", "INACTIVE", "DEFAULT"]:
-        err("Current policy \'" + active_policy + "\' has no labels defined.\n")
-
-    (primary, secondary, f, pol_exists) = getmapfile(policy_name)
-    if not f:
-        if pol_exists:
-            err("Cannot find mapfile for policy \'" + policy_name +
-                "\'.\nPlease use makepolicy to create mapping file.")
-        else:
-            err("Unknown policy \'" + policy_name + "\'")
-
-    labels = []
-    for line in f:
-        if condition.match(line):
-            label = line.split()[3]
-            if label not in labels:
-                labels.append(label)
-    return labels
-
-
-def get_res_label(resource):
-    """Returns resource label information (label, policy) if it exists.
-       Otherwise returns null label and policy.
-    """
-    def default_res_label():
-        ssidref = NULL_SSIDREF
-        if on():
-            label = ssidref2label(ssidref)
-        else:
-            label = None
-        return (label, 'NULL')
-
-    (label, policy) = default_res_label()
-
-    # load the resource label file
-    res_label_cache = {}
-    try:
-        res_label_cache = dictio.dict_read("resources", res_label_filename)
-    except:
-        log.info("Resource label file not found.")
-        return default_res_label()
-
-    # find the resource information
-    if res_label_cache.has_key(resource):
-        (policy, label) = res_label_cache[resource]
-
-    return (label, policy)
-
-
-def get_res_security_details(resource):
-    """Returns the (label, ssidref, policy) associated with a given
-       resource from the global resource label file.
-    """
-    def default_security_details():
-        ssidref = NULL_SSIDREF
-        if on():
-            label = ssidref2label(ssidref)
-        else:
-            label = None
-        policy = active_policy
-        return (label, ssidref, policy)
-
-    (label, ssidref, policy) = default_security_details()
-
-    # find the entry associated with this resource
-    (label, policy) = get_res_label(resource)
-    if policy == 'NULL':
-        log.info("Resource label for "+resource+" not in file, using DEFAULT.")
-        return default_security_details()
-
-    # is this resource label for the running policy?
-    if policy == active_policy:
-        ssidref = label2ssidref(label, policy, 'res')
-    else:
-        log.info("Resource label not for active policy, using DEFAULT.")
-        return default_security_details()
-
-    return (label, ssidref, policy)
-
-
-def unify_resname(resource):
-    """Makes all resource locations absolute. In case of physical
-    resources, '/dev/' is added to local file names"""
-
-    if not resource:
-        return resource
-
-    # sanity check on resource name
-    try:
-        (type, resfile) = resource.split(":", 1)
-    except:
-        err("Resource spec '%s' contains no ':' delimiter" % resource)
-
-    if type == "tap":
-        try:
-            (subtype, resfile) = resfile.split(":")
-        except:
-            err("Resource spec '%s' contains no tap subtype" % resource)
-
-    if type in ["phy", "tap"]:
-        if not resfile.startswith("/"):
-            resfile = "/dev/" + resfile
-
-    #file: resources must specified with absolute path
-    if (not resfile.startswith("/")) or (not os.path.exists(resfile)):
-        err("Invalid resource.")
-
-    # from here on absolute file names with resources
-    if type == "tap":
-        type = type + ":" + subtype
-    resource = type + ":" + resfile
-    return resource
-
-
-def res_security_check(resource, domain_label):
-    """Checks if the given resource can be used by the given domain
-       label.  Returns 1 if the resource can be used, otherwise 0.
-    """
-    rtnval = 1
-
-    # if security is on, ask the hypervisor for a decision
-    if on():
-        #build canonical resource name
-        resource = unify_resname(resource)
-
-        (label, ssidref, policy) = get_res_security_details(resource)
-        domac = ['access_control']
-        domac.append(['policy', active_policy])
-        domac.append(['label', domain_label])
-        domac.append(['type', 'dom'])
-        decision = get_decision(domac, ['ssidref', str(ssidref)])
-
-        # provide descriptive error messages
-        if decision == 'DENIED':
-            if label == ssidref2label(NULL_SSIDREF):
-                raise ACMError("Resource '"+resource+"' is not labeled")
-                rtnval = 0
-            else:
-                raise ACMError("Permission denied for resource '"+resource+"' because label '"+label+"' is not allowed")
-                rtnval = 0
-
-    # security is off, make sure resource isn't labeled
-    else:
-        # Note, we can't canonicalise the resource here, because people using
-        # xm without ACM are free to use relative paths.
-        (label, policy) = get_res_label(resource)
-        if policy != 'NULL':
-            raise ACMError("Security is off, but '"+resource+"' is labeled")
-            rtnval = 0
-
-    return rtnval
diff -r 8ae246493872 -r 12213351ff5d tools/python/xen/util/xsm/acm/__init__.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/python/xen/util/xsm/acm/__init__.py	Mon Jun 04 11:09:10 2007 -0400
@@ -0,0 +1,1 @@
+ 
diff -r 8ae246493872 -r 12213351ff5d tools/python/xen/util/xsm/acm/acm.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/python/xen/util/xsm/acm/acm.py	Mon Jun 04 11:09:10 2007 -0400
@@ -0,0 +1,660 @@
+#===========================================================================
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of version 2.1 of the GNU Lesser General Public
+# License as published by the Free Software Foundation.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#============================================================================
+# Copyright (C) 2006 International Business Machines Corp.
+# Author: Reiner Sailer
+# Author: Bryan D. Payne <bdpayne@us.ibm.com>
+#============================================================================
+
+import commands
+import logging
+import sys, os, string, re
+import traceback
+import shutil
+from xen.lowlevel import acm
+from xen.xend import sxp
+from xen.xend.XendLogging import log
+from xen.util import dictio
+
+#global directories and tools for security management
+policy_dir_prefix = "/etc/xen/acm-security/policies"
+res_label_filename = policy_dir_prefix + "/resource_labels"
+boot_filename = "/boot/grub/menu.lst"
+altboot_filename = "/boot/grub/grub.conf"
+xensec_xml2bin = "/usr/sbin/xensec_xml2bin"
+xensec_tool = "/usr/sbin/xensec_tool"
+
+#global patterns for map file
+#police_reference_tagname = "POLICYREFERENCENAME"
+primary_entry_re = re.compile("\s*PRIMARY\s+.*", re.IGNORECASE)
+secondary_entry_re = re.compile("\s*SECONDARY\s+.*", re.IGNORECASE)
+label_template_re =  re.compile(".*security_label_template.xml", re.IGNORECASE)
+mapping_filename_re = re.compile(".*\.map", re.IGNORECASE)
+policy_reference_entry_re = re.compile("\s*POLICYREFERENCENAME\s+.*", re.IGNORECASE)
+vm_label_re = re.compile("\s*LABEL->SSID\s+VM\s+.*", re.IGNORECASE)
+res_label_re = re.compile("\s*LABEL->SSID\s+RES\s+.*", re.IGNORECASE)
+all_label_re = re.compile("\s*LABEL->SSID\s+.*", re.IGNORECASE)
+access_control_re = re.compile("\s*access_control\s*=", re.IGNORECASE)
+
+#global patterns for boot configuration file
+xen_title_re = re.compile("\s*title\s+XEN", re.IGNORECASE)
+any_title_re = re.compile("\s*title\s", re.IGNORECASE)
+xen_kernel_re = re.compile("\s*kernel.*xen.*\.gz", re.IGNORECASE)
+kernel_ver_re = re.compile("\s*module.*vmlinuz", re.IGNORECASE)
+any_module_re = re.compile("\s*module\s", re.IGNORECASE)
+empty_line_re = re.compile("^\s*$")
+binary_name_re = re.compile(".*[chwall|ste|chwall_ste].*\.bin", re.IGNORECASE)
+policy_name_re = re.compile(".*[chwall|ste|chwall_ste].*", re.IGNORECASE)
+
+#other global variables
+NULL_SSIDREF = 0
+
+log = logging.getLogger("xend.util.security")
+
+def err(msg):
+    """Raise XSM-ACM exception.
+    """
+    sys.stderr.write("XSM-ACMError: " + msg + "\n")
+    raise XSMError(msg)
+
+
+
+active_policy = None
+
+
+def refresh_security_policy():
+    """
+    retrieves security policy
+    """
+    global active_policy
+
+    try:
+        active_policy = acm.policy()
+    except:
+        active_policy = "INACTIVE"
+
+# now set active_policy
+refresh_security_policy()
+
+def on():
+    """
+    returns none if security policy is off (not compiled),
+    any string otherwise, use it: if not security.on() ...
+    """
+    refresh_security_policy()
+    return (active_policy not in ['INACTIVE', 'NULL'])
+
+
+
+# Assumes a 'security' info  [security access_control ...] [ssidref ...]
+def get_security_info(info, field):
+    """retrieves security field from self.info['security'])
+    allowed search fields: ssidref, label, policy
+    """
+    if isinstance(info, dict):
+        security = info['security']
+    elif isinstance(info, list):
+        security = sxp.child_value(info, 'security')
+    if not security:
+        if field == 'ssidref':
+            #return default ssid
+            return 0
+        else:
+            err("Security information not found in info struct.")
+
+    if field == 'ssidref':
+        search = 'ssidref'
+    elif field in ['policy', 'label']:
+            search = 'access_control'
+    else:
+        err("Illegal field in get_security_info.")
+
+    for idx in range(0, len(security)):
+        if search != security[idx][0]:
+            continue
+        if search == 'ssidref':
+            return int(security[idx][1])
+        else:
+            for aidx in range(0, len(security[idx])):
+                if security[idx][aidx][0] == field:
+                    return str(security[idx][aidx][1])
+
+    if search == 'ssidref':
+        return 0
+    else:
+        return None
+
+
+
+def get_security_printlabel(info):
+    """retrieves printable security label from self.info['security']),
+    preferably the label name and otherwise (if label is not specified
+    in config and cannot be found in mapping file) a hex string of the
+    ssidref or none if both not available
+    """
+    try:
+        if not on():
+            return "INACTIVE"
+        if active_policy in ["DEFAULT"]:
+            return "DEFAULT"
+
+        printlabel = get_security_info(info, 'label')
+        if printlabel:
+            return printlabel
+        ssidref = get_security_info(info, 'ssidref')
+        if not ssidref:
+            return None
+        #try to translate ssidref to a label
+        result = ssidref2label(ssidref)
+        if not result:
+            printlabel = "0x%08x" % ssidref
+        else:
+            printlabel = result
+        return printlabel
+    except XSMError:
+        #don't throw an exception in xm list
+        return "ERROR"
+
+
+
+def getmapfile(policyname):
+    """
+    in: if policyname is None then the currently
+    active hypervisor policy is used
+    out: 1. primary policy, 2. secondary policy,
+    3. open file descriptor for mapping file, and
+    4. True if policy file is available, False otherwise
+    """
+    if not policyname:
+        policyname = active_policy
+    map_file_ok = False
+    primary = None
+    secondary = None
+    #strip last part of policy as file name part
+    policy_dir_list = string.split(policyname, ".")
+    policy_file = policy_dir_list.pop()
+    if len(policy_dir_list) > 0:
+        policy_dir = string.join(policy_dir_list, "/") + "/"
+    else:
+        policy_dir = ""
+
+    map_filename = policy_dir_prefix + "/" + policy_dir + policy_file + ".map"
+    # check if it is there, if not check if policy file is there
+    if not os.path.isfile(map_filename):
+        policy_filename =  policy_dir_prefix + "/" + policy_dir + policy_file + "-security_policy.xml"
+        if not os.path.isfile(policy_filename):
+            err("Policy file \'" + policy_filename + "\' not found.")
+        else:
+            err("Mapping file \'" + map_filename + "\' not found." +
+                " Use xm makepolicy to create it.")
+
+    f = open(map_filename)
+    for line in f:
+        if policy_reference_entry_re.match(line):
+            l = line.split()
+            if (len(l) == 2) and (l[1] == policyname):
+                map_file_ok = True
+        elif primary_entry_re.match(line):
+            l = line.split()
+            if len(l) == 2:
+                primary = l[1]
+        elif secondary_entry_re.match(line):
+            l = line.split()
+            if len(l) == 2:
+                secondary = l[1]
+    f.close()
+    f = open(map_filename)
+    if map_file_ok and primary and secondary:
+        return (primary, secondary, f, True)
+    else:
+        err("Mapping file inconsistencies found. Try makepolicy to create a new one.")
+
+
+
+def ssidref2label(ssidref_var):
+    """
+    returns labelname corresponding to ssidref;
+    maps current policy to default directory
+    to find mapping file
+    """
+    #1. translated permitted input formats
+    if isinstance(ssidref_var, str):
+        ssidref_var.strip()
+        if ssidref_var[0:2] == "0x":
+            ssidref = int(ssidref_var[2:], 16)
+        else:
+            ssidref = int(ssidref_var)
+    elif isinstance(ssidref_var, int):
+        ssidref = ssidref_var
+    else:
+        err("Instance type of ssidref not supported (must be of type 'str' or 'int')")
+
+    (primary, secondary, f, pol_exists) = getmapfile(None)
+    if not f:
+        if (pol_exists):
+            err("Mapping file for policy \'" + policyname + "\' not found.\n" +
+                "Please use makepolicy command to create mapping file!")
+        else:
+            err("Policy file for \'" + active_policy + "\' not found.")
+
+    #2. get labelnames for both ssidref parts
+    pri_ssid = ssidref & 0xffff
+    sec_ssid = ssidref >> 16
+    pri_null_ssid = NULL_SSIDREF & 0xffff
+    sec_null_ssid = NULL_SSIDREF >> 16
+    pri_labels = []
+    sec_labels = []
+    labels = []
+
+    for line in f:
+        l = line.split()
+        if (len(l) < 5) or (l[0] != "LABEL->SSID"):
+            continue
+        if primary and (l[2] == primary) and (int(l[4], 16) == pri_ssid):
+            pri_labels.append(l[3])
+        if secondary and (l[2] == secondary) and (int(l[4], 16) == sec_ssid):
+            sec_labels.append(l[3])
+    f.close()
+
+    #3. get the label that is in both lists (combination must be a single label)
+    if (primary == "CHWALL") and (pri_ssid == pri_null_ssid) and (sec_ssid != sec_null_ssid):
+        labels = sec_labels
+    elif (secondary == "CHWALL") and (pri_ssid != pri_null_ssid) and (sec_ssid == sec_null_ssid):
+        labels = pri_labels
+    elif secondary == "NULL":
+        labels = pri_labels
+    else:
+        for i in pri_labels:
+            for j in sec_labels:
+                if (i==j):
+                    labels.append(i)
+    if len(labels) != 1:
+        err("Label for ssidref \'" +  str(ssidref) +
+            "\' unknown or not unique in policy \'" + active_policy + "\'")
+
+    return labels[0]
+
+
+
+def label2ssidref(labelname, policyname, type):
+    """
+    returns ssidref corresponding to labelname;
+    maps current policy to default directory
+    to find mapping file    """
+
+    if policyname in ['NULL', 'INACTIVE', 'DEFAULT']:
+        err("Cannot translate labels for \'" + policyname + "\' policy.")
+
+    allowed_types = ['ANY']
+    if type == 'dom':
+        allowed_types.append('VM')
+    elif type == 'res':
+        allowed_types.append('RES')
+    else:
+        err("Invalid type.  Must specify 'dom' or 'res'.")
+
+    (primary, secondary, f, pol_exists) = getmapfile(policyname)
+
+    #2. get labelnames for ssidref parts and find a common label
+    pri_ssid = []
+    sec_ssid = []
+    for line in f:
+        l = line.split()
+        if (len(l) < 5) or (l[0] != "LABEL->SSID"):
+            continue
+        if primary and (l[1] in allowed_types) and (l[2] == primary) and (l[3] == labelname):
+            pri_ssid.append(int(l[4], 16))
+        if secondary and (l[1] in allowed_types) and (l[2] == secondary) and (l[3] == labelname):
+            sec_ssid.append(int(l[4], 16))
+    f.close()
+    if (type == 'res') and (primary == "CHWALL") and (len(pri_ssid) == 0):
+        pri_ssid.append(NULL_SSIDREF)
+    elif (type == 'res') and (secondary == "CHWALL") and (len(sec_ssid) == 0):
+        sec_ssid.append(NULL_SSIDREF)
+
+    #3. sanity check and composition of ssidref
+    if (len(pri_ssid) == 0) or ((len(sec_ssid) == 0) and (secondary != "NULL")):
+        err("Label \'" + labelname + "\' not found.")
+    elif (len(pri_ssid) > 1) or (len(sec_ssid) > 1):
+        err("Label \'" + labelname + "\' not unique in policy (policy error)")
+    if secondary == "NULL":
+        return pri_ssid[0]
+    else:
+        return (sec_ssid[0] << 16) | pri_ssid[0]
+
+
+
+def refresh_ssidref(config):
+    """
+    looks up ssidref from security field
+    and refreshes the value if label exists
+    """
+    #called by dom0, policy could have changed after xen.utils.security was initialized
+    refresh_security_policy()
+
+    security = None
+    if isinstance(config, dict):
+        security = config['security']
+    elif isinstance(config, list):
+        security = sxp.child_value(config, 'security')
+    else:
+        err("Instance type of config parameter not supported.")
+    if not security:
+        #nothing to do (no security label attached)
+        return config
+
+    policyname = None
+    labelname = None
+    # compose new security field
+    for idx in range(0, len(security)):
+        if security[idx][0] == 'ssidref':
+            security.pop(idx)
+            break
+        elif security[idx][0] == 'access_control':
+            for jdx in [1, 2]:
+                if security[idx][jdx][0] == 'label':
+                    labelname = security[idx][jdx][1]
+                elif security[idx][jdx][0] == 'policy':
+                    policyname = security[idx][jdx][1]
+                else:
+                    err("Illegal field in access_control")
+    #verify policy is correct
+    if active_policy != policyname:
+        err("Policy \'" + policyname + "\' in label does not match active policy \'"
+            + active_policy +"\'!")
+
+    new_ssidref = label2ssidref(labelname, policyname, 'dom')
+    if not new_ssidref:
+        err("SSIDREF refresh failed!")
+
+    security.append([ 'ssidref',str(new_ssidref)])
+    security = ['security', security ]
+
+    for idx in range(0,len(config)):
+        if config[idx][0] == 'security':
+            config.pop(idx)
+            break
+        config.append(security)
+
+
+
+def get_ssid(domain):
+    """
+    enables domains to retrieve the label / ssidref of a running domain
+    """
+    if not on():
+        err("No policy active.")
+
+    if isinstance(domain, str):
+        domain_int = int(domain)
+    elif isinstance(domain, int):
+        domain_int = domain
+    else:
+        err("Illegal parameter type.")
+    try:
+        ssid_info = acm.getssid(int(domain_int))
+    except:
+        err("Cannot determine security information.")
+
+    if active_policy in ["DEFAULT"]:
+        label = "DEFAULT"
+    else:
+        label = ssidref2label(ssid_info["ssidref"])
+    return(ssid_info["policyreference"],
+           label,
+           ssid_info["policytype"],
+           ssid_info["ssidref"])
+
+
+
+def get_decision(arg1, arg2):
+    """
+    enables domains to retrieve access control decisions from
+    the hypervisor Access Control Module.
+    IN: args format = ['domid', id] or ['ssidref', ssidref]
+    or ['access_control', ['policy', policy], ['label', label], ['type', type]]
+    """
+
+    if not on():
+        err("No policy active.")
+
+    #translate labels before calling low-level function
+    if arg1[0] == 'access_control':
+        if (arg1[1][0] != 'policy') or (arg1[2][0] != 'label') or (arg1[3][0] != 'type'):
+            err("Argument type not supported.")
+        ssidref = label2ssidref(arg1[2][1], arg1[1][1], arg1[3][1])
+        arg1 = ['ssidref', str(ssidref)]
+    if arg2[0] == 'access_control':
+        if (arg2[1][0] != 'policy') or (arg2[2][0] != 'label') or (arg2[3][0] != 'type'):
+            err("Argument type not supported.")
+        ssidref = label2ssidref(arg2[2][1], arg2[1][1], arg2[3][1])
+        arg2 = ['ssidref', str(ssidref)]
+
+    # accept only int or string types for domid and ssidref
+    if isinstance(arg1[1], int):
+        arg1[1] = str(arg1[1])
+    if isinstance(arg2[1], int):
+        arg2[1] = str(arg2[1])
+    if not isinstance(arg1[1], str) or not isinstance(arg2[1], str):
+        err("Invalid id or ssidref type, string or int required")
+
+    try:
+        decision = acm.getdecision(arg1[0], arg1[1], arg2[0], arg2[1])
+    except:
+        err("Cannot determine decision.")
+
+    if decision:
+        return decision
+    else:
+        err("Cannot determine decision (Invalid parameter).")
+
+
+
+def make_policy(policy_name):
+    policy_file = string.join(string.split(policy_name, "."), "/")
+    if not os.path.isfile(policy_dir_prefix + "/" + policy_file + "-security_policy.xml"):
+        err("Unknown policy \'" + policy_name + "\'")
+
+    (ret, output) = commands.getstatusoutput(xensec_xml2bin + " -d " + policy_dir_prefix + " " + policy_file)
+    if ret:
+        err("Creating policy failed:\n" + output)
+
+
+
+def load_policy(policy_name):
+    global active_policy
+    policy_file = policy_dir_prefix + "/" + string.join(string.split(policy_name, "."), "/")
+    if not os.path.isfile(policy_file + ".bin"):
+        if os.path.isfile(policy_file + "-security_policy.xml"):
+            err("Binary file does not exist." +
+                "Please use makepolicy to build the policy binary.")
+        else:
+            err("Unknown Policy " + policy_name)
+
+    #require this policy to be the first or the same as installed
+    if active_policy not in ['DEFAULT', policy_name]:
+        err("Active policy \'" + active_policy +
+            "\' incompatible with new policy \'" + policy_name + "\'")
+    (ret, output) = commands.getstatusoutput(xensec_tool + " loadpolicy " + policy_file + ".bin")
+    if ret:
+        err("Loading policy failed:\n" + output)
+    else:
+        # refresh active policy
+        refresh_security_policy()
+
+
+
+def dump_policy():
+    if active_policy in ['NULL', 'INACTIVE']:
+        err("\'" + active_policy + "\' policy. Nothing to dump.")
+
+    (ret, output) = commands.getstatusoutput(xensec_tool + " getpolicy")
+    if ret:
+       err("Dumping hypervisor policy failed:\n" + output)
+    print output
+
+
+
+def list_labels(policy_name, condition):
+    if (not policy_name) and (active_policy) in ["NULL", "INACTIVE", "DEFAULT"]:
+        err("Current policy \'" + active_policy + "\' has no labels defined.\n")
+
+    (primary, secondary, f, pol_exists) = getmapfile(policy_name)
+    if not f:
+        if pol_exists:
+            err("Cannot find mapfile for policy \'" + policy_name +
+                "\'.\nPlease use makepolicy to create mapping file.")
+        else:
+            err("Unknown policy \'" + policy_name + "\'")
+
+    labels = []
+    for line in f:
+        if condition.match(line):
+            label = line.split()[3]
+            if label not in labels:
+                labels.append(label)
+    return labels
+
+
+def get_res_label(resource):
+    """Returns resource label information (label, policy) if it exists.
+       Otherwise returns null label and policy.
+    """
+    def default_res_label():
+        ssidref = NULL_SSIDREF
+        if on():
+            label = ssidref2label(ssidref)
+        else:
+            label = None
+        return (label, 'NULL')
+
+    (label, policy) = default_res_label()
+
+    # load the resource label file
+    res_label_cache = {}
+    try:
+        res_label_cache = dictio.dict_read("resources", res_label_filename)
+    except:
+        log.info("Resource label file not found.")
+        return default_res_label()
+
+    # find the resource information
+    if res_label_cache.has_key(resource):
+        (policy, label) = res_label_cache[resource]
+
+    return (label, policy)
+
+
+def get_res_security_details(resource):
+    """Returns the (label, ssidref, policy) associated with a given
+       resource from the global resource label file.
+    """
+    def default_security_details():
+        ssidref = NULL_SSIDREF
+        if on():
+            label = ssidref2label(ssidref)
+        else:
+            label = None
+        policy = active_policy
+        return (label, ssidref, policy)
+
+    (label, ssidref, policy) = default_security_details()
+
+    # find the entry associated with this resource
+    (label, policy) = get_res_label(resource)
+    if policy == 'NULL':
+        log.info("Resource label for "+resource+" not in file, using DEFAULT.")
+        return default_security_details()
+
+    # is this resource label for the running policy?
+    if policy == active_policy:
+        ssidref = label2ssidref(label, policy, 'res')
+    else:
+        log.info("Resource label not for active policy, using DEFAULT.")
+        return default_security_details()
+
+    return (label, ssidref, policy)
+
+
+def unify_resname(resource):
+    """Makes all resource locations absolute. In case of physical
+    resources, '/dev/' is added to local file names"""
+
+    if not resource:
+        return resource
+
+    # sanity check on resource name
+    try:
+        (type, resfile) = resource.split(":", 1)
+    except:
+        err("Resource spec '%s' contains no ':' delimiter" % resource)
+
+    if type == "tap":
+        try:
+            (subtype, resfile) = resfile.split(":")
+        except:
+            err("Resource spec '%s' contains no tap subtype" % resource)
+
+    if type in ["phy", "tap"]:
+        if not resfile.startswith("/"):
+            resfile = "/dev/" + resfile
+
+    #file: resources must specified with absolute path
+    if (not resfile.startswith("/")) or (not os.path.exists(resfile)):
+        err("Invalid resource.")
+
+    # from here on absolute file names with resources
+    if type == "tap":
+        type = type + ":" + subtype
+    resource = type + ":" + resfile
+    return resource
+
+
+def res_security_check(resource, domain_label):
+    """Checks if the given resource can be used by the given domain
+       label.  Returns 1 if the resource can be used, otherwise 0.
+    """
+    rtnval = 1
+
+    # if security is on, ask the hypervisor for a decision
+    if on():
+        #build canonical resource name
+        resource = unify_resname(resource)
+
+        (label, ssidref, policy) = get_res_security_details(resource)
+        domac = ['access_control']
+        domac.append(['policy', active_policy])
+        domac.append(['label', domain_label])
+        domac.append(['type', 'dom'])
+        decision = get_decision(domac, ['ssidref', str(ssidref)])
+
+        # provide descriptive error messages
+        if decision == 'DENIED':
+            if label == ssidref2label(NULL_SSIDREF):
+                raise XSMError("Resource '"+resource+"' is not labeled")
+                rtnval = 0
+            else:
+                raise XSMError("Permission denied for resource '"+resource+"' because label '"+label+"' is not allowed")
+                rtnval = 0
+
+    # security is off, make sure resource isn't labeled
+    else:
+        # Note, we can't canonicalise the resource here, because people using
+        # xm without ACM are free to use relative paths.
+        (label, policy) = get_res_label(resource)
+        if policy != 'NULL':
+            raise XSMError("Security is off, but '"+resource+"' is labeled")
+            rtnval = 0
+
+    return rtnval
diff -r 8ae246493872 -r 12213351ff5d tools/python/xen/util/xsm/dummy/__init__.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/python/xen/util/xsm/dummy/__init__.py	Mon Jun 04 11:09:10 2007 -0400
@@ -0,0 +1,1 @@
+ 
diff -r 8ae246493872 -r 12213351ff5d tools/python/xen/util/xsm/dummy/dummy.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/python/xen/util/xsm/dummy/dummy.py	Mon Jun 04 11:09:10 2007 -0400
@@ -0,0 +1,53 @@
+import sys
+
+active_policy = "";
+NULL_SSIDREF = 0;
+
+def err(msg):
+    """Raise XSM-dummy exception.
+    """
+    sys.stderr.write("XSM-dummyError: " + msg + "\n")
+    raise XSMError(msg)
+
+def on():
+    return 0
+
+def get_security_info(info, field):
+    return 0
+
+def get_security_printlabel(info):
+    return 0
+
+def ssidref2label(ssidref):
+    return 0
+
+def label2ssidref(label, policy, type):
+    return 0
+
+def res_security_check(resource, domain_label):
+    return 1
+
+def get_res_security_details(resource):
+    return ("","","")
+
+def get_res_label(resource):
+    return ("","")
+
+def unify_resname(resource):
+    return ""
+
+def make_policy(policy_name):
+    return 1
+
+def load_policy(policy_name):
+    return 1
+
+def dump_policy():
+    print ""
+
+def list_labels(policy_name, condition):
+    labels = []
+    return labels
+
+def refresh_ssidref(config):
+    return config
diff -r 8ae246493872 -r 12213351ff5d tools/python/xen/util/xsm/flask/__init__.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/python/xen/util/xsm/flask/__init__.py	Mon Jun 04 11:09:10 2007 -0400
@@ -0,0 +1,1 @@
+ 
diff -r 8ae246493872 -r 12213351ff5d tools/python/xen/util/xsm/flask/flask.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/python/xen/util/xsm/flask/flask.py	Mon Jun 04 11:09:10 2007 -0400
@@ -0,0 +1,77 @@
+import sys
+from xen.lowlevel import flask
+from xen.xend import sxp
+
+active_policy = "";
+NULL_SSIDREF = 0;
+
+def err(msg):
+    """Raise XSM-Flask exception.
+    """
+    sys.stderr.write("XSM-FlaskError: " + msg + "\n")
+    raise XSMError(msg)
+
+def on():
+    return 1
+
+def get_security_info(info, field):
+    if isinstance(info, dict):
+        security = info['security']
+    elif isinstance(info, list):
+        security = sxp.child_value(info, 'security', )
+
+    for idx in range(0, len(security)):
+        if security[idx][0] != 'ssidref':
+            continue
+        if field == 'ssidref':
+            return int(security[idx][1])
+        elif field == 'label':
+            try:
+                return flask.flask_sid_to_context(int(security[idx][1]))
+            except:
+                return ""
+        else:
+            err("Field not found!")
+
+def get_security_printlabel(info):
+    return get_security_info(info, 'label')
+
+def ssidref2label(ssidref):
+    try:
+        return flask.flask_sid_to_context(ssidref)
+    except:
+        return ""
+
+def label2ssidref(label, policy, type):
+    try:
+        return flask.flask_context_to_sid(label)
+    except:
+        return ""
+
+def res_security_check(resource, domain_label):
+    return 1
+
+def get_res_security_details(resource):
+    return ("","","")
+
+def get_res_label(resource):
+    return ("","")
+
+def unify_resname(resource):
+    return ""
+
+def make_policy(policy_name):
+    return 1
+
+def load_policy(policy_name):
+    return 1
+
+def dump_policy():
+    print ""
+
+def list_labels(policy_name, condition):
+    labels = []
+    return labels
+
+def refresh_ssidref(config):
+    return config
diff -r 8ae246493872 -r 12213351ff5d tools/python/xen/util/xsm/xsm_core.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/python/xen/util/xsm/xsm_core.py	Mon Jun 04 11:09:10 2007 -0400
@@ -0,0 +1,13 @@
+import sys
+import xen.util.xsm.dummy.dummy as dummy
+
+class XSMError(Exception):
+    def __init__(self,value):
+        self.value = value
+    def __str__(self):
+        return repr(self.value)
+
+def xsm_init(self):
+    for op in dir(dummy):
+        if not hasattr(self, op):
+            setattr(self, op, getattr(dummy, op, None))
diff -r 8ae246493872 -r 12213351ff5d tools/python/xen/xend/XendDomain.py
--- a/tools/python/xen/xend/XendDomain.py	Mon Jun 04 11:06:52 2007 -0400
+++ b/tools/python/xen/xend/XendDomain.py	Mon Jun 04 11:09:10 2007 -0400
@@ -49,7 +49,8 @@ from xen.xend.XendAPIConstants import *
 
 from xen.xend.xenstore.xstransact import xstransact
 from xen.xend.xenstore.xswatch import xswatch
-from xen.util import mkdir, security
+from xen.util import mkdir
+import xen.util.xsm.xsm as security
 from xen.xend import uuid
 
 xc = xen.lowlevel.xc.xc()
diff -r 8ae246493872 -r 12213351ff5d tools/python/xen/xend/XendDomainInfo.py
--- a/tools/python/xen/xend/XendDomainInfo.py	Mon Jun 04 11:06:52 2007 -0400
+++ b/tools/python/xen/xend/XendDomainInfo.py	Mon Jun 04 11:09:10 2007 -0400
@@ -36,7 +36,7 @@ import xen.lowlevel.xc
 import xen.lowlevel.xc
 from xen.util import asserts
 from xen.util.blkif import blkdev_uname_to_file, blkdev_uname_to_taptype
-from xen.util import security
+import xen.util.xsm.xsm as security
 
 from xen.xend import balloon, sxp, uuid, image, arch, osdep
 from xen.xend import XendOptions, XendNode, XendConfig
diff -r 8ae246493872 -r 12213351ff5d tools/python/xen/xend/server/blkif.py
--- a/tools/python/xen/xend/server/blkif.py	Mon Jun 04 11:06:52 2007 -0400
+++ b/tools/python/xen/xend/server/blkif.py	Mon Jun 04 11:09:10 2007 -0400
@@ -20,7 +20,7 @@ import string
 import string
 
 from xen.util import blkif
-from xen.util import security
+import xen.util.xsm.xsm as security
 from xen.xend.XendError import VmError
 from xen.xend.server.DevController import DevController
 
diff -r 8ae246493872 -r 12213351ff5d tools/python/xen/xm/addlabel.py
--- a/tools/python/xen/xm/addlabel.py	Mon Jun 04 11:06:52 2007 -0400
+++ b/tools/python/xen/xm/addlabel.py	Mon Jun 04 11:09:10 2007 -0400
@@ -23,7 +23,7 @@ import sys
 import sys
 
 from xen.util import dictio
-from xen.util import security
+import xen.util.xsm.xsm as security
 from xen.xm.opts import OptionError
 
 def help():
diff -r 8ae246493872 -r 12213351ff5d tools/python/xen/xm/cfgbootpolicy.py
--- a/tools/python/xen/xm/cfgbootpolicy.py	Mon Jun 04 11:06:52 2007 -0400
+++ b/tools/python/xen/xm/cfgbootpolicy.py	Mon Jun 04 11:09:10 2007 -0400
@@ -26,11 +26,11 @@ import shutil
 import shutil
 import string
 import re
-from xen.util.security import err
-from xen.util.security import policy_dir_prefix, xen_title_re
-from xen.util.security import boot_filename, altboot_filename
-from xen.util.security import any_title_re, xen_kernel_re, any_module_re
-from xen.util.security import empty_line_re, binary_name_re, policy_name_re
+from xen.util.xsm.xsm import err
+from xen.util.xsm.xsm import policy_dir_prefix, xen_title_re
+from xen.util.xsm.xsm import boot_filename, altboot_filename
+from xen.util.xsm.xsm import any_title_re, xen_kernel_re, any_module_re
+from xen.util.xsm.xsm import empty_line_re, binary_name_re, policy_name_re
 from xen.xm.opts import OptionError
 
 def help():
diff -r 8ae246493872 -r 12213351ff5d tools/python/xen/xm/create.py
--- a/tools/python/xen/xm/create.py	Mon Jun 04 11:06:52 2007 -0400
+++ b/tools/python/xen/xm/create.py	Mon Jun 04 11:09:10 2007 -0400
@@ -33,7 +33,7 @@ import xen.xend.XendClient
 import xen.xend.XendClient
 from xen.xend.XendBootloader import bootloader
 from xen.util import blkif
-from xen.util import security
+import xen.util.xsm.xsm as security
 from xen.xm.main import serverType, SERVER_XEN_API, get_single_vm
 
 from xen.xm.opts import *
@@ -1225,7 +1225,7 @@ def config_security_check(config, verbos
             if verbose:
                 print "   %s: PERMITTED" % (resource)
 
-        except security.ACMError:
+        except security.XSMError:
             print "   %s: DENIED" % (resource)
             (res_label, res_policy) = security.get_res_label(resource)
             if not res_label:
@@ -1247,7 +1247,7 @@ def create_security_check(config):
                 passed = 1
         else:
             print "Checking resources: (skipped)"
-    except security.ACMError:
+    except security.XSMError:
         sys.exit(-1)
 
     return passed
@@ -1304,7 +1304,7 @@ def main(argv):
         map(lambda vm_ref: server.xenapi.VM.start(vm_ref, 0), vm_refs)
     elif not opts.is_xml:
         if not create_security_check(config):
-            raise security.ACMError(
+            raise security.XSMError(
                 'Security Configuration prevents domain from starting')
         dom = make_domain(opts, config)
         
diff -r 8ae246493872 -r 12213351ff5d tools/python/xen/xm/dry-run.py
--- a/tools/python/xen/xm/dry-run.py	Mon Jun 04 11:06:52 2007 -0400
+++ b/tools/python/xen/xm/dry-run.py	Mon Jun 04 11:09:10 2007 -0400
@@ -19,7 +19,7 @@
 """Tests the security settings for a domain and its resources.
 """
 import sys
-from xen.util import security
+import xen.util.xsm.xsm as security
 from xen.xm import create
 from xen.xend import sxp
 from xen.xm.opts import OptionError
diff -r 8ae246493872 -r 12213351ff5d tools/python/xen/xm/dumppolicy.py
--- a/tools/python/xen/xm/dumppolicy.py	Mon Jun 04 11:06:52 2007 -0400
+++ b/tools/python/xen/xm/dumppolicy.py	Mon Jun 04 11:09:10 2007 -0400
@@ -18,7 +18,7 @@
 """Display currently enforced policy (low-level hypervisor representation).
 """
 import sys
-from xen.util.security import ACMError, err, dump_policy
+from xen.util.xsm.xsm import XSMError, err, dump_policy
 from xen.xm.opts import OptionError
 
 def help():
diff -r 8ae246493872 -r 12213351ff5d tools/python/xen/xm/getlabel.py
--- a/tools/python/xen/xm/getlabel.py	Mon Jun 04 11:06:52 2007 -0400
+++ b/tools/python/xen/xm/getlabel.py	Mon Jun 04 11:09:10 2007 -0400
@@ -20,7 +20,7 @@
 """
 import sys, os, re
 from xen.util import dictio
-from xen.util import security
+import xen.util.xsm.xsm as security
 from xen.xm.opts import OptionError
 
 def help():
@@ -49,7 +49,7 @@ def get_resource_label(resource):
         label = access_control[resource][1]
         print "policy="+policy+",label="+label
     else:
-        raise security.ACMError("Resource not labeled")
+        raise security.XSMError("Resource not labeled")
 
 
 def get_domain_label(configfile):
@@ -82,7 +82,7 @@ def get_domain_label(configfile):
 
     # send error message if we didn't find anything
     if acline == "":
-        raise security.ACMError("Domain not labeled")
+        raise security.XSMError("Domain not labeled")
 
     # print out the label
     (title, data) = acline.split("=", 1)
diff -r 8ae246493872 -r 12213351ff5d tools/python/xen/xm/labels.py
--- a/tools/python/xen/xm/labels.py	Mon Jun 04 11:06:52 2007 -0400
+++ b/tools/python/xen/xm/labels.py	Mon Jun 04 11:09:10 2007 -0400
@@ -21,8 +21,8 @@ import sys
 import sys
 import traceback
 import string
-from xen.util.security import ACMError, err, list_labels, active_policy
-from xen.util.security import vm_label_re, res_label_re, all_label_re
+from xen.util.xsm.xsm import XSMError, err, list_labels, active_policy
+from xen.util.xsm.xsm import vm_label_re, res_label_re, all_label_re
 from xen.xm.opts import OptionError
 
 
@@ -68,7 +68,7 @@ def main(argv):
         for label in labels:
             print label
 
-    except ACMError:
+    except XSMError:
         sys.exit(-1)
     except:
         traceback.print_exc(limit = 1)
diff -r 8ae246493872 -r 12213351ff5d tools/python/xen/xm/loadpolicy.py
--- a/tools/python/xen/xm/loadpolicy.py	Mon Jun 04 11:06:52 2007 -0400
+++ b/tools/python/xen/xm/loadpolicy.py	Mon Jun 04 11:09:10 2007 -0400
@@ -20,7 +20,7 @@
 """
 import sys
 import traceback
-from xen.util.security import ACMError, err, load_policy
+from xen.util.xsm.xsm import XSMError, err, load_policy
 from xen.xm.opts import OptionError
 
 def help():
diff -r 8ae246493872 -r 12213351ff5d tools/python/xen/xm/main.py
--- a/tools/python/xen/xm/main.py	Mon Jun 04 11:06:52 2007 -0400
+++ b/tools/python/xen/xm/main.py	Mon Jun 04 11:09:10 2007 -0400
@@ -870,7 +870,7 @@ def parse_doms_info(info):
     # We're not supporting security stuff just yet via XenAPI
 
     if serverType != SERVER_XEN_API:
-        from xen.util import security
+        import xen.util.xsm.xsm as security
         parsed_info['seclabel'] = security.get_security_printlabel(info)
     else:
         parsed_info['seclabel'] = ""
@@ -931,16 +931,16 @@ def xm_brief_list(doms):
         print format % d
 
 def xm_label_list(doms):
-    print '%-32s %5s %5s %5s %5s %9s %-8s' % \
+    print '%-40s %3s %5s %5s %10s %9s %-10s' % \
           ('Name', 'ID', 'Mem', 'VCPUs', 'State', 'Time(s)', 'Label')
-    
+
     output = []
-    format = '%(name)-32s %(domid)5s %(mem)5d %(vcpus)5d %(state)10s ' \
-             '%(cpu_time)8.1f %(seclabel)9s'
+    format = '%(name)-40s %(domid)3s %(mem)5d %(vcpus)5d %(state)10s ' \
+             '%(cpu_time)8.1f %(seclabel)10s'
 
     if serverType != SERVER_XEN_API:
-        from xen.util import security
-        
+        import xen.util.xsm.xsm as security
+
         for dom in doms:
             d = parse_doms_info(dom)
 
@@ -2027,7 +2027,7 @@ def parse_block_configuration(args):
 
     if serverType != SERVER_XEN_API:
         # verify that policy permits attaching this resource
-        from xen.util import security
+        import xen.util.xsm.xsm as security
     
         if security.on():
             dominfo = server.xend.domain(dom)
@@ -2561,8 +2561,8 @@ def _run_cmd(cmd, cmd_name, args):
         err(str(e))
     except Exception, e:
         if serverType != SERVER_XEN_API:
-           from xen.util import security
-           if isinstance(e, security.ACMError):
+           import xen.util.xsm.xsm as security
+           if isinstance(e, security.XSMError):
                err(str(e))
                return False, 1
         print "Unexpected error:", sys.exc_info()[0]
diff -r 8ae246493872 -r 12213351ff5d tools/python/xen/xm/makepolicy.py
--- a/tools/python/xen/xm/makepolicy.py	Mon Jun 04 11:06:52 2007 -0400
+++ b/tools/python/xen/xm/makepolicy.py	Mon Jun 04 11:09:10 2007 -0400
@@ -19,7 +19,7 @@
 """
 import sys
 import traceback
-from xen.util.security import ACMError, err, make_policy
+from xen.util.xsm.xsm import XSMError, err, make_policy
 from xen.xm.opts import OptionError
 
 def usage():
diff -r 8ae246493872 -r 12213351ff5d tools/python/xen/xm/resources.py
--- a/tools/python/xen/xm/resources.py	Mon Jun 04 11:06:52 2007 -0400
+++ b/tools/python/xen/xm/resources.py	Mon Jun 04 11:09:10 2007 -0400
@@ -20,7 +20,7 @@
 """
 import sys
 from xen.util import dictio
-from xen.util import security
+import xen.util.xsm.xsm as security
 from xen.xm.opts import OptionError
 
 def help():
diff -r 8ae246493872 -r 12213351ff5d tools/python/xen/xm/rmlabel.py
--- a/tools/python/xen/xm/rmlabel.py	Mon Jun 04 11:06:52 2007 -0400
+++ b/tools/python/xen/xm/rmlabel.py	Mon Jun 04 11:09:10 2007 -0400
@@ -20,7 +20,7 @@
 """
 import sys, os, re
 from xen.util import dictio
-from xen.util import security
+import xen.util.xsm.xsm as security
 from xen.xm.opts import OptionError
 
 def help():
@@ -45,14 +45,14 @@ def rm_resource_label(resource):
     try:
         access_control = dictio.dict_read("resources", file)
     except:
-        raise security.ACMError("Resource file not found, cannot remove label!")
+        raise security.XSMError("Resource file not found, cannot remove label!")
 
     # remove the entry and update file
     if access_control.has_key(resource):
         del access_control[resource]
         dictio.dict_write(access_control, "resources", file)
     else:
-        raise security.ACMError("Resource not labeled")
+        raise security.XSMError("Resource not labeled")
 
 
 def rm_domain_label(configfile):
@@ -90,7 +90,7 @@ def rm_domain_label(configfile):
 
     # send error message if we didn't find anything to remove
     if not removed:
-        raise security.ACMError('Domain not labeled')
+        raise security.XSMError('Domain not labeled')
 
     # write the data back out to the file
     fd = open(file, "wb")

[-- Attachment #3: Type: text/plain, Size: 138 bytes --]

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xensource.com
http://lists.xensource.com/xen-devel

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2007-06-14 18:14 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2007-05-07 21:41 [Xense-devel][PATCH][2/4] Xen Securtiy Modules: FLASK George S. Coker, II
2007-05-07 23:24 ` Chris Wright
2007-05-08  3:15 ` Mark Williamson
2007-06-04 19:06 George S. Coker, II
2007-06-14 18:14 ` George S. Coker, II

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.