[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

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



# 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


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.