WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-changelog

[Xen-changelog] [xen-unstable] Xen Security Modules: FLASK

To: xen-changelog@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-changelog] [xen-unstable] Xen Security Modules: FLASK
From: Xen patchbot-unstable <patchbot-unstable@xxxxxxxxxxxxxxxxxxx>
Date: Fri, 07 Sep 2007 09:13:39 -0700
Delivery-date: Fri, 07 Sep 2007 09:19:26 -0700
Envelope-to: www-data@xxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-changelog-request@lists.xensource.com?subject=help>
List-id: BK change log <xen-changelog.lists.xensource.com>
List-post: <mailto:xen-changelog@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=unsubscribe>
Reply-to: xen-devel@xxxxxxxxxxxxxxxxxxx
Sender: xen-changelog-bounces@xxxxxxxxxxxxxxxxxxx
# HG changeset patch
# User kfraser@xxxxxxxxxxxxxxxxxxxxx
# Date 1188556278 -3600
# Node ID 6c8c934b235c39f821efdfe6a2af7d44e4e35aab
# Parent  96f64f4c42f043e3af2db369f4b9bdb9fcef017b
Xen Security Modules: FLASK
Signed-off-by: George Coker <gscoker@xxxxxxxxxxxxxx>
---
 Config.mk                                     |    8 
 xen/Rules.mk                                  |    4 
 xen/common/vsprintf.c                         |  236 +++
 xen/include/public/xsm/flask_op.h             |   45 
 xen/include/xen/lib.h                         |    4 
 xen/xsm/Makefile                              |    2 
 xen/xsm/flask/Makefile                        |    7 
 xen/xsm/flask/avc.c                           |  817 +++++++++++
 xen/xsm/flask/flask_op.c                      | 1079 +++++++++++++++
 xen/xsm/flask/hooks.c                         | 1159 ++++++++++++++++
 xen/xsm/flask/include/av_inherit.h            |    1 
 xen/xsm/flask/include/av_perm_to_string.h     |   99 +
 xen/xsm/flask/include/av_permissions.h        |  108 +
 xen/xsm/flask/include/avc.h                   |  106 +
 xen/xsm/flask/include/avc_ss.h                |   14 
 xen/xsm/flask/include/class_to_string.h       |   14 
 xen/xsm/flask/include/common_perm_to_string.h |    1 
 xen/xsm/flask/include/conditional.h           |   22 
 xen/xsm/flask/include/flask.h                 |   36 
 xen/xsm/flask/include/initial_sid_to_string.h |   18 
 xen/xsm/flask/include/objsec.h                |   33 
 xen/xsm/flask/include/security.h              |   83 +
 xen/xsm/flask/ss/Makefile                     |   11 
 xen/xsm/flask/ss/avtab.c                      |  471 ++++++
 xen/xsm/flask/ss/avtab.h                      |   85 +
 xen/xsm/flask/ss/conditional.c                |  546 +++++++
 xen/xsm/flask/ss/conditional.h                |   77 +
 xen/xsm/flask/ss/constraint.h                 |   61 
 xen/xsm/flask/ss/context.h                    |  110 +
 xen/xsm/flask/ss/ebitmap.c                    |  328 ++++
 xen/xsm/flask/ss/ebitmap.h                    |   79 +
 xen/xsm/flask/ss/hashtab.c                    |  181 ++
 xen/xsm/flask/ss/hashtab.h                    |   85 +
 xen/xsm/flask/ss/mls.c                        |  612 ++++++++
 xen/xsm/flask/ss/mls.h                        |   37 
 xen/xsm/flask/ss/mls_types.h                  |   58 
 xen/xsm/flask/ss/policydb.c                   | 1798 ++++++++++++++++++++++++++
 xen/xsm/flask/ss/policydb.h                   |  257 +++
 xen/xsm/flask/ss/services.c                   | 1657 +++++++++++++++++++++++
 xen/xsm/flask/ss/services.h                   |   15 
 xen/xsm/flask/ss/sidtab.c                     |  327 ++++
 xen/xsm/flask/ss/sidtab.h                     |   53 
 xen/xsm/flask/ss/symtab.c                     |   47 
 xen/xsm/flask/ss/symtab.h                     |   23 
 44 files changed, 10814 insertions(+)

diff -r 96f64f4c42f0 -r 6c8c934b235c Config.mk
--- a/Config.mk Fri Aug 31 11:21:35 2007 +0100
+++ b/Config.mk Fri Aug 31 11:31:18 2007 +0100
@@ -81,6 +81,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 96f64f4c42f0 -r 6c8c934b235c xen/Rules.mk
--- a/xen/Rules.mk      Fri Aug 31 11:21:35 2007 +0100
+++ b/xen/Rules.mk      Fri Aug 31 11:31:18 2007 +0100
@@ -58,6 +58,10 @@ ALL_OBJS-y               += $(BASEDIR)/a
 
 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
diff -r 96f64f4c42f0 -r 6c8c934b235c xen/common/vsprintf.c
--- a/xen/common/vsprintf.c     Fri Aug 31 11:21:35 2007 +0100
+++ b/xen/common/vsprintf.c     Fri Aug 31 11:31:18 2007 +0100
@@ -513,6 +513,223 @@ 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 +778,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 96f64f4c42f0 -r 6c8c934b235c xen/include/public/xsm/flask_op.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/include/public/xsm/flask_op.h Fri Aug 31 11:31:18 2007 +0100
@@ -0,0 +1,45 @@
+/*
+ *  This file contains the flask_op hypercall commands and definitions.
+ *
+ *  Author:  George Coker, <gscoker@xxxxxxxxxxxxxx>
+ *
+ *  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   cmd;
+    int   size;
+    char *buf;
+} flask_op_t;
+
+DEFINE_XEN_GUEST_HANDLE(flask_op_t);
+
+long do_flask_op (XEN_GUEST_HANDLE(xsm_op_t) u_flask_op);
+
+#endif
diff -r 96f64f4c42f0 -r 6c8c934b235c xen/include/xen/lib.h
--- a/xen/include/xen/lib.h     Fri Aug 31 11:21:35 2007 +0100
+++ b/xen/include/xen/lib.h     Fri Aug 31 11:31:18 2007 +0100
@@ -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 96f64f4c42f0 -r 6c8c934b235c xen/xsm/Makefile
--- a/xen/xsm/Makefile  Fri Aug 31 11:21:35 2007 +0100
+++ b/xen/xsm/Makefile  Fri Aug 31 11:31:18 2007 +0100
@@ -3,3 +3,5 @@ ifeq ($(XSM_ENABLE),y)
 ifeq ($(XSM_ENABLE),y)
 obj-y += dummy.o
 endif
+
+subdir-$(FLASK_ENABLE) += flask
diff -r 96f64f4c42f0 -r 6c8c934b235c xen/xsm/flask/Makefile
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/Makefile    Fri Aug 31 11:31:18 2007 +0100
@@ -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 96f64f4c42f0 -r 6c8c934b235c xen/xsm/flask/avc.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/avc.c       Fri Aug 31 11:31:18 2007 +0100
@@ -0,0 +1,817 @@
+/*
+ * Implementation of the kernel access vector cache (AVC).
+ *
+ * Authors:  Stephen Smalley, <sds@xxxxxxxxxxxxxx>
+ *           James Morris <jmorris@xxxxxxxxxx>
+ *
+ * Update:   KaiGai, Kohei <kaigai@xxxxxxxxxxxxx>
+ *     Replaced the avc_lock spinlock by RCU.
+ *
+ * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@xxxxxxxxxx>
+ *
+ *    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@xxxxxxxxxxxxxx> */
+ 
+#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 96f64f4c42f0 -r 6c8c934b235c xen/xsm/flask/flask_op.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/flask_op.c  Fri Aug 31 11:31:18 2007 +0100
@@ -0,0 +1,1079 @@
+/*
+ *  This file contains the flask_op hypercall and associated functions.
+ *
+ *  Author:  George Coker, <gscoker@xxxxxxxxxxxxxx>
+ *
+ *  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/xsm/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(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 ( op->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 96f64f4c42f0 -r 6c8c934b235c xen/xsm/flask/hooks.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/hooks.c     Fri Aug 31 11:31:18 2007 +0100
@@ -0,0 +1,1159 @@
+ /*
+ *  This file contains the Flask hook function implementations for Xen.
+ *
+ *  Author:  George Coker, <gscoker@xxxxxxxxxxxxxx>
+ *
+ *    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/xsm/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(struct page_info *page, u32 *sid)
+{
+    int rc = 0;
+    struct domain *d;
+    struct domain_security_struct *dsec;
+    unsigned long mfn;
+
+    d = page_get_owner(page);
+
+    if ( d == NULL )
+    {
+        mfn = page_to_mfn(page);
+        rc = security_iomem_sid(mfn, sid);
+        return rc;
+    }
+
+    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;
+    }
+
+    return rc;
+}
+
+static int get_mfn_sid(unsigned long mfn, u32 *sid)
+{
+    int rc = 0;
+    struct page_info *page;
+
+    if ( mfn_valid(mfn) )
+    {
+        /*mfn is valid if this is a page that Xen is tracking!*/
+        page = mfn_to_page(mfn);        
+        rc = get_page_sid(page, sid);
+    }
+    else
+    {
+        /*Possibly an untracked IO page?*/
+        rc = security_iomem_sid(mfn, sid);
+    }
+
+    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_mfn_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, struct page_info *page)
+{
+    int rc = 0;
+    u32 sid;
+    struct domain_security_struct *dsec;
+    dsec = d->ssid;
+
+    rc = get_page_sid(page, &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_mfn_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(struct page_info *page)
+{
+    int rc = 0;
+    u32 tsid;
+    struct domain_security_struct *dsec;
+
+    dsec = current->domain->ssid;
+
+    rc = get_page_sid(page, &tsid);
+    if ( rc )
+        return rc;
+
+    return avc_has_perm(dsec->sid, tsid, 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_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 *d)
+{
+    return domain_has_perm(current->domain, d, 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_mfn_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_mfn_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,
+    .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 96f64f4c42f0 -r 6c8c934b235c 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        Fri Aug 31 11:31:18 2007 +0100
@@ -0,0 +1,1 @@
+/* This file is automatically generated.  Do not edit. */
diff -r 96f64f4c42f0 -r 6c8c934b235c 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 Fri Aug 31 11:31:18 2007 +0100
@@ -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 96f64f4c42f0 -r 6c8c934b235c 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    Fri Aug 31 11:31:18 2007 +0100
@@ -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 96f64f4c42f0 -r 6c8c934b235c xen/xsm/flask/include/avc.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/include/avc.h       Fri Aug 31 11:31:18 2007 +0100
@@ -0,0 +1,106 @@
+/*
+ * Access vector cache interface for object managers.
+ *
+ * Author : Stephen Smalley, <sds@xxxxxxxxxxxxxx>
+ */
+ 
+/* Ported to Xen 3.0, George Coker, <gscoker@xxxxxxxxxxxxxx> */
+
+#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 96f64f4c42f0 -r 6c8c934b235c 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    Fri Aug 31 11:31:18 2007 +0100
@@ -0,0 +1,14 @@
+/*
+ * Access vector cache interface for the security server.
+ *
+ * Author : Stephen Smalley, <sds@xxxxxxxxxxxxxx>
+ */
+#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 96f64f4c42f0 -r 6c8c934b235c 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   Fri Aug 31 11:31:18 2007 +0100
@@ -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 96f64f4c42f0 -r 6c8c934b235c 
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     Fri Aug 31 11:31:18 
2007 +0100
@@ -0,0 +1,1 @@
+/* This file is automatically generated.  Do not edit. */
diff -r 96f64f4c42f0 -r 6c8c934b235c xen/xsm/flask/include/conditional.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/include/conditional.h       Fri Aug 31 11:31:18 2007 +0100
@@ -0,0 +1,22 @@
+/*
+ * Interface to booleans in the security server. This is exported
+ * for the selinuxfs.
+ *
+ * Author: Karl MacMillan <kmacmillan@xxxxxxxxxx>
+ *
+ * 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 96f64f4c42f0 -r 6c8c934b235c xen/xsm/flask/include/flask.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/include/flask.h     Fri Aug 31 11:31:18 2007 +0100
@@ -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 96f64f4c42f0 -r 6c8c934b235c 
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     Fri Aug 31 11:31:18 
2007 +0100
@@ -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 96f64f4c42f0 -r 6c8c934b235c xen/xsm/flask/include/objsec.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/include/objsec.h    Fri Aug 31 11:31:18 2007 +0100
@@ -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@xxxxxxxxxxxxxx>
+ *
+ *    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 96f64f4c42f0 -r 6c8c934b235c xen/xsm/flask/include/security.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/include/security.h  Fri Aug 31 11:31:18 2007 +0100
@@ -0,0 +1,83 @@
+/*
+ * Security server interface.
+ *
+ * Author : Stephen Smalley, <sds@xxxxxxxxxxxxxx>
+ *
+ */
+
+/* Ported to Xen 3.0, George Coker, <gscoker@xxxxxxxxxxxxxx> */
+
+#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 96f64f4c42f0 -r 6c8c934b235c xen/xsm/flask/ss/Makefile
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/ss/Makefile Fri Aug 31 11:31:18 2007 +0100
@@ -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 96f64f4c42f0 -r 6c8c934b235c xen/xsm/flask/ss/avtab.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/ss/avtab.c  Fri Aug 31 11:31:18 2007 +0100
@@ -0,0 +1,471 @@
+/*
+ * Implementation of the access vector table type.
+ *
+ * Author : Stephen Smalley, <sds@xxxxxxxxxxxxxx>
+ */
+
+/* Updated: Frank Mayer <mayerf@xxxxxxxxxx> and Karl MacMillan 
<kmacmillan@xxxxxxxxxx>
+ *
+ *     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@xxxxxxxxxxxxxx> */
+
+#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 96f64f4c42f0 -r 6c8c934b235c xen/xsm/flask/ss/avtab.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/ss/avtab.h  Fri Aug 31 11:31:18 2007 +0100
@@ -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@xxxxxxxxxxxxxx>
+ */
+
+/* Updated: Frank Mayer <mayerf@xxxxxxxxxx> and Karl MacMillan 
<kmacmillan@xxxxxxxxxx>
+ *
+ *     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@xxxxxxxxxxxxxx> */
+
+#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 96f64f4c42f0 -r 6c8c934b235c xen/xsm/flask/ss/conditional.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/ss/conditional.c    Fri Aug 31 11:31:18 2007 +0100
@@ -0,0 +1,546 @@
+/* Authors: Karl MacMillan <kmacmillan@xxxxxxxxxx>
+ *          Frank Mayer <mayerf@xxxxxxxxxx>
+ *
+ * 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@xxxxxxxxxxxxxx> */
+
+#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 96f64f4c42f0 -r 6c8c934b235c xen/xsm/flask/ss/conditional.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/ss/conditional.h    Fri Aug 31 11:31:18 2007 +0100
@@ -0,0 +1,77 @@
+/* Authors: Karl MacMillan <kmacmillan@xxxxxxxxxx>
+ *          Frank Mayer <mayerf@xxxxxxxxxx>
+ *
+ * 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 96f64f4c42f0 -r 6c8c934b235c xen/xsm/flask/ss/constraint.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/ss/constraint.h     Fri Aug 31 11:31:18 2007 +0100
@@ -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@xxxxxxxxxxxxxx>
+ */
+#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 96f64f4c42f0 -r 6c8c934b235c xen/xsm/flask/ss/context.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/ss/context.h        Fri Aug 31 11:31:18 2007 +0100
@@ -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@xxxxxxxxxxxxxx>
+ */
+ 
+/* Ported to Xen 3.0, George Coker, <gscoker@xxxxxxxxxxxxxx> */
+ 
+#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 96f64f4c42f0 -r 6c8c934b235c xen/xsm/flask/ss/ebitmap.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/ss/ebitmap.c        Fri Aug 31 11:31:18 2007 +0100
@@ -0,0 +1,328 @@
+/*
+ * Implementation of the extensible bitmap type.
+ *
+ * Author : Stephen Smalley, <sds@xxxxxxxxxxxxxx>
+ */
+
+/* Ported to Xen 3.0, George Coker, <gscoker@xxxxxxxxxxxxxx> */
+
+#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 96f64f4c42f0 -r 6c8c934b235c xen/xsm/flask/ss/ebitmap.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/ss/ebitmap.h        Fri Aug 31 11:31:18 2007 +0100
@@ -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@xxxxxxxxxxxxxx>
+ */
+#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 96f64f4c42f0 -r 6c8c934b235c xen/xsm/flask/ss/hashtab.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/ss/hashtab.c        Fri Aug 31 11:31:18 2007 +0100
@@ -0,0 +1,181 @@
+/*
+ * Implementation of the hash table type.
+ *
+ * Author : Stephen Smalley, <sds@xxxxxxxxxxxxxx>
+ */
+
+/* Ported to Xen 3.0, George Coker, <gscoker@xxxxxxxxxxxxxx> */
+
+#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 96f64f4c42f0 -r 6c8c934b235c xen/xsm/flask/ss/hashtab.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/ss/hashtab.h        Fri Aug 31 11:31:18 2007 +0100
@@ -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@xxxxxxxxxxxxxx>
+ */
+#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 96f64f4c42f0 -r 6c8c934b235c xen/xsm/flask/ss/mls.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/ss/mls.c    Fri Aug 31 11:31:18 2007 +0100
@@ -0,0 +1,612 @@
+/*
+ * Implementation of the multi-level security (MLS) policy.
+ *
+ * Author : Stephen Smalley, <sds@xxxxxxxxxxxxxx>
+ */
+
+/*
+ * Updated: Trusted Computer Solutions, Inc. <dgoeddel@xxxxxxxxxxxxx>
+ *
+ *    Support for enhanced MLS infrastructure.
+ *
+ * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
+ */
+
+/* Ported to Xen 3.0, George Coker, <gscoker@xxxxxxxxxxxxxx> */
+
+#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 96f64f4c42f0 -r 6c8c934b235c xen/xsm/flask/ss/mls.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/ss/mls.h    Fri Aug 31 11:31:18 2007 +0100
@@ -0,0 +1,37 @@
+/*
+ * Multi-level security (MLS) policy operations.
+ *
+ * Author : Stephen Smalley, <sds@xxxxxxxxxxxxxx>
+ */
+/*
+ * Updated: Trusted Computer Solutions, Inc. <dgoeddel@xxxxxxxxxxxxx>
+ *
+ *    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 96f64f4c42f0 -r 6c8c934b235c 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      Fri Aug 31 11:31:18 2007 +0100
@@ -0,0 +1,58 @@
+/*
+ * Type definitions for the multi-level security (MLS) policy.
+ *
+ * Author : Stephen Smalley, <sds@xxxxxxxxxxxxxx>
+ */
+/*
+ * Updated: Trusted Computer Solutions, Inc. <dgoeddel@xxxxxxxxxxxxx>
+ *
+ *    Support for enhanced MLS infrastructure.
+ *
+ * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
+ */
+
+/* Ported to Xen 3.0, George Coker, <gscoker@xxxxxxxxxxxxxx> */
+
+#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 96f64f4c42f0 -r 6c8c934b235c xen/xsm/flask/ss/policydb.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/ss/policydb.c       Fri Aug 31 11:31:18 2007 +0100
@@ -0,0 +1,1798 @@
+/*
+ * Implementation of the policy database.
+ *
+ * Author : Stephen Smalley, <sds@xxxxxxxxxxxxxx>
+ */
+
+/*
+ * Updated: Trusted Computer Solutions, Inc. <dgoeddel@xxxxxxxxxxxxx>
+ *
+ *    Support for enhanced MLS infrastructure.
+ *
+ * Updated: Frank Mayer <mayerf@xxxxxxxxxx> and Karl MacMillan 
<kmacmillan@xxxxxxxxxx>
+ *
+ *     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@xxxxxxxxxxxxxx> */
+
+#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 96f64f4c42f0 -r 6c8c934b235c xen/xsm/flask/ss/policydb.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/ss/policydb.h       Fri Aug 31 11:31:18 2007 +0100
@@ -0,0 +1,257 @@
+/*
+ * A policy database (policydb) specifies the
+ * configuration data for the security policy.
+ *
+ * Author : Stephen Smalley, <sds@xxxxxxxxxxxxxx>
+ */
+
+/*
+ * Updated: Trusted Computer Solutions, Inc. <dgoeddel@xxxxxxxxxxxxx>
+ *
+ *    Support for enhanced MLS infrastructure.
+ *
+ * Updated: Frank Mayer <mayerf@xxxxxxxxxx> and Karl MacMillan 
<kmacmillan@xxxxxxxxxx>
+ *
+ *     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@xxxxxxxxxxxxxx> */
+
+#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 96f64f4c42f0 -r 6c8c934b235c xen/xsm/flask/ss/services.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/ss/services.c       Fri Aug 31 11:31:18 2007 +0100
@@ -0,0 +1,1657 @@
+/*
+ * Implementation of the security services.
+ *
+ * Authors : Stephen Smalley, <sds@xxxxxxxxxxxxxx>
+ *           James Morris <jmorris@xxxxxxxxxx>
+ *
+ * Updated: Trusted Computer Solutions, Inc. <dgoeddel@xxxxxxxxxxxxx>
+ *
+ *    Support for enhanced MLS infrastructure.
+ *
+ * Updated: Frank Mayer <mayerf@xxxxxxxxxx> and Karl MacMillan 
<kmacmillan@xxxxxxxxxx>
+ *
+ *     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@xxxxxxxxxx>
+ *    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@xxxxxxxxxxxxxx> */
+
+#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;

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

<Prev in Thread] Current Thread [Next in Thread>
  • [Xen-changelog] [xen-unstable] Xen Security Modules: FLASK, Xen patchbot-unstable <=