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

[Xen-changelog] [xen-unstable] Update Xen Flask module to policy.24.



# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1250688172 -3600
# Node ID 001a99da12947d3e2caadafc7458e40a8ba92fbf
# Parent  b79da5f5ffe7d1463176a6975e155f92ac3b10af
Update Xen Flask module to policy.24.

This is a back-port of the latest SELinux code to Xen, adjusted
for Xen coding style and interfaces.  Unneeded functionality such
as most object context config data, handle_unknown, MLS field
defaulting, etc has been omitted.

Signed-off-by:  Stephen D. Smalley <sds@xxxxxxxxxxxxx>
Signed-off-by: George S. Coker, II <gscoker@xxxxxxxxxxxxxx>
---
 tools/flask/policy/Makefile      |    2 
 xen/xsm/flask/avc.c              |  264 +++++++++--------
 xen/xsm/flask/flask_op.c         |    2 
 xen/xsm/flask/include/avc_ss.h   |   23 +
 xen/xsm/flask/include/security.h |   14 
 xen/xsm/flask/ss/avtab.c         |  144 ++++++---
 xen/xsm/flask/ss/avtab.h         |   20 -
 xen/xsm/flask/ss/conditional.c   |   23 -
 xen/xsm/flask/ss/conditional.h   |    2 
 xen/xsm/flask/ss/context.h       |   33 +-
 xen/xsm/flask/ss/ebitmap.c       |  231 +++++++--------
 xen/xsm/flask/ss/ebitmap.h       |   94 ++++--
 xen/xsm/flask/ss/hashtab.c       |   10 
 xen/xsm/flask/ss/hashtab.h       |   12 
 xen/xsm/flask/ss/mls.c           |  351 ++++++++--------------
 xen/xsm/flask/ss/mls.h           |    6 
 xen/xsm/flask/ss/policydb.c      |  415 +++++++++++++++++++++++---
 xen/xsm/flask/ss/policydb.h      |   31 +-
 xen/xsm/flask/ss/services.c      |  600 +++++++++++++++++++++++++++------------
 xen/xsm/flask/ss/sidtab.c        |    2 
 xen/xsm/flask/ss/symtab.c        |    8 
 21 files changed, 1496 insertions(+), 791 deletions(-)

diff -r b79da5f5ffe7 -r 001a99da1294 tools/flask/policy/Makefile
--- a/tools/flask/policy/Makefile       Wed Aug 19 14:22:15 2009 +0100
+++ b/tools/flask/policy/Makefile       Wed Aug 19 14:22:52 2009 +0100
@@ -20,7 +20,7 @@
 # By default, checkpolicy will create the highest
 # version policy it supports.  Setting this will
 # override the version.
-OUTPUT_POLICY = 20
+#OUTPUT_POLICY = 20
 
 # Policy Type
 # strict, targeted,
diff -r b79da5f5ffe7 -r 001a99da1294 xen/xsm/flask/avc.c
--- a/xen/xsm/flask/avc.c       Wed Aug 19 14:22:15 2009 +0100
+++ b/xen/xsm/flask/avc.c       Wed Aug 19 14:22:52 2009 +0100
@@ -32,12 +32,7 @@
 #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[] = {
+static const struct av_perm_to_string av_perm_to_string[] = {
 #define S_(c, v, s) { c, v, s },
 #include "av_perm_to_string.h"
 #undef S_
@@ -57,15 +52,20 @@ static const char *class_to_string[] = {
 #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 },
+static const struct av_inherit av_inherit[] = {
+#define S_(c, i, b) { .tclass = c, .common_pts = common_##i##_perm_to_string, \
+                     .common_base = b },
 #include "av_inherit.h"
 #undef S_
+};
+
+const struct selinux_class_perm selinux_class_perm = {
+       .av_perm_to_string = av_perm_to_string,
+       .av_pts_len = ARRAY_SIZE(av_perm_to_string),
+       .class_to_string = class_to_string,
+       .cts_len = ARRAY_SIZE(class_to_string),
+       .av_inherit = av_inherit,
+       .av_inherit_len = ARRAY_SIZE(av_inherit)
 };
 
 #define AVC_CACHE_SLOTS            512
@@ -86,17 +86,16 @@ struct avc_entry {
     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 hlist_node   list; /* anchored in avc_cache->slots[i] */
     struct rcu_head     rhead;
 };
 
 struct avc_cache {
-    struct list_head    slots[AVC_CACHE_SLOTS];
+    struct hlist_head    slots[AVC_CACHE_SLOTS]; /* head for avc_node->list */
     spinlock_t        slots_lock[AVC_CACHE_SLOTS]; /* lock for writes */
     atomic_t        lru_hint;    /* LRU hint for reclaim scan */
     atomic_t        active_nodes;
@@ -241,7 +240,7 @@ void __init avc_init(void)
 
     for ( i = 0; i < AVC_CACHE_SLOTS; i++ )
     {
-        INIT_LIST_HEAD(&avc_cache.slots[i]);
+        INIT_HLIST_HEAD(&avc_cache.slots[i]);
         spin_lock_init(&avc_cache.slots_lock[i]);
     }
     atomic_set(&avc_cache.active_nodes, 0);
@@ -254,6 +253,7 @@ int avc_get_hash_stats(char *buf, uint32
 {
     int i, chain_len, max_chain_len, slots_used;
     struct avc_node *node;
+    struct hlist_head *head;
 
     rcu_read_lock();
 
@@ -261,11 +261,14 @@ int avc_get_hash_stats(char *buf, uint32
     max_chain_len = 0;
     for ( i = 0; i < AVC_CACHE_SLOTS; i++ )
     {
-        if ( !list_empty(&avc_cache.slots[i]) )
-        {
+        head = &avc_cache.slots[i];
+        if ( !hlist_empty(head) )
+        {
+           struct hlist_node *next;
+
             slots_used++;
             chain_len = 0;
-            list_for_each_entry_rcu(node, &avc_cache.slots[i], list)
+            hlist_for_each_entry_rcu(node, next, head, list)
                 chain_len++;
             if ( chain_len > max_chain_len )
                 max_chain_len = chain_len;
@@ -289,7 +292,7 @@ static void avc_node_free(struct rcu_hea
 
 static void avc_node_delete(struct avc_node *node)
 {
-    list_del_rcu(&node->list);
+    hlist_del_rcu(&node->list);
     call_rcu(&node->rhead, avc_node_free);
     atomic_dec(&avc_cache.active_nodes);
 }
@@ -303,7 +306,7 @@ static void avc_node_kill(struct avc_nod
 
 static void avc_node_replace(struct avc_node *new, struct avc_node *old)
 {
-    list_replace_rcu(&old->list, &new->list);
+    hlist_replace_rcu(&old->list, &new->list);
     call_rcu(&old->rhead, avc_node_free);
     atomic_dec(&avc_cache.active_nodes);
 }
@@ -312,31 +315,34 @@ static inline int avc_reclaim_node(void)
 {
     struct avc_node *node;
     int hvalue, try, ecx;
-       unsigned long flags;
+    unsigned long flags;
+    struct hlist_head *head;
+    struct hlist_node *next;
+    spinlock_t *lock;
 
     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 */
+        head = &avc_cache.slots[hvalue];
+        lock = &avc_cache.slots_lock[hvalue];
+
+        spin_lock_irqsave(&avc_cache.slots_lock[hvalue], flags);
+        rcu_read_lock();
+        hlist_for_each_entry(node, next, head, list)
+        {
                 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;
+                 rcu_read_unlock();
+                 spin_unlock_irqrestore(lock, flags);
+                 goto out;
                 }
-            }
-        }
-               spin_unlock_irqrestore(&avc_cache.slots_lock[hvalue], flags);
+        }
+        rcu_read_unlock();
+        spin_unlock_irqrestore(lock, flags);
     }    
 out:
     return ecx;
@@ -352,8 +358,7 @@ static struct avc_node *avc_alloc_node(v
 
     memset(node, 0, sizeof(*node));
     INIT_RCU_HEAD(&node->rhead);
-    INIT_LIST_HEAD(&node->list);
-    atomic_set(&node->ae.used, 1);
+    INIT_HLIST_NODE(&node->list);
     avc_cache_stats_incr(allocations);
 
     atomic_inc(&avc_cache.active_nodes);
@@ -364,40 +369,35 @@ out:
     return node;
 }
 
-static void avc_node_populate(struct avc_node *node, u32 ssid, u32 tsid, u16 
tclass, struct avc_entry *ae)
+static void avc_node_populate(struct avc_node *node, u32 ssid, u32 tsid,
+                              u16 tclass, struct av_decision *avd)
 {
     node->ae.ssid = ssid;
     node->ae.tsid = tsid;
     node->ae.tclass = tclass;
-    memcpy(&node->ae.avd, &ae->avd, sizeof(node->ae.avd));
+    memcpy(&node->ae.avd, 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;
+    struct hlist_head *head;
+    struct hlist_node *next;
 
     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 )
+    head = &avc_cache.slots[hvalue];
+    hlist_for_each_entry_rcu(node, next, head, 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;
 }
 
@@ -415,22 +415,18 @@ out:
  * 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)
+static struct avc_node *avc_lookup(u32 ssid, u32 tsid, u16 tclass)
 {
     struct avc_node *node;
 
     avc_cache_stats_incr(lookups);
     node = avc_search_node(ssid, tsid, tclass);
 
-    if ( node && ((node->ae.avd.decided & requested) == requested) )
-    {
+    if ( node )
         avc_cache_stats_incr(hits);
-        goto out;
-    }
-
-    node = NULL;
-    avc_cache_stats_incr(misses);
-out:
+    else
+        avc_cache_stats_incr(misses);
+
     return node;
 }
 
@@ -477,34 +473,43 @@ static int avc_latest_notif_update(int s
  * 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)
+static struct avc_node *avc_insert(u32 ssid, u32 tsid, u16 tclass,
+                                   struct av_decision *avd)
 {
     struct avc_node *pos, *node = NULL;
     int hvalue;
-       unsigned long flag;
-
-    if ( avc_latest_notif_update(ae->avd.seqno, 1) )
+    unsigned long flag;
+
+    if ( avc_latest_notif_update(avd->seqno, 1) )
         goto out;
 
     node = avc_alloc_node();
     if ( node )
     {
+        struct hlist_head *head;
+        struct hlist_node *next;
+        spinlock_t *lock;
+
         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_populate(node, ssid, tsid, tclass, avd);
+
+        head = &avc_cache.slots[hvalue];
+        lock = &avc_cache.slots_lock[hvalue];
+
+        spin_lock_irqsave(lock, flag);
+        hlist_for_each_entry(pos, next, head, 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]);
+        hlist_add_head_rcu(&node->list, head);
 found:
-               spin_unlock_irqrestore(&avc_cache.slots_lock[hvalue], flag);
+        spin_unlock_irqrestore(lock, flag);
     }
 out:
     return node;
@@ -622,11 +627,15 @@ static inline int avc_sidcmp(u32 x, u32 
  * 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)
+static int avc_update_node(u32 event, u32 perms, u32 ssid, u32 tsid, u16 
tclass,
+                          u32 seqno)
 {
     int hvalue, rc = 0;
-       unsigned long flag;
+    unsigned long flag;
     struct avc_node *pos, *node, *orig = NULL;
+    struct hlist_head *head;
+    struct hlist_node *next;
+    spinlock_t *lock;
     
     node = avc_alloc_node();
     if ( !node )
@@ -636,12 +645,18 @@ static int avc_update_node(u32 event, u3
     }
 
     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 
)
+
+    head = &avc_cache.slots[hvalue];
+    lock = &avc_cache.slots_lock[hvalue];
+
+    spin_lock_irqsave(lock, flag);
+
+    hlist_for_each_entry(pos, next, head, list)
+    {
+        if ( ssid == pos->ae.ssid &&
+            tsid == pos->ae.tsid &&
+            tclass == pos->ae.tclass &&
+            seqno == pos->ae.avd.seqno )
         {
             orig = pos;
             break;
@@ -659,7 +674,7 @@ static int avc_update_node(u32 event, u3
      * Copy and replace original node.
      */
 
-    avc_node_populate(node, ssid, tsid, tclass, &orig->ae);
+    avc_node_populate(node, ssid, tsid, tclass, &orig->ae.avd);
 
     switch ( event )
     {
@@ -685,7 +700,7 @@ static int avc_update_node(u32 event, u3
     }
     avc_node_replace(node, orig);
 out_unlock:
-       spin_unlock_irqrestore(&avc_cache.slots_lock[hvalue], flag);
+    spin_unlock_irqrestore(lock, flag);
 out:
     return rc;
 }
@@ -697,31 +712,40 @@ int avc_ss_reset(u32 seqno)
 int avc_ss_reset(u32 seqno)
 {
     struct avc_callback_node *c;
-    int i, rc = 0;
-       unsigned long flag;
+    int i, rc = 0, tmprc;
+    unsigned long flag;
     struct avc_node *node;
+    struct hlist_head *head;
+    struct hlist_node *next;
+    spinlock_t *lock;
 
     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)
+        head = &avc_cache.slots[i];
+        lock = &avc_cache.slots_lock[i];
+
+        spin_lock_irqsave(lock, flag);
+        rcu_read_lock();
+        hlist_for_each_entry(node, next, head, list)
             avc_node_delete(node);
-               spin_unlock_irqrestore(&avc_cache.slots_lock[i], flag);
+        rcu_read_unlock();
+        spin_unlock_irqrestore(lock, 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;
+            tmprc = c->callback(AVC_CALLBACK_RESET,
+                                0, 0, 0, 0, NULL);
+            /* save the first error encountered for the return
+               value and continue processing the callbacks */
+            if ( !rc )
+                rc = tmprc;
         }
     }
 
     avc_latest_notif_update(seqno, 0);
-out:
     return rc;
 }
 
@@ -745,41 +769,47 @@ out:
  * should be released for the auditing.
  */
 int avc_has_perm_noaudit(u32 ssid, u32 tsid, u16 tclass, u32 requested,
-                                                     struct av_decision *avd)
+                         struct av_decision *in_avd)
 {
     struct avc_node *node;
-    struct avc_entry entry, *p_ae;
+    struct av_decision avd_entry, *avd;
     int rc = 0;
     u32 denied;
 
+    BUG_ON(!requested);
+
     rcu_read_lock();
 
-    node = avc_lookup(ssid, tsid, tclass, requested);
+    node = avc_lookup(ssid, tsid, tclass);
     if ( !node )
     {
         rcu_read_unlock();
-        rc = security_compute_av(ssid,tsid,tclass,requested,&entry.avd);
+
+        if ( in_avd )
+            avd = in_avd;
+        else
+            avd = &avd_entry;
+
+        rc = security_compute_av(ssid,tsid,tclass,requested,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 )
+        node = avc_insert(ssid,tsid,tclass,avd);
+    } else {
+        if ( in_avd )
+            memcpy(in_avd, &node->ae.avd, sizeof(*in_avd));
+        avd = &node->ae.avd;
+    }
+
+    denied = requested & ~(avd->allowed);
+
+    if ( denied )
+    {
+        if ( !flask_enforcing || (avd->flags & AVD_FLAGS_PERMISSIVE) )
+            avc_update_node(AVC_CALLBACK_GRANT,requested,
+                            ssid,tsid,tclass,avd->seqno);
+        else
             rc = -EACCES;
-        else
-            if ( node )
-                avc_update_node(AVC_CALLBACK_GRANT,requested,
-                        ssid,tsid,tclass);
     }
 
     rcu_read_unlock();
diff -r b79da5f5ffe7 -r 001a99da1294 xen/xsm/flask/flask_op.c
--- a/xen/xsm/flask/flask_op.c  Wed Aug 19 14:22:15 2009 +0100
+++ b/xen/xsm/flask/flask_op.c  Wed Aug 19 14:22:52 2009 +0100
@@ -346,7 +346,7 @@ static int flask_security_access(char *b
 
     memset(buf, 0, size);
     length = snprintf(buf, size, "%x %x %x %x %u", 
-                                        avd.allowed, avd.decided,
+                                        avd.allowed, 0xffffffff,
                                         avd.auditallow, avd.auditdeny, 
                                         avd.seqno);
                 
diff -r b79da5f5ffe7 -r 001a99da1294 xen/xsm/flask/include/avc_ss.h
--- a/xen/xsm/flask/include/avc_ss.h    Wed Aug 19 14:22:15 2009 +0100
+++ b/xen/xsm/flask/include/avc_ss.h    Wed Aug 19 14:22:52 2009 +0100
@@ -10,5 +10,28 @@
 
 int avc_ss_reset(u32 seqno);
 
+struct av_perm_to_string {
+    u16 tclass;
+    u32 value;
+    const char *name;
+};
+
+struct av_inherit {
+    const char **common_pts;
+    u32 common_base;
+    u16 tclass;
+};
+
+struct selinux_class_perm {
+    const struct av_perm_to_string *av_perm_to_string;
+    u32 av_pts_len;
+    u32 cts_len;
+    const char **class_to_string;
+    const struct av_inherit *av_inherit;
+    u32 av_inherit_len;
+};
+
+extern const struct selinux_class_perm selinux_class_perm;
+
 #endif /* _FLASK_AVC_SS_H_ */
 
diff -r b79da5f5ffe7 -r 001a99da1294 xen/xsm/flask/include/security.h
--- a/xen/xsm/flask/include/security.h  Wed Aug 19 14:22:15 2009 +0100
+++ b/xen/xsm/flask/include/security.h  Wed Aug 19 14:22:52 2009 +0100
@@ -26,10 +26,14 @@
 #define POLICYDB_VERSION_VALIDATETRANS    19
 #define POLICYDB_VERSION_MLS        19
 #define POLICYDB_VERSION_AVTAB        20
+#define POLICYDB_VERSION_RANGETRANS    21
+#define POLICYDB_VERSION_POLCAP                22
+#define POLICYDB_VERSION_PERMISSIVE    23
+#define POLICYDB_VERSION_BOUNDARY      24
 
 /* Range of policy versions we understand*/
 #define POLICYDB_VERSION_MIN   POLICYDB_VERSION_BASE
-#define POLICYDB_VERSION_MAX   POLICYDB_VERSION_AVTAB
+#define POLICYDB_VERSION_MAX   POLICYDB_VERSION_BOUNDARY
 
 #ifdef FLASK_BOOTPARAM
 extern int flask_enabled;
@@ -43,11 +47,14 @@ int security_load_policy(void * data, si
 
 struct av_decision {
     u32 allowed;
-    u32 decided;
     u32 auditallow;
     u32 auditdeny;
     u32 seqno;
+    u32 flags;
 };
+
+/* definitions of av_decision.flags */
+#define AVD_FLAGS_PERMISSIVE   0x0001
 
 int security_compute_av(u32 ssid, u32 tsid, u16 tclass, u32 requested,
                                                     struct av_decision *avd);
@@ -61,9 +68,6 @@ int security_sid_to_context(u32 sid, cha
 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);
 
diff -r b79da5f5ffe7 -r 001a99da1294 xen/xsm/flask/ss/avtab.c
--- a/xen/xsm/flask/ss/avtab.c  Wed Aug 19 14:22:15 2009 +0100
+++ b/xen/xsm/flask/ss/avtab.c  Wed Aug 19 14:22:52 2009 +0100
@@ -12,6 +12,9 @@
  *    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.
+ *
+ * Updated: Yuichi Nakamura <ynakam@xxxxxxxxxxxxxx>
+ *     Tuned number of hash slots for avtab to reduce memory usage
  */
 
 /* Ported to Xen 3.0, George Coker, <gscoker@xxxxxxxxxxxxxx> */
@@ -25,11 +28,11 @@
 #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 inline int avtab_hash(struct avtab_key *keyp, u16 mask)
+{
+    return ((keyp->target_class + (keyp->target_type << 2) +
+             (keyp->source_type << 9)) & 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, 
@@ -64,10 +67,10 @@ static int avtab_insert(struct avtab *h,
     struct avtab_node *prev, *cur, *newnode;
     u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD);
 
-    if ( !h )
+    if ( !h || !h->htable )
         return -EINVAL;
 
-    hvalue = AVTAB_HASH(key);
+    hvalue = avtab_hash(key, h->mask);
     for ( prev = NULL, cur = h->htable[hvalue]; cur;
                                                     prev = cur, cur = 
cur->next)
     {
@@ -105,9 +108,9 @@ struct avtab_node * avtab_insert_nonuniq
     struct avtab_node *prev, *cur, *newnode;
     u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD);
 
-    if ( !h )
+    if ( !h || !h->htable )
         return NULL;
-    hvalue = AVTAB_HASH(key);
+    hvalue = avtab_hash(key, h->mask);
     for ( prev = NULL, cur = h->htable[hvalue]; cur; 
                                                 prev = cur, cur = cur->next )
     {
@@ -137,10 +140,10 @@ struct avtab_datum *avtab_search(struct 
     struct avtab_node *cur;
     u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD);
 
-    if ( !h )
+    if ( !h || !h->htable )
         return NULL;
 
-    hvalue = AVTAB_HASH(key);
+    hvalue = avtab_hash(key, h->mask);
     for ( cur = h->htable[hvalue]; cur; cur = cur->next )
     {
         if ( key->source_type == cur->key.source_type &&
@@ -172,10 +175,10 @@ struct avtab_node* avtab_search_node(str
     struct avtab_node *cur;
     u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD);
 
-    if ( !h )
+    if ( !h || !h->htable )
         return NULL;
 
-    hvalue = AVTAB_HASH(key);
+    hvalue = avtab_hash(key, h->mask);
     for ( cur = h->htable[hvalue]; cur; cur = cur->next )
     {
         if ( key->source_type == cur->key.source_type &&
@@ -235,7 +238,7 @@ void avtab_destroy(struct avtab *h)
     if ( !h || !h->htable )
         return;
 
-    for ( i = 0; i < AVTAB_SIZE; i++ )
+    for ( i = 0; i < h->nslot; i++ )
     {
         cur = h->htable[i];
         while ( cur != NULL )
@@ -248,19 +251,52 @@ void avtab_destroy(struct avtab *h)
     }
     xfree(h->htable);
     h->htable = NULL;
-}
-
+    h->nslot = 0;
+    h->mask = 0;
+}
 
 int avtab_init(struct avtab *h)
 {
+    h->htable = NULL;
+    h->nel = 0;
+    return 0;
+}
+
+int avtab_alloc(struct avtab *h, u32 nrules)
+{
+    u16 mask = 0;
+    u32 shift = 0;
+    u32 work = nrules;
+    u32 nslot = 0;
     int i;
 
-    h->htable = (void *)xmalloc_array(struct avtab_node, AVTAB_SIZE);
+    if ( nrules == 0 )
+        goto avtab_alloc_out;
+
+    while ( work )
+    {
+        work  = work >> 1;
+        shift++;
+       }
+       if ( shift > 2 )
+        shift = shift - 2;
+    nslot = 1 << shift;
+    if ( nslot > MAX_AVTAB_SIZE )
+        nslot = MAX_AVTAB_SIZE;
+    mask = nslot - 1;
+
+    h->htable = xmalloc_array(struct avtab_node *, nslot);
     if ( !h->htable )
         return -ENOMEM;
-    for ( i = 0; i < AVTAB_SIZE; i++ )
+    for ( i = 0; i < nslot; i++ )
         h->htable[i] = NULL;
+
+avtab_alloc_out:
     h->nel = 0;
+    h->nslot = nslot;
+    h->mask = mask;
+    printk(KERN_DEBUG "Flask: %d avtab hash slots, %d rules.\n",
+           h->nslot, nrules);
     return 0;
 }
 
@@ -271,7 +307,7 @@ void avtab_hash_eval(struct avtab *h, ch
 
     slots_used = 0;
     max_chain_len = 0;
-    for ( i = 0; i < AVTAB_SIZE; i++ )
+    for ( i = 0; i < h->nslot; i++ )
     {
         cur = h->htable[i];
         if ( cur )
@@ -290,7 +326,7 @@ void avtab_hash_eval(struct avtab *h, ch
     }
 
     printk(KERN_INFO "%s:  %d entries and %d/%d buckets used, longest "
-           "chain length %d\n", tag, h->nel, slots_used, AVTAB_SIZE,
+           "chain length %d\n", tag, h->nel, slots_used, h->nslot,
                                                                max_chain_len);
 }
 
@@ -303,17 +339,18 @@ static uint16_t spec_order[] = {
     AVTAB_MEMBER
 };
 
-int avtab_read_item(void *fp, u32 vers, struct avtab *a,
+int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol,
                             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;
+    u32 items, items2, val, vers = pol->policyvers;
     struct avtab_key key;
     struct avtab_datum datum;
     int i, rc;
+    unsigned set;
 
     memset(&key, 0, sizeof(struct avtab_key));
     memset(&datum, 0, sizeof(struct avtab_datum));
@@ -323,20 +360,20 @@ int avtab_read_item(void *fp, u32 vers, 
         rc = next_entry(buf32, fp, sizeof(u32));
         if ( rc < 0 )
         {
-            printk(KERN_ERR "security: avtab: truncated entry\n");
+            printk(KERN_ERR "Flask: 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");
+            printk(KERN_ERR "Flask: 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");
+            printk(KERN_ERR "Flask: avtab: truncated entry\n");
             return -1;
         }
         items = 0;
@@ -345,21 +382,21 @@ int avtab_read_item(void *fp, u32 vers, 
         key.source_type = (u16)val;
         if ( key.source_type != val )
         {
-            printk("security: avtab: truncated source type\n");
+            printk("Flask: 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");
+            printk("Flask: 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");
+            printk("Flask: avtab: truncated target class\n");
             return -1;
         }
 
@@ -368,12 +405,12 @@ int avtab_read_item(void *fp, u32 vers, 
 
         if ( !(val & (AVTAB_AV | AVTAB_TYPE)) )
         {
-            printk("security: avtab: null entry\n");
+            printk("Flask: avtab: null entry\n");
             return -1;
         }
         if ( (val & AVTAB_AV) && (val & AVTAB_TYPE) )
         {
-            printk("security: avtab: entry has both access vectors and 
types\n");
+            printk("Flask: avtab: entry has both access vectors and types\n");
             return -1;
         }
 
@@ -390,7 +427,7 @@ int avtab_read_item(void *fp, u32 vers, 
         }
 
         if ( items != items2 ) {
-            printk("security: avtab: entry only had %d items, expected %d\n", 
+            printk("Flask: avtab: entry only had %d items, expected %d\n",
                                                                 items2, items);
             return -1;
         }
@@ -400,7 +437,7 @@ int avtab_read_item(void *fp, u32 vers, 
     rc = next_entry(buf16, fp, sizeof(u16)*4);
     if ( rc < 0 )
     {
-        printk("security: avtab: truncated entry\n");
+        printk("Flask: avtab: truncated entry\n");
         return -1;
     }
 
@@ -410,13 +447,39 @@ int avtab_read_item(void *fp, u32 vers, 
     key.target_class = le16_to_cpu(buf16[items++]);
     key.specified = le16_to_cpu(buf16[items++]);
 
+    if ( !policydb_type_isvalid(pol, key.source_type) ||
+         !policydb_type_isvalid(pol, key.target_type) ||
+         !policydb_class_isvalid(pol, key.target_class) )
+    {
+        printk(KERN_ERR "Flask: avtab: invalid type or class\n");
+        return -1;
+    }
+
+    set = 0;
+    for ( i = 0; i < ARRAY_SIZE(spec_order); i++ )
+    {
+        if ( key.specified & spec_order[i] )
+            set++;
+    }
+    if ( !set || set > 1 )
+    {
+        printk(KERN_ERR "Flask:  avtab:  more than one specifier\n");
+        return -1;
+    }
+
     rc = next_entry(buf32, fp, sizeof(u32));
     if ( rc < 0 )
     {
-        printk("security: avtab: truncated entry\n");
+        printk("Flask: avtab: truncated entry\n");
         return -1;
     }
     datum.data = le32_to_cpu(*buf32);
+    if ( (key.specified & AVTAB_TYPE) &&
+         !policydb_type_isvalid(pol, datum.data) )
+    {
+        printk(KERN_ERR "Flask: avtab: invalid type\n");
+        return -1;
+    }
     return insertf(a, &key, &datum, p);
 }
 
@@ -426,7 +489,7 @@ static int avtab_insertf(struct avtab *a
     return avtab_insert(a, k, d);
 }
 
-int avtab_read(struct avtab *a, void *fp, u32 vers)
+int avtab_read(struct avtab *a, void *fp, struct policydb *pol)
 {
     int rc;
     __le32 buf[1];
@@ -435,25 +498,28 @@ int avtab_read(struct avtab *a, void *fp
     rc = next_entry(buf, fp, sizeof(u32));
     if ( rc < 0 )
     {
-        printk(KERN_ERR "security: avtab: truncated table\n");
+        printk(KERN_ERR "Flask: avtab: truncated table\n");
         goto bad;
     }
     nel = le32_to_cpu(buf[0]);
     if ( !nel )
     {
-        printk(KERN_ERR "security: avtab: table is empty\n");
+        printk(KERN_ERR "Flask: avtab: table is empty\n");
         rc = -EINVAL;
         goto bad;
     }
+    rc = avtab_alloc(a, nel);
+    if ( rc )
+        goto bad;
     for ( i = 0; i < nel; i++ )
     {
-        rc = avtab_read_item(fp,vers, a, avtab_insertf, NULL);
+        rc = avtab_read_item(a, fp, pol, avtab_insertf, NULL);
         if ( rc )
         {
             if ( rc == -ENOMEM )
-                printk(KERN_ERR "security: avtab: out of memory\n");
+                printk(KERN_ERR "Flask: avtab: out of memory\n");
             else if ( rc == -EEXIST )
-                printk(KERN_ERR "security: avtab: duplicate entry\n");
+                printk(KERN_ERR "Flask: avtab: duplicate entry\n");
             else
                 rc = -EINVAL;
             goto bad;
diff -r b79da5f5ffe7 -r 001a99da1294 xen/xsm/flask/ss/avtab.h
--- a/xen/xsm/flask/ss/avtab.h  Wed Aug 19 14:22:15 2009 +0100
+++ b/xen/xsm/flask/ss/avtab.h  Wed Aug 19 14:22:52 2009 +0100
@@ -16,6 +16,9 @@
  *    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.
+ *
+ * Updated: Yuichi Nakamura <ynakam@xxxxxxxxxxxxxx>
+ *     Tuned number of hash slots for avtab to reduce memory usage
  */
 
 /* Ported to Xen 3.0, George Coker, <gscoker@xxxxxxxxxxxxxx> */
@@ -53,19 +56,23 @@ struct avtab {
 struct avtab {
     struct avtab_node **htable;
     u32 nel;    /* number of elements */
+    u32 nslot;      /* number of hash slots */
+    u16 mask;       /* mask to compute hash func */
 };
 
 int avtab_init(struct avtab *);
+int avtab_alloc(struct avtab *, u32);
 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,
+struct policydb;
+int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol,
             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);
+int avtab_read(struct avtab *a, void *fp, struct policydb *pol);
 
 struct avtab_node *avtab_insert_nonunique(struct avtab *h, 
                             struct avtab_key *key, struct avtab_datum *datum);
@@ -75,11 +82,10 @@ struct avtab_node *avtab_search_node_nex
 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
+#define MAX_AVTAB_HASH_BITS 13
+#define MAX_AVTAB_HASH_BUCKETS (1 << MAX_AVTAB_HASH_BITS)
+#define MAX_AVTAB_HASH_MASK (MAX_AVTAB_HASH_BUCKETS-1)
+#define MAX_AVTAB_SIZE MAX_AVTAB_HASH_BUCKETS
 
 #endif    /* _SS_AVTAB_H_ */
 
diff -r b79da5f5ffe7 -r 001a99da1294 xen/xsm/flask/ss/conditional.c
--- a/xen/xsm/flask/ss/conditional.c    Wed Aug 19 14:22:15 2009 +0100
+++ b/xen/xsm/flask/ss/conditional.c    Wed Aug 19 14:22:52 2009 +0100
@@ -101,7 +101,7 @@ int evaluate_cond_node(struct policydb *
     {
         node->cur_state = new_state;
         if ( new_state == -1 )
-            printk(KERN_ERR "security: expression result was undefined - 
disabling all rules.\n");
+            printk(KERN_ERR "Flask: expression result was undefined - 
disabling all rules.\n");
         /* turn the rules on or off */
         for ( cur = node->true_list; cur != NULL; cur = cur->next )
         {
@@ -287,7 +287,7 @@ static int cond_insertf(struct avtab *a,
     {
         if ( avtab_search(&p->te_avtab, k) )
         {
-            printk("security: type rule already exists outside of a "
+            printk("Flask: type rule already exists outside of a "
                                                                 
"conditional.");
             goto err;
         }
@@ -306,7 +306,7 @@ static int cond_insertf(struct avtab *a,
             {
                 if ( avtab_search_node_next(node_ptr, k->specified) )
                 {
-                    printk("security: too many conflicting type rules.");
+                    printk("Flask: too many conflicting type rules.");
                     goto err;
                 }
                 found = 0;
@@ -320,7 +320,7 @@ static int cond_insertf(struct avtab *a,
                 }
                 if ( !found )
                 {
-                    printk("security: conflicting type rules.\n");
+                    printk("Flask: conflicting type rules.\n");
                     goto err;
                 }
             }
@@ -329,7 +329,7 @@ static int cond_insertf(struct avtab *a,
         {
             if ( avtab_search(&p->te_cond_avtab, k) )
             {
-                printk("security: conflicting type rules when adding type rule 
"
+                printk("Flask: conflicting type rules when adding type rule "
                                                                 "for true.\n");
                 goto err;
             }
@@ -339,7 +339,7 @@ static int cond_insertf(struct avtab *a,
     node_ptr = avtab_insert_nonunique(&p->te_cond_avtab, k, d);
     if ( !node_ptr )
     {
-        printk("security: could not insert rule.");
+        printk("Flask: could not insert rule.");
         goto err;
     }
 
@@ -389,8 +389,7 @@ static int cond_read_av_list(struct poli
     data.tail = NULL;
     for ( i = 0; i < len; i++ )
     {
-        rc = avtab_read_item(fp, p->policyvers, &p->te_cond_avtab, 
cond_insertf,
-                                                                        &data);
+        rc = avtab_read_item(&p->te_cond_avtab, fp, p, cond_insertf, &data);
         if ( rc )
             return rc;
     }
@@ -403,13 +402,13 @@ static int expr_isvalid(struct policydb 
 {
     if ( expr->expr_type <= 0 || expr->expr_type > COND_LAST )
     {
-        printk("security: conditional expressions uses unknown operator.\n");
+        printk("Flask: conditional expressions uses unknown operator.\n");
         return 0;
     }
 
     if ( expr->bool > p->p_bools.nprim )
     {
-        printk("security: conditional expressions uses unknown bool.\n");
+        printk("Flask: conditional expressions uses unknown bool.\n");
         return 0;
     }
     return 1;
@@ -488,6 +487,10 @@ int cond_read_list(struct policydb *p, v
         return -1;
 
     len = le32_to_cpu(buf[0]);
+
+    rc = avtab_alloc(&(p->te_cond_avtab), p->te_avtab.nel);
+    if ( rc )
+      goto err;
 
     for ( i = 0; i < len; i++ )
     {
diff -r b79da5f5ffe7 -r 001a99da1294 xen/xsm/flask/ss/conditional.h
--- a/xen/xsm/flask/ss/conditional.h    Wed Aug 19 14:22:15 2009 +0100
+++ b/xen/xsm/flask/ss/conditional.h    Wed Aug 19 14:22:52 2009 +0100
@@ -28,7 +28,7 @@ struct cond_expr {
 #define COND_XOR    5 /* bool ^ bool */
 #define COND_EQ        6 /* bool == bool */
 #define COND_NEQ    7 /* bool != bool */
-#define COND_LAST    8
+#define COND_LAST    COND_NEQ
     __u32 expr_type;
     __u32 bool;
     struct cond_expr *next;
diff -r b79da5f5ffe7 -r 001a99da1294 xen/xsm/flask/ss/context.h
--- a/xen/xsm/flask/ss/context.h        Wed Aug 19 14:22:15 2009 +0100
+++ b/xen/xsm/flask/ss/context.h        Wed Aug 19 14:22:52 2009 +0100
@@ -42,17 +42,40 @@ static inline int mls_context_cpy(struct
 {
     int rc;
 
-    if (!flask_mls_enabled)
+    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)
+    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)
+    if ( rc )
+        ebitmap_destroy(&dst->range.level[0].cat);
+out:
+    return rc;
+}
+
+/*
+ * Sets both levels in the MLS range of 'dst' to the low level of 'src'.
+ */
+static inline int mls_context_cpy_low(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[0].sens;
+    rc = ebitmap_cpy(&dst->range.level[1].cat, &src->range.level[0].cat);
+    if ( rc )
         ebitmap_destroy(&dst->range.level[0].cat);
 out:
     return rc;
@@ -60,7 +83,7 @@ out:
 
 static inline int mls_context_cmp(struct context *c1, struct context *c2)
 {
-    if (!flask_mls_enabled)
+    if ( !flask_mls_enabled )
         return 1;
 
     return ((c1->range.level[0].sens == c2->range.level[0].sens) &&
@@ -71,7 +94,7 @@ static inline int mls_context_cmp(struct
 
 static inline void mls_context_destroy(struct context *c)
 {
-    if (!flask_mls_enabled)
+    if ( !flask_mls_enabled )
         return;
 
     ebitmap_destroy(&c->range.level[0].cat);
diff -r b79da5f5ffe7 -r 001a99da1294 xen/xsm/flask/ss/ebitmap.c
--- a/xen/xsm/flask/ss/ebitmap.c        Wed Aug 19 14:22:15 2009 +0100
+++ b/xen/xsm/flask/ss/ebitmap.c        Wed Aug 19 14:22:52 2009 +0100
@@ -3,6 +3,10 @@
  *
  * Author : Stephen Smalley, <sds@xxxxxxxxxxxxxx>
  */
+/*
+ * Updated: KaiGai Kohei <kaigai@xxxxxxxxxxxxx>
+ *      Applied standard bit operations to improve bitmap scanning.
+ */
 
 /* Ported to Xen 3.0, George Coker, <gscoker@xxxxxxxxxxxxxx> */
 
@@ -11,6 +15,7 @@
 #include <xen/xmalloc.h>
 #include <xen/errno.h>
 #include <xen/spinlock.h>
+#include <xen/bitmap.h>
 #include "ebitmap.h"
 #include "policydb.h"
 
@@ -23,7 +28,8 @@ int ebitmap_cmp(struct ebitmap *e1, stru
 
     n1 = e1->node;
     n2 = e2->node;
-    while ( n1 && n2 && (n1->startbit == n2->startbit) && (n1->map == n2->map) 
)
+    while ( n1 && n2 && (n1->startbit == n2->startbit) &&
+            !memcmp(n1->maps, n2->maps, EBITMAP_SIZE / 8))
     {
         n1 = n1->next;
         n2 = n2->next;
@@ -52,7 +58,7 @@ int ebitmap_cpy(struct ebitmap *dst, str
         }
         memset(new, 0, sizeof(*new));
         new->startbit = n->startbit;
-        new->map = n->map;
+        memcpy(new->maps, n->maps, EBITMAP_SIZE / 8);
         new->next = NULL;
         if ( prev )
             prev->next = new;
@@ -69,6 +75,7 @@ int ebitmap_contains(struct ebitmap *e1,
 int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2)
 {
     struct ebitmap_node *n1, *n2;
+    int i;
 
     if ( e1->highbit < e2->highbit )
         return 0;
@@ -82,8 +89,11 @@ int ebitmap_contains(struct ebitmap *e1,
             n1 = n1->next;
             continue;
         }
-        if ( (n1->map & n2->map) != n2->map )
-            return 0;
+        for ( i = 0; i < EBITMAP_UNIT_NUMS; i++ )
+        {
+            if ( (n1->maps[i] & n2->maps[i]) != n2->maps[i] )
+                return 0;
+        }
 
         n1 = n1->next;
         n2 = n2->next;
@@ -105,13 +115,8 @@ int ebitmap_get_bit(struct ebitmap *e, u
     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;
-        }
+        if ( (n->startbit + EBITMAP_SIZE) > bit )
+            return ebitmap_node_get_bit(n, bit);
         n = n->next;
     }
 
@@ -126,37 +131,41 @@ int ebitmap_set_bit(struct ebitmap *e, u
     n = e->node;
     while ( n && n->startbit <= bit )
     {
-        if ( (n->startbit + MAPSIZE) > bit )
+        if ( (n->startbit + EBITMAP_SIZE) > bit )
         {
             if ( value )
             {
-                n->map |= (MAPBIT << (bit - n->startbit));
+                ebitmap_node_set_bit(n, bit);
             }
             else
             {
-                n->map &= ~(MAPBIT << (bit - n->startbit));
-                if ( !n->map )
+                unsigned int s;
+
+                ebitmap_node_clr_bit(n, bit);
+
+                s = find_first_bit(n->maps, EBITMAP_SIZE);
+                if ( s < EBITMAP_SIZE )
+                    return 0;
+
+                /* drop this node from the bitmap */
+
+                if ( !n->next )
                 {
-                    /* 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;
-                    }
+                    /*
+                     * this was the highest map
+                     * within the bitmap
+                     */
                     if ( prev )
-                        prev->next = n->next;
+                        e->highbit = prev->startbit + EBITMAP_SIZE;
                     else
-                        e->node = n->next;
-
-                    xfree(n);
+                        e->highbit = 0;
                 }
+                if ( prev )
+                    prev->next = n->next;
+                else
+                    e->node = n->next;
+
+                xfree(n);
             }
             return 0;
         }
@@ -172,12 +181,12 @@ int ebitmap_set_bit(struct ebitmap *e, u
         return -ENOMEM;
     memset(new, 0, sizeof(*new));
 
-    new->startbit = bit & ~(MAPSIZE - 1);
-    new->map = (MAPBIT << (bit - new->startbit));
+    new->startbit = bit - (bit % EBITMAP_SIZE);
+    ebitmap_node_set_bit(new, bit);
 
     if ( !n )
         /* this node will be the highest map within the bitmap */
-        e->highbit = new->startbit + MAPSIZE;
+        e->highbit = new->startbit + EBITMAP_SIZE;
 
     if ( prev )
     {
@@ -215,11 +224,11 @@ void ebitmap_destroy(struct ebitmap *e)
 
 int ebitmap_read(struct ebitmap *e, void *fp)
 {
-    int rc;
-    struct ebitmap_node *n, *l;
+    struct ebitmap_node *n = NULL;
+    u32 mapunit, count, startbit, index;
+    u64 map;
     __le32 buf[3];
-    u32 mapsize, count, i;
-    __le64 map;
+    int rc, i;
 
     ebitmap_init(e);
 
@@ -227,99 +236,99 @@ int ebitmap_read(struct ebitmap *e, void
     if ( rc < 0 )
         goto out;
 
-    mapsize = le32_to_cpu(buf[0]);
+    mapunit = 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);
+    if ( mapunit != sizeof(u64) * 8 )
+    {
+        printk(KERN_ERR "Flask: ebitmap: map size %u does not "
+               "match my size %Zd (high bit was %d)\n", mapunit,
+               sizeof(u64) * 8, e->highbit);
         goto bad;
     }
+
+    /* round up e->highbit */
+    e->highbit += EBITMAP_SIZE - 1;
+    e->highbit -= (e->highbit % EBITMAP_SIZE);
+
     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));
+        rc = next_entry(&startbit, 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;
-        }
+            printk(KERN_ERR "Flask: ebitmap: truncated map\n");
+            goto bad;
+        }
+        startbit = le32_to_cpu(startbit);
+        if ( startbit & (mapunit - 1) )
+        {
+            printk(KERN_ERR "Flask: ebitmap start bit (%d) is "
+                   "not a multiple of the map unit size (%u)\n",
+                   startbit, mapunit);
+            goto bad;
+        }
+        if ( startbit > e->highbit - mapunit )
+        {
+            printk(KERN_ERR "Flask: ebitmap start bit (%d) is "
+                   "beyond the end of the bitmap (%u)\n",
+                   startbit, (e->highbit - mapunit));
+            goto bad;
+        }
+
+        if ( !n || startbit >= n->startbit + EBITMAP_SIZE )
+        {
+            struct ebitmap_node *tmp;
+            tmp = xmalloc(struct ebitmap_node);
+            if ( !tmp )
+            {
+                printk(KERN_ERR
+                       "Flask: ebitmap: out of memory\n");
+                rc = -ENOMEM;
+                goto bad;
+            }
+            memset(tmp, 0, sizeof(*tmp));
+            /* round down */
+            tmp->startbit = startbit - (startbit % EBITMAP_SIZE);
+            if ( n )
+                n->next = tmp;
+            else
+                e->node = tmp;
+            n = tmp;
+        }
+        else if ( startbit <= n->startbit )
+        {
+            printk(KERN_ERR "Flask: ebitmap: start bit %d"
+                   " comes after start bit %d\n",
+                   startbit, n->startbit);
+            goto bad;
+        }
+
         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;
-    }
-
+            printk(KERN_ERR "Flask: ebitmap: truncated map\n");
+            goto bad;
+        }
+        map = le64_to_cpu(map);
+
+        index = (startbit - n->startbit) / EBITMAP_UNIT_SIZE;
+        while ( map )
+        {
+            n->maps[index++] = map & (-1UL);
+            map = EBITMAP_SHIFT_UNIT_SIZE(map);
+        }
+    }
 ok:
     rc = 0;
 out:
     return rc;
-bad_free:
-    xfree(n);
 bad:
     if ( !rc )
         rc = -EINVAL;
diff -r b79da5f5ffe7 -r 001a99da1294 xen/xsm/flask/ss/ebitmap.h
--- a/xen/xsm/flask/ss/ebitmap.h        Wed Aug 19 14:22:15 2009 +0100
+++ b/xen/xsm/flask/ss/ebitmap.h        Wed Aug 19 14:22:52 2009 +0100
@@ -14,14 +14,20 @@
 #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 */
+#include <xen/bitmap.h>
+
+#define EBITMAP_UNIT_NUMS      ((32 - sizeof(void *) - sizeof(u32))    \
+                                       / sizeof(unsigned long))
+#define EBITMAP_UNIT_SIZE      BITS_PER_LONG
+#define EBITMAP_SIZE           (EBITMAP_UNIT_NUMS * EBITMAP_UNIT_SIZE)
+#define EBITMAP_BIT            1ULL
+#define EBITMAP_SHIFT_UNIT_SIZE(x)                                     \
+       (((x) >> EBITMAP_UNIT_SIZE / 2) >> EBITMAP_UNIT_SIZE / 2)
 
 struct ebitmap_node {
-    u32 startbit;        /* starting position in the total bitmap */
-    MAPTYPE map;        /* this node's portion of the bitmap */
     struct ebitmap_node *next;
+    unsigned long maps[EBITMAP_UNIT_NUMS];
+    u32 startbit;
 };
 
 struct ebitmap {
@@ -32,11 +38,18 @@ struct ebitmap {
 #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)
+static inline unsigned int ebitmap_start_positive(struct ebitmap *e,
+                                                  struct ebitmap_node **n)
 {
-    *n = e->node;
-    return ebitmap_startbit(e);
+    unsigned int ofs;
+
+    for ( *n = e->node; *n; *n = (*n)->next )
+    {
+        ofs = find_first_bit((*n)->maps, EBITMAP_SIZE);
+        if ( ofs < EBITMAP_SIZE )
+            return (*n)->startbit + ofs;
+    }
+    return ebitmap_length(e);
 }
 
 static inline void ebitmap_init(struct ebitmap *e)
@@ -44,29 +57,66 @@ static inline void ebitmap_init(struct e
     memset(e, 0, sizeof(*e));
 }
 
-static inline unsigned int ebitmap_next(struct ebitmap_node **n,
-                                                        unsigned int bit)
+static inline unsigned int ebitmap_next_positive(struct ebitmap *e,
+                                                 struct ebitmap_node **n,
+                                                 unsigned int bit)
 {
-    if ( (bit == ((*n)->startbit + MAPSIZE - 1)) && (*n)->next )
+    unsigned int ofs;
+
+    ofs = find_next_bit((*n)->maps, EBITMAP_SIZE, bit - (*n)->startbit + 1);
+    if ( ofs < EBITMAP_SIZE )
+        return ofs + (*n)->startbit;
+
+    for ( *n = (*n)->next; *n; *n = (*n)->next )
     {
-        *n = (*n)->next;
-        return (*n)->startbit;
+        ofs = find_first_bit((*n)->maps, EBITMAP_SIZE);
+        if ( ofs < EBITMAP_SIZE )
+            return ofs + (*n)->startbit;
     }
-
-    return (bit+1);
+    return ebitmap_length(e);
 }
 
-static inline int ebitmap_node_get_bit(struct ebitmap_node * n,
-                                                        unsigned int bit)
+#define EBITMAP_NODE_INDEX(node, bit)  \
+    (((bit) - (node)->startbit) / EBITMAP_UNIT_SIZE)
+#define EBITMAP_NODE_OFFSET(node, bit) \
+    (((bit) - (node)->startbit) % EBITMAP_UNIT_SIZE)
+
+static inline int ebitmap_node_get_bit(struct ebitmap_node *n,
+                                       unsigned int bit)
 {
-    if ( n->map & (MAPBIT << (bit - n->startbit)) )
+    unsigned int index = EBITMAP_NODE_INDEX(n, bit);
+    unsigned int ofs = EBITMAP_NODE_OFFSET(n, bit);
+
+    BUG_ON( index >= EBITMAP_UNIT_NUMS );
+    if ( (n->maps[index] & (EBITMAP_BIT << ofs)) )
         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) ) \
+static inline void ebitmap_node_set_bit(struct ebitmap_node *n,
+                                        unsigned int bit)
+{
+    unsigned int index = EBITMAP_NODE_INDEX(n, bit);
+    unsigned int ofs = EBITMAP_NODE_OFFSET(n, bit);
+
+    BUG_ON(index >= EBITMAP_UNIT_NUMS);
+    n->maps[index] |= (EBITMAP_BIT << ofs);
+}
+
+static inline void ebitmap_node_clr_bit(struct ebitmap_node *n,
+                                        unsigned int bit)
+{
+    unsigned int index = EBITMAP_NODE_INDEX(n, bit);
+    unsigned int ofs = EBITMAP_NODE_OFFSET(n, bit);
+
+    BUG_ON( index >= EBITMAP_UNIT_NUMS );
+    n->maps[index] &= ~(EBITMAP_BIT << ofs);
+}
+
+#define ebitmap_for_each_positive_bit(e, n, bit)       \
+    for ( bit = ebitmap_start_positive(e, &n);       \
+          bit < ebitmap_length(e);                   \
+          bit = ebitmap_next_positive(e, &n, bit) )   \
 
 int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2);
 int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src);
diff -r b79da5f5ffe7 -r 001a99da1294 xen/xsm/flask/ss/hashtab.c
--- a/xen/xsm/flask/ss/hashtab.c        Wed Aug 19 14:22:15 2009 +0100
+++ b/xen/xsm/flask/ss/hashtab.c        Wed Aug 19 14:22:52 2009 +0100
@@ -11,8 +11,10 @@
 #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 *hashtab_create(u32 (*hash_value)(struct hashtab *h,
+                                                const void *key),
+            int (*keycmp)(struct hashtab *h, const void *key1,
+                         const void *key2), u32 size)
 {
     struct hashtab *p;
     u32 i;
@@ -26,7 +28,7 @@ struct hashtab *hashtab_create(u32 (*has
     p->nel = 0;
     p->hash_value = hash_value;
     p->keycmp = keycmp;
-    p->htable = (void *)xmalloc_array(struct hashtab_node, size);
+    p->htable = xmalloc_array(struct hashtab_node *, size);
     if ( p->htable == NULL )
     {
         xfree(p);
@@ -80,7 +82,7 @@ int hashtab_insert(struct hashtab *h, vo
     return 0;
 }
 
-void *hashtab_search(struct hashtab *h, void *key)
+void *hashtab_search(struct hashtab *h, const void *key)
 {
     u32 hvalue;
     struct hashtab_node *cur;
diff -r b79da5f5ffe7 -r 001a99da1294 xen/xsm/flask/ss/hashtab.h
--- a/xen/xsm/flask/ss/hashtab.h        Wed Aug 19 14:22:15 2009 +0100
+++ b/xen/xsm/flask/ss/hashtab.h        Wed Aug 19 14:22:52 2009 +0100
@@ -22,9 +22,9 @@ 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);
+    u32 (*hash_value)(struct hashtab *h, const void *key);
                     /* hash function */
-    int (*keycmp)(struct hashtab *h, void *key1, void *key2);
+    int (*keycmp)(struct hashtab *h, const void *key1, const void *key2);
                     /* key comparison function */
 };
 
@@ -39,8 +39,10 @@ struct hashtab_info {
  * 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);
+struct hashtab *hashtab_create(u32 (*hash_value)(struct hashtab *h,
+                                                const void *key),
+            int (*keycmp)(struct hashtab *h, const void *key1,
+                         const void *key2), u32 size);
 
 /*
  * Inserts the specified (key, datum) pair into the specified hash table.
@@ -58,7 +60,7 @@ int hashtab_insert(struct hashtab *h, vo
  * Returns NULL if no entry has the specified key or
  * the datum of the entry otherwise.
  */
-void *hashtab_search(struct hashtab *h, void *k);
+void *hashtab_search(struct hashtab *h, const void *k);
 
 /*
  * Destroys the specified hash table.
diff -r b79da5f5ffe7 -r 001a99da1294 xen/xsm/flask/ss/mls.c
--- a/xen/xsm/flask/ss/mls.c    Wed Aug 19 14:22:15 2009 +0100
+++ b/xen/xsm/flask/ss/mls.c    Wed Aug 19 14:22:52 2009 +0100
@@ -29,46 +29,49 @@
  */
 int mls_compute_context_len(struct context * context)
 {
-    int i, l, len, range;
+    int i, l, len, head, prev;
+    char *nm;
+    struct ebitmap *e;
     struct ebitmap_node *node;
 
-    if (!flask_mls_enabled)
+    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) )
+        int index_sens = context->range.level[l].sens;
+        len += strlen(policydb.p_sens_val_to_name[index_sens - 1]);
+
+        /* categories */
+        head = -2;
+        prev = -2;
+        e = &context->range.level[l].cat;
+        ebitmap_for_each_positive_bit(e, node, i)
+        {
+            if ( i - prev > 1 )
             {
-                if ( range )
-                {
-                    range++;
-                    continue;
-                }
-
-                len += strlen(policydb.p_cat_val_to_name[i]) + 1;
-                range++;
+                               /* one or more negative bits are skipped */
+                if ( head != prev )
+                {
+                    nm = policydb.p_cat_val_to_name[prev];
+                    len += strlen(nm) + 1;
+                }
+                nm = policydb.p_cat_val_to_name[i];
+                len += strlen(nm) + 1;
+                head = i;
             }
-            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;
-
+            prev = i;
+        }
+        if ( prev != head )
+        {
+            nm = policydb.p_cat_val_to_name[prev];
+            len += strlen(nm) + 1;
+        }
         if ( l == 0 )
         {
             if ( mls_level_eq(&context->range.level[0], 
-                                                &context->range.level[1]) )
+                              &context->range.level[1]) )
                 break;
             else
                 len++;
@@ -85,8 +88,9 @@ int mls_compute_context_len(struct conte
  */
 void mls_sid_to_context(struct context *context, char **scontext)
 {
-    char *scontextp;
-    int i, l, range, wrote_sep;
+    char *scontextp, *nm;
+    int i, l, head, prev;
+    struct ebitmap *e;
     struct ebitmap_node *node;
 
     if ( !flask_mls_enabled )
@@ -99,64 +103,51 @@ void mls_sid_to_context(struct context *
 
     for ( l = 0; l < 2; l++ )
     {
-        range = 0;
-        wrote_sep = 0;
-        strlcpy(scontextp,
+        memcpy(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]);
+        scontextp += strlen(scontextp);
 
         /* categories */
-        ebitmap_for_each_bit(&context->range.level[l].cat, node, i)
-        {
-            if ( ebitmap_node_get_bit(node, i) )
+        head = -2;
+        prev = -2;
+        e = &context->range.level[l].cat;
+        ebitmap_for_each_positive_bit(e, node, i)
+        {
+            if ( i - prev > 1 )
             {
-                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 )
+                /* one or more negative bits are skipped */
+                if ( prev != head )
+                {
+                    if ( prev - head > 1 )
                         *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;
+                    nm = policydb.p_cat_val_to_name[prev];
+                    memcpy(scontextp, nm, strlen(nm));
+                    scontextp += strlen(nm);
+                }
+                if ( prev < 0 )
+                    *scontextp++ = ':';
+                else
+                    *scontextp++ = ',';
+                nm = policydb.p_cat_val_to_name[i];
+                memcpy(scontextp, nm, strlen(nm));
+                scontextp += strlen(nm);
+                head = i;
             }
-        }
-
-        /* Handle case where last category is the end of range */
-        if ( range > 1 )
-        {
-            if ( range > 2 )
+            prev = i;
+        }
+
+        if ( prev != head )
+        {
+            if ( prev - head > 1 )
                 *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]);
+            nm = policydb.p_cat_val_to_name[prev];
+            memcpy(scontextp, nm, strlen(nm));
+            scontextp += strlen(nm);
         }
 
         if ( l == 0 )
@@ -176,54 +167,56 @@ void mls_sid_to_context(struct context *
     return;
 }
 
+int mls_level_isvalid(struct policydb *p, struct mls_level *l)
+{
+    struct level_datum *levdatum;
+    struct ebitmap_node *node;
+    int i;
+
+    if ( !l->sens || l->sens > p->p_levels.nprim )
+        return 0;
+    levdatum = hashtab_search(p->p_levels.table,
+                              p->p_sens_val_to_name[l->sens - 1]);
+    if ( !levdatum )
+        return 0;
+
+    ebitmap_for_each_positive_bit(&l->cat, 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.
+             */
+            return 0;
+        }
+    }
+
+    return 1;
+}
+
+int mls_range_isvalid(struct policydb *p, struct mls_range *r)
+{
+    return ( mls_level_isvalid(p, &r->level[0]) &&
+             mls_level_isvalid(p, &r->level[1]) &&
+             mls_level_dom(&r->level[1], &r->level[0]));
+}
+
 /*
  * 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 ( !mls_range_isvalid(p, &c->range) )
+        return 0;
 
     if ( c->role == OBJECT_R_VAL )
         return 1;
@@ -238,26 +231,6 @@ int mls_context_isvalid(struct policydb 
         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;
 }
 
 /*
@@ -270,16 +243,11 @@ static inline int mls_copy_context(struc
  * 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)
+int mls_context_to_sid(char oldc, char **scontext,
+                       struct context *context, struct sidtab *s)
 {
 
     char delim;
@@ -292,23 +260,10 @@ int mls_context_to_sid(char oldc, char *
         return 0;
 
     /*
-     * No MLS component to the security context, try and map to
-     * default if provided.
+     * No MLS component to the security context -> error.
      */
     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;
@@ -421,26 +376,6 @@ out:
 }
 
 /*
- * 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,
@@ -537,20 +472,17 @@ int mls_convert_context(struct policydb 
         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_for_each_positive_bit(&c->range.level[l].cat, 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;
@@ -562,48 +494,37 @@ int mls_compute_sid(struct context *scon
 int mls_compute_sid(struct context *scontext, struct context *tcontext,
                         u16 tclass, u32 specified, struct context *newcontext)
 {
+    struct range_trans *rtr;
+
     if ( !flask_mls_enabled )
         return 0;
 
     switch ( specified )
     {
         case AVTAB_TRANSITION:
-            if ( tclass == SECCLASS_DOMAIN )
+            /* Look for a range transition rule. */
+            for (rtr = policydb.range_tr; rtr; rtr = rtr->next)
             {
-                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);
-                    }
+                if (rtr->source_type == scontext->type &&
+                    rtr->target_type == tcontext->type &&
+                    rtr->target_class == tclass)
+                {
+                    /* Set the range from the rule */
+                    return mls_range_set(newcontext,
+                                         &rtr->target_range);
                 }
             }
             /* Fallthrough */
         case AVTAB_CHANGE:
             if ( tclass == SECCLASS_DOMAIN )
                 /* Use the process MLS attributes. */
-                return mls_copy_context(newcontext, scontext);
+                return mls_context_cpy(newcontext, scontext);
             else
+                /* Use the process effective MLS attributes. */
+                return mls_context_cpy_low(newcontext, scontext);
+        case AVTAB_MEMBER:
             /* 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);
-            }
+            return mls_context_cpy_low(newcontext, scontext);
         default:
             return -EINVAL;
     }
diff -r b79da5f5ffe7 -r 001a99da1294 xen/xsm/flask/ss/mls.h
--- a/xen/xsm/flask/ss/mls.h    Wed Aug 19 14:22:15 2009 +0100
+++ b/xen/xsm/flask/ss/mls.h    Wed Aug 19 14:22:52 2009 +0100
@@ -8,7 +8,7 @@
  *
  *    Support for enhanced MLS infrastructure.
  *
- * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
+ * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc.
  */
 
 #ifndef _SS_MLS_H_
@@ -20,9 +20,11 @@ int mls_compute_context_len(struct conte
 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_range_isvalid(struct policydb *p, struct mls_range *r);
+int mls_level_isvalid(struct policydb *p, struct mls_level *l);
 
 int mls_context_to_sid(char oldc, char **scontext, struct context *context,
-                                               struct sidtab *s, u32 def_sid);
+                       struct sidtab *s);
 
 int mls_convert_context(struct policydb *oldp, struct policydb *newp,
                                                     struct context *context);
diff -r b79da5f5ffe7 -r 001a99da1294 xen/xsm/flask/ss/policydb.c
--- a/xen/xsm/flask/ss/policydb.c       Wed Aug 19 14:22:15 2009 +0100
+++ b/xen/xsm/flask/ss/policydb.c       Wed Aug 19 14:22:52 2009 +0100
@@ -100,6 +100,26 @@ static struct policydb_compat_info polic
         .sym_num        = SYM_NUM,
         .ocon_num       = OCON_NUM,
     },
+    {
+       .version        = POLICYDB_VERSION_RANGETRANS,
+       .sym_num        = SYM_NUM,
+       .ocon_num       = OCON_NUM,
+    },
+    {
+       .version        = POLICYDB_VERSION_POLCAP,
+       .sym_num        = SYM_NUM,
+       .ocon_num       = OCON_NUM,
+    },
+    {
+       .version        = POLICYDB_VERSION_PERMISSIVE,
+       .sym_num        = SYM_NUM,
+       .ocon_num       = OCON_NUM,
+    },
+    {
+       .version        = POLICYDB_VERSION_BOUNDARY,
+       .sym_num        = SYM_NUM,
+       .ocon_num       = OCON_NUM,
+    },
 };
 
 static struct policydb_compat_info *policydb_lookup_compat(int version)
@@ -187,6 +207,9 @@ static int policydb_init(struct policydb
     rc = cond_policydb_init(p);
     if ( rc )
         goto out_free_avtab;
+
+    ebitmap_init(&p->policycaps);
+    ebitmap_init(&p->permissive_map);
 
 out:
     return rc;
@@ -244,7 +267,9 @@ static int role_index(void *key, void *d
 
     role = datum;
     p = datap;
-    if ( !role->value || role->value > p->p_roles.nprim )
+    if ( !role->value
+         || role->value > p->p_roles.nprim
+         || role->bounds > 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;
@@ -261,9 +286,12 @@ static int type_index(void *key, void *d
 
     if ( typdatum->primary )
     {
-        if ( !typdatum->value || typdatum->value > p->p_types.nprim )
+        if ( !typdatum->value
+             || typdatum->value > p->p_types.nprim
+             || typdatum->bounds > p->p_types.nprim )
             return -EINVAL;
         p->p_type_val_to_name[typdatum->value - 1] = key;
+        p->type_val_to_struct[typdatum->value - 1] = typdatum;
     }
 
     return 0;
@@ -276,7 +304,9 @@ static int user_index(void *key, void *d
 
     usrdatum = datum;
     p = datap;
-    if ( !usrdatum->value || usrdatum->value > p->p_users.nprim )
+    if ( !usrdatum->value
+         || usrdatum->value > p->p_users.nprim
+         || usrdatum->bounds > 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;
@@ -356,7 +386,7 @@ static int policydb_index_classes(struct
         goto out;
 
     p->class_val_to_struct =
-        (void *)xmalloc_array(struct class_datum, p->p_classes.nprim);
+        xmalloc_array(struct class_datum *, p->p_classes.nprim);
     if ( !p->class_val_to_struct )
     {
         rc = -ENOMEM;
@@ -404,14 +434,14 @@ static int policydb_index_others(struct 
 {
     int i, rc = 0;
 
-    printk(KERN_INFO "security:  %d users, %d roles, %d types, %d bools",
+    printk(KERN_INFO "Flask:  %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",
+    printk(KERN_INFO "Flask:  %d classes, %d rules\n",
            p->p_classes.nprim, p->te_avtab.nel);
 
 #ifdef DEBUG_HASHES
@@ -420,7 +450,7 @@ static int policydb_index_others(struct 
 #endif
 
     p->role_val_to_struct =
-        (void *)xmalloc_array(struct role_datum, p->p_roles.nprim);
+        xmalloc_array(struct role_datum *, p->p_roles.nprim);
     if ( !p->role_val_to_struct )
     {
         rc = -ENOMEM;
@@ -428,8 +458,16 @@ static int policydb_index_others(struct 
     }
 
     p->user_val_to_struct =
-        (void *)xmalloc_array(struct user_datum, p->p_users.nprim);
+        xmalloc_array(struct user_datum *, p->p_users.nprim);
     if ( !p->user_val_to_struct )
+    {
+        rc = -ENOMEM;
+        goto out;
+    }
+
+    p->type_val_to_struct =
+        xmalloc_array(struct type_datum *, p->p_types.nprim);
+    if ( !p->type_val_to_struct )
     {
         rc = -ENOMEM;
         goto out;
@@ -627,6 +665,7 @@ void policydb_destroy(struct policydb *p
     xfree(p->class_val_to_struct);
     xfree(p->role_val_to_struct);
     xfree(p->user_val_to_struct);
+    xfree(p->type_val_to_struct);
 
     avtab_destroy(&p->te_avtab);
 
@@ -639,6 +678,7 @@ void policydb_destroy(struct policydb *p
             c = c->next;
             ocontext_destroy(ctmp,i);
         }
+        p->ocontexts[i] = NULL;
     }
 
     cond_policydb_destroy(p);
@@ -659,14 +699,28 @@ void policydb_destroy(struct policydb *p
 
     for ( rt = p->range_tr; rt; rt = rt -> next )
     {
-        if ( lrt ) xfree(lrt);
+        if ( lrt )
+        {
+            ebitmap_destroy(&lrt->target_range.level[0].cat);
+            ebitmap_destroy(&lrt->target_range.level[1].cat);
+            xfree(lrt);
+        }
         lrt = rt;
     }
-    if ( lrt ) xfree(lrt);
-
-    for ( i = 0; i < p->p_types.nprim; i++ )
-        ebitmap_destroy(&p->type_attr_map[i]);
+    if ( lrt )
+    {
+        ebitmap_destroy(&lrt->target_range.level[0].cat);
+        ebitmap_destroy(&lrt->target_range.level[1].cat);
+        xfree(lrt);
+    }
+
+    if ( p->type_attr_map )
+        for ( i = 0; i < p->p_types.nprim; i++ )
+            ebitmap_destroy(&p->type_attr_map[i]);
     xfree(p->type_attr_map);
+
+    ebitmap_destroy(&p->policycaps);
+    ebitmap_destroy(&p->permissive_map);
 
     return;
 }
@@ -683,7 +737,7 @@ int policydb_load_isids(struct policydb 
     rc = sidtab_init(s);
     if ( rc )
     {
-        printk(KERN_ERR "security:  out of memory on SID table init\n");
+        printk(KERN_ERR "Flask:  out of memory on SID table init\n");
         goto out;
     }
 
@@ -692,14 +746,14 @@ int policydb_load_isids(struct policydb 
     {
         if ( !c->context[0].user )
         {
-            printk(KERN_ERR "security:  SID %s was never "
+            printk(KERN_ERR "Flask:  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 "
+            printk(KERN_ERR "Flask:  unable to load initial "
                    "SID %s.\n", c->u.name);
             rc = -EINVAL;
             goto out;
@@ -707,6 +761,27 @@ int policydb_load_isids(struct policydb 
     }
 out:
     return rc;
+}
+
+int policydb_class_isvalid(struct policydb *p, unsigned int class)
+{
+    if ( !class || class > p->p_classes.nprim )
+        return 0;
+    return 1;
+}
+
+int policydb_role_isvalid(struct policydb *p, unsigned int role)
+{
+    if ( !role || role > p->p_roles.nprim )
+        return 0;
+    return 1;
+}
+
+int policydb_type_isvalid(struct policydb *p, unsigned int type)
+{
+    if ( !type || type > p->p_types.nprim )
+        return 0;
+    return 1;
 }
 
 /*
@@ -772,14 +847,14 @@ static int mls_read_range_helper(struct 
     items = le32_to_cpu(buf[0]);
     if ( items > ARRAY_SIZE(buf) )
     {
-        printk(KERN_ERR "security: mls:  range overflow\n");
+        printk(KERN_ERR "Flask: 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");
+        printk(KERN_ERR "Flask: mls:  truncated range\n");
         goto out;
     }
     r->level[0].sens = le32_to_cpu(buf[0]);
@@ -791,7 +866,7 @@ static int mls_read_range_helper(struct 
     rc = ebitmap_read(&r->level[0].cat, fp);
     if ( rc )
     {
-        printk(KERN_ERR "security: mls:  error reading low "
+        printk(KERN_ERR "Flask: mls:  error reading low "
                "categories\n");
         goto out;
     }
@@ -800,7 +875,7 @@ static int mls_read_range_helper(struct 
         rc = ebitmap_read(&r->level[1].cat, fp);
         if ( rc )
         {
-            printk(KERN_ERR "security: mls:  error reading high "
+            printk(KERN_ERR "Flask: mls:  error reading high "
                    "categories\n");
             goto bad_high;
         }
@@ -810,7 +885,7 @@ static int mls_read_range_helper(struct 
         rc = ebitmap_cpy(&r->level[1].cat, &r->level[0].cat);
         if ( rc )
         {
-            printk(KERN_ERR "security: mls:  out of memory\n");
+            printk(KERN_ERR "Flask: mls:  out of memory\n");
             goto bad_high;
         }
     }
@@ -836,7 +911,7 @@ static int context_read_and_validate(str
     rc = next_entry(buf, fp, sizeof buf);
     if ( rc < 0 )
     {
-        printk(KERN_ERR "security: context truncated\n");
+        printk(KERN_ERR "Flask: context truncated\n");
         goto out;
     }
     c->user = le32_to_cpu(buf[0]);
@@ -846,7 +921,7 @@ static int context_read_and_validate(str
     {
         if ( mls_read_range_helper(&c->range, fp) )
         {
-            printk(KERN_ERR "security: error reading MLS range of "
+            printk(KERN_ERR "Flask: error reading MLS range of "
                    "context\n");
             rc = -EINVAL;
             goto out;
@@ -855,7 +930,7 @@ static int context_read_and_validate(str
 
     if ( !policydb_context_isvalid(p, c) )
     {
-        printk(KERN_ERR "security:  invalid security context\n");
+        printk(KERN_ERR "Flask:  invalid security context\n");
         context_destroy(c);
         rc = -EINVAL;
     }
@@ -1121,7 +1196,7 @@ static int class_read(struct policydb *p
                             cladatum->comkey);
         if ( !cladatum->comdatum )
         {
-            printk(KERN_ERR "security:  unknown common %s\n",
+            printk(KERN_ERR "Flask:  unknown common %s\n",
                    cladatum->comkey);
             rc = -EINVAL;
             goto bad;
@@ -1166,8 +1241,8 @@ static int role_read(struct policydb *p,
 {
     char *key = NULL;
     struct role_datum *role;
-    int rc;
-    __le32 buf[2];
+    int rc, to_read = 2;
+    __le32 buf[3];
     u32 len;
 
     role = xmalloc(struct role_datum);
@@ -1178,12 +1253,17 @@ static int role_read(struct policydb *p,
     }
     memset(role, 0, sizeof(*role));
 
-    rc = next_entry(buf, fp, sizeof buf);
+    if ( p->policyvers >= POLICYDB_VERSION_BOUNDARY )
+        to_read = 3;
+
+    rc = next_entry(buf, fp, sizeof(buf[0]) * to_read);
     if ( rc < 0 )
         goto bad;
 
     len = le32_to_cpu(buf[0]);
     role->value = le32_to_cpu(buf[1]);
+    if ( p->policyvers >= POLICYDB_VERSION_BOUNDARY )
+        role->bounds = le32_to_cpu(buf[2]);
 
     key = xmalloc_array(char, len + 1);
     if ( !key )
@@ -1231,8 +1311,8 @@ static int type_read(struct policydb *p,
 {
     char *key = NULL;
     struct type_datum *typdatum;
-    int rc;
-    __le32 buf[3];
+    int rc, to_read = 3;
+    __le32 buf[4];
     u32 len;
 
     typdatum = xmalloc(struct type_datum);
@@ -1243,13 +1323,30 @@ static int type_read(struct policydb *p,
     }
     memset(typdatum, 0, sizeof(*typdatum));
 
-    rc = next_entry(buf, fp, sizeof buf);
+    if ( p->policyvers >= POLICYDB_VERSION_BOUNDARY )
+        to_read = 4;
+
+    rc = next_entry(buf, fp, sizeof(buf[0]) * to_read);
     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]);
+    if ( p->policyvers >= POLICYDB_VERSION_BOUNDARY )
+    {
+        u32 prop = le32_to_cpu(buf[2]);
+
+        if ( prop & TYPEDATUM_PROPERTY_PRIMARY )
+            typdatum->primary = 1;
+        if ( prop & TYPEDATUM_PROPERTY_ATTRIBUTE )
+            typdatum->attribute = 1;
+
+        typdatum->bounds = le32_to_cpu(buf[3]);
+    }
+    else
+    {
+        typdatum->primary = le32_to_cpu(buf[2]);
+    }
 
     key = xmalloc_array(char, len + 1);
     if ( !key )
@@ -1287,14 +1384,14 @@ static int mls_read_level(struct mls_lev
     rc = next_entry(buf, fp, sizeof buf);
     if ( rc < 0 )
     {
-        printk(KERN_ERR "security: mls: truncated level\n");
+        printk(KERN_ERR "Flask: 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");
+        printk(KERN_ERR "Flask: mls:  error reading level categories\n");
         goto bad;
     }
     return 0;
@@ -1307,8 +1404,8 @@ static int user_read(struct policydb *p,
 {
     char *key = NULL;
     struct user_datum *usrdatum;
-    int rc;
-    __le32 buf[2];
+    int rc, to_read = 2;
+    __le32 buf[3];
     u32 len;
 
     usrdatum = xmalloc(struct user_datum);
@@ -1319,12 +1416,17 @@ static int user_read(struct policydb *p,
     }
     memset(usrdatum, 0, sizeof(*usrdatum));
 
-    rc = next_entry(buf, fp, sizeof buf);
+    if ( p->policyvers >= POLICYDB_VERSION_BOUNDARY )
+        to_read = 3;
+
+    rc = next_entry(buf, fp, sizeof(buf[0]) * to_read);
     if ( rc < 0 )
         goto bad;
 
     len = le32_to_cpu(buf[0]);
     usrdatum->value = le32_to_cpu(buf[1]);
+    if ( p->policyvers >= POLICYDB_VERSION_BOUNDARY )
+        usrdatum->bounds = le32_to_cpu(buf[2]);
 
     key = xmalloc_array(char, len + 1);
     if ( !key )
@@ -1475,6 +1577,142 @@ static int (*read_f[SYM_NUM]) (struct po
     cat_read,
 };
 
+static int user_bounds_sanity_check(void *key, void *datum, void *datap)
+{
+    struct user_datum *upper, *user;
+    struct policydb *p = datap;
+    int depth = 0;
+
+    upper = user = datum;
+    while (upper->bounds)
+    {
+        struct ebitmap_node *node;
+        unsigned long bit;
+
+        if ( ++depth == POLICYDB_BOUNDS_MAXDEPTH )
+        {
+            printk(KERN_ERR "Flask: user %s: "
+                   "too deep or looped boundary",
+                   (char *) key);
+            return -EINVAL;
+        }
+
+        upper = p->user_val_to_struct[upper->bounds - 1];
+        ebitmap_for_each_positive_bit(&user->roles, node, bit)
+        {
+            if ( ebitmap_get_bit(&upper->roles, bit) )
+                continue;
+
+            printk(KERN_ERR
+                   "Flask: boundary violated policy: "
+                   "user=%s role=%s bounds=%s\n",
+                   p->p_user_val_to_name[user->value - 1],
+                   p->p_role_val_to_name[bit],
+                   p->p_user_val_to_name[upper->value - 1]);
+
+            return -EINVAL;
+        }
+    }
+
+    return 0;
+}
+
+static int role_bounds_sanity_check(void *key, void *datum, void *datap)
+{
+    struct role_datum *upper, *role;
+    struct policydb *p = datap;
+    int depth = 0;
+
+    upper = role = datum;
+    while (upper->bounds)
+    {
+        struct ebitmap_node *node;
+        unsigned long bit;
+
+        if ( ++depth == POLICYDB_BOUNDS_MAXDEPTH )
+        {
+            printk(KERN_ERR "Flask: role %s: "
+                   "too deep or looped bounds\n",
+                   (char *) key);
+            return -EINVAL;
+        }
+
+        upper = p->role_val_to_struct[upper->bounds - 1];
+        ebitmap_for_each_positive_bit(&role->types, node, bit)
+        {
+            if ( ebitmap_get_bit(&upper->types, bit) )
+                continue;
+
+            printk(KERN_ERR
+                   "Flask: boundary violated policy: "
+                   "role=%s type=%s bounds=%s\n",
+                   p->p_role_val_to_name[role->value - 1],
+                   p->p_type_val_to_name[bit],
+                   p->p_role_val_to_name[upper->value - 1]);
+
+            return -EINVAL;
+        }
+    }
+
+    return 0;
+}
+
+static int type_bounds_sanity_check(void *key, void *datum, void *datap)
+{
+    struct type_datum *upper, *type;
+    struct policydb *p = datap;
+    int depth = 0;
+
+    upper = type = datum;
+    while (upper->bounds)
+    {
+        if ( ++depth == POLICYDB_BOUNDS_MAXDEPTH )
+        {
+            printk(KERN_ERR "Flask: type %s: "
+                              "too deep or looped boundary\n",
+                              (char *) key);
+            return -EINVAL;
+        }
+
+        upper = p->type_val_to_struct[upper->bounds - 1];
+        if ( upper->attribute )
+        {
+            printk(KERN_ERR "Flask: type %s: "
+                              "bounded by attribute %s",
+                              (char *) key,
+                              p->p_type_val_to_name[upper->value - 1]);
+            return -EINVAL;
+        }
+    }
+
+    return 0;
+}
+
+static int policydb_bounds_sanity_check(struct policydb *p)
+{
+    int rc;
+
+    if ( p->policyvers < POLICYDB_VERSION_BOUNDARY )
+        return 0;
+
+    rc = hashtab_map(p->p_users.table,
+                     user_bounds_sanity_check, p);
+    if ( rc )
+        return rc;
+
+    rc = hashtab_map(p->p_roles.table,
+                     role_bounds_sanity_check, p);
+    if ( rc )
+        return rc;
+
+    rc = hashtab_map(p->p_types.table,
+                     type_bounds_sanity_check, p);
+    if ( rc )
+        return rc;
+
+    return 0;
+}
+
 extern int ss_initialized;
 
 /*
@@ -1505,7 +1743,7 @@ int policydb_read(struct policydb *p, vo
 
     if ( le32_to_cpu(buf[0]) != POLICYDB_MAGIC )
     {
-        printk(KERN_ERR "security:  policydb magic number 0x%x does "
+        printk(KERN_ERR "Flask:  policydb magic number 0x%x does "
                "not match expected magic number 0x%x\n",
                le32_to_cpu(buf[0]), POLICYDB_MAGIC);
         goto bad;
@@ -1514,7 +1752,7 @@ int policydb_read(struct policydb *p, vo
     len = le32_to_cpu(buf[1]);
     if ( len != strlen(POLICYDB_STRING) )
     {
-        printk(KERN_ERR "security:  policydb string length %d does not "
+        printk(KERN_ERR "Flask:  policydb string length %d does not "
                "match expected length %lu\n",
                len, strlen(POLICYDB_STRING));
         goto bad;
@@ -1522,7 +1760,7 @@ int policydb_read(struct policydb *p, vo
     policydb_str = xmalloc_array(char, len + 1);
     if ( !policydb_str )
     {
-        printk(KERN_ERR "security:  unable to allocate memory for policydb "
+        printk(KERN_ERR "Flask:  unable to allocate memory for policydb "
                "string of length %d\n", len);
         rc = -ENOMEM;
         goto bad;
@@ -1530,14 +1768,14 @@ int policydb_read(struct policydb *p, vo
     rc = next_entry(policydb_str, fp, len);
     if ( rc < 0 )
     {
-        printk(KERN_ERR "security:  truncated policydb string identifier\n");
+        printk(KERN_ERR "Flask:  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 "
+        printk(KERN_ERR "Flask:  policydb string %s does not match "
                "my string %s\n", policydb_str, POLICYDB_STRING);
         xfree(policydb_str);
         goto bad;
@@ -1555,7 +1793,7 @@ int policydb_read(struct policydb *p, vo
     if ( p->policyvers < POLICYDB_VERSION_MIN ||
                                         p->policyvers > POLICYDB_VERSION_MAX )
     {
-            printk(KERN_ERR "security:  policydb version %d does not match "
+            printk(KERN_ERR "Flask:  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;
@@ -1589,20 +1827,28 @@ int policydb_read(struct policydb *p, vo
         }
     }
 
+    if ( p->policyvers >= POLICYDB_VERSION_POLCAP &&
+         ebitmap_read(&p->policycaps, fp) != 0 )
+        goto bad;
+
+    if ( p->policyvers >= POLICYDB_VERSION_PERMISSIVE &&
+         ebitmap_read(&p->permissive_map, fp) != 0 )
+        goto bad;
+
     info = policydb_lookup_compat(p->policyvers);
     if ( !info )
     {
-        printk(KERN_ERR "security:  unable to find policy compat info "
+        printk(KERN_ERR "Flask:  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 "
+         le32_to_cpu(buf[3]) != info->ocon_num )
+    {
+        printk(KERN_ERR "Flask:  policydb table sizes (%d,%d) do "
                "not match mine (%d,%d)\n", le32_to_cpu(buf[2]),
-            le32_to_cpu(buf[3]),
+               le32_to_cpu(buf[3]),
                info->sym_num, info->ocon_num);
         goto bad;
     }
@@ -1624,7 +1870,7 @@ int policydb_read(struct policydb *p, vo
         p->symtab[i].nprim = nprim;
     }
 
-    rc = avtab_read(&p->te_avtab, fp, p->policyvers);
+    rc = avtab_read(&p->te_avtab, fp, p);
     if ( rc )
         goto bad;
 
@@ -1659,6 +1905,13 @@ int policydb_read(struct policydb *p, vo
         tr->role = le32_to_cpu(buf[0]);
         tr->type = le32_to_cpu(buf[1]);
         tr->new_role = le32_to_cpu(buf[2]);
+        if ( !policydb_role_isvalid(p, tr->role) ||
+             !policydb_type_isvalid(p, tr->type) ||
+             !policydb_role_isvalid(p, tr->new_role) )
+        {
+            rc = -EINVAL;
+            goto bad;
+        }
         ltr = tr;
     }
 
@@ -1685,6 +1938,12 @@ int policydb_read(struct policydb *p, vo
             goto bad;
         ra->role = le32_to_cpu(buf[0]);
         ra->new_role = le32_to_cpu(buf[1]);
+        if ( !policydb_role_isvalid(p, ra->role) ||
+             !policydb_role_isvalid(p, ra->new_role) )
+        {
+            rc = -EINVAL;
+            goto bad;
+        }
         lra = ra;
     }
 
@@ -1720,15 +1979,20 @@ int policydb_read(struct policydb *p, vo
             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;
+            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;
+            default:
+                printk(KERN_ERR
+                       "Flask:  unsupported object context config data\n");
+                rc = -EINVAL;
+                goto bad;
             }
         }
     }
@@ -1737,9 +2001,16 @@ int policydb_read(struct policydb *p, vo
     if ( rc < 0 )
         goto bad;
     nel = le32_to_cpu(buf[0]);
+    if ( nel )
+    {
+        printk(KERN_ERR "Flask:  unsupported genfs config data\n");
+        rc = -EINVAL;
+        goto bad;
+    }
 
     if ( p->policyvers >= POLICYDB_VERSION_MLS )
     {
+        int new_rangetr = p->policyvers >= POLICYDB_VERSION_RANGETRANS;
         rc = next_entry(buf, fp, sizeof(u32));
         if ( rc < 0 )
             goto bad;
@@ -1761,11 +2032,31 @@ int policydb_read(struct policydb *p, vo
             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);
+            rt->source_type = le32_to_cpu(buf[0]);
+            rt->target_type = le32_to_cpu(buf[1]);
+            if ( new_rangetr )
+            {
+                rc = next_entry(buf, fp, sizeof(u32));
+                if ( rc < 0 )
+                    goto bad;
+                rt->target_class = le32_to_cpu(buf[0]);
+            } else
+                rt->target_class = SECCLASS_DOMAIN;
+            if ( !policydb_type_isvalid(p, rt->source_type) ||
+                 !policydb_type_isvalid(p, rt->target_type) ||
+                 !policydb_class_isvalid(p, rt->target_class) )
+            {
+                rc = -EINVAL;
+                goto bad;
+            }
+            rc = mls_read_range_helper(&rt->target_range, fp);
             if ( rc )
                 goto bad;
+            if ( !mls_range_isvalid(p, &rt->target_range) )
+            {
+                printk(KERN_WARNING "Flask:  rangetrans:  invalid range\n");
+                goto bad;
+            }
             lrt = rt;
         }
     }
@@ -1786,6 +2077,10 @@ int policydb_read(struct policydb *p, vo
         if ( ebitmap_set_bit(&p->type_attr_map[i], i, 1) )
                 goto bad;
     }
+
+    rc = policydb_bounds_sanity_check(p);
+    if ( rc )
+        goto bad;
 
     rc = 0;
 out:
diff -r b79da5f5ffe7 -r 001a99da1294 xen/xsm/flask/ss/policydb.h
--- a/xen/xsm/flask/ss/policydb.h       Wed Aug 19 14:22:15 2009 +0100
+++ b/xen/xsm/flask/ss/policydb.h       Wed Aug 19 14:22:52 2009 +0100
@@ -63,6 +63,7 @@ struct class_datum {
 /* Role attributes */
 struct role_datum {
     u32 value;            /* internal role value */
+    u32 bounds;                        /* boundary of role */
     struct ebitmap dominates;    /* set of roles dominated by this role */
     struct ebitmap types;        /* set of authorized types for role */
 };
@@ -83,12 +84,25 @@ struct role_allow {
 /* Type attributes */
 struct type_datum {
     u32 value;        /* internal type value */
+    u32 bounds;                /* boundary of type */
     unsigned char primary;    /* primary name? */
-};
+    unsigned char attribute;/* attribute ?*/
+};
+
+/*
+ * type_datum properties
+ * available at the kernel policy version >= POLICYDB_VERSION_BOUNDARY
+ */
+#define TYPEDATUM_PROPERTY_PRIMARY     0x0001
+#define TYPEDATUM_PROPERTY_ATTRIBUTE   0x0002
+
+/* limitation of boundary depth  */
+#define POLICYDB_BOUNDS_MAXDEPTH       4
 
 /* User attributes */
 struct user_datum {
     u32 value;            /* internal user value */
+    u32 bounds;                        /* bounds of user */
     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 */
@@ -108,9 +122,10 @@ struct cat_datum {
 };
 
 struct range_trans {
-    u32 dom;            /* current process domain */
-    u32 type;            /* program executable type */
-    struct mls_range range;        /* new range */
+    u32 source_type;
+    u32 target_type;
+    u32 target_class;
+    struct mls_range target_range;
     struct range_trans *next;
 };
 
@@ -191,6 +206,7 @@ struct policydb {
     struct class_datum **class_val_to_struct;
     struct role_datum **role_val_to_struct;
     struct user_datum **user_val_to_struct;
+    struct type_datum **type_val_to_struct;
 
     /* type enforcement access vectors and transitions */
     struct avtab te_avtab;
@@ -218,12 +234,19 @@ struct policydb {
     /* type -> attribute reverse mapping */
     struct ebitmap *type_attr_map;
 
+    struct ebitmap policycaps;
+
+    struct ebitmap permissive_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_class_isvalid(struct policydb *p, unsigned int class);
+extern int policydb_type_isvalid(struct policydb *p, unsigned int type);
+extern int policydb_role_isvalid(struct policydb *p, unsigned int role);
 extern int policydb_read(struct policydb *p, void *fp);
 
 #define PERM_SYMTAB_SIZE 32
diff -r b79da5f5ffe7 -r 001a99da1294 xen/xsm/flask/ss/services.c
--- a/xen/xsm/flask/ss/services.c       Wed Aug 19 14:22:15 2009 +0100
+++ b/xen/xsm/flask/ss/services.c       Wed Aug 19 14:22:52 2009 +0100
@@ -12,8 +12,22 @@
  *
  *     Added conditional policy language extensions
  *
- * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
- * Copyright (C) 2003 - 2004 Tresys Technology, LLC
+ * Updated: Hewlett-Packard <paul.moore@xxxxxx>
+ *
+ *      Added support for the policy capability bitmap
+ *
+ * Updated: Chad Sellers <csellers@xxxxxxxxxx>
+ *
+ *  Added validation of kernel classes and permissions
+ *
+ * Updated: KaiGai Kohei <kaigai@xxxxxxxxxxxxx>
+ *
+ *  Added support for bounds domain and audit messaged on masked permissions
+ *
+ * Copyright (C) 2008, 2009 NEC Corporation
+ * Copyright (C) 2006, 2007 Hewlett-Packard Development Company, L.P.
+ * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc.
+ * Copyright (C) 2003 - 2004, 2006 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
@@ -42,9 +56,9 @@ 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_WRLOCK write_lock(&policy_rwlock)
 #define POLICY_RDUNLOCK read_unlock(&policy_rwlock)
-#define POLICY_WRUNLOCK write_unlock_irq(&policy_rwlock)
+#define POLICY_WRUNLOCK write_unlock(&policy_rwlock)
 
 static DEFINE_SPINLOCK(load_sem);
 #define LOAD_LOCK spin_lock(&load_sem)
@@ -65,6 +79,12 @@ static u32 latest_granting = 0;
 /* Forward declaration. */
 static int context_struct_to_string(struct context *context, char **scontext,
                                                             u32 *scontext_len);
+
+static int context_struct_compute_av(struct context *scontext,
+                                    struct context *tcontext,
+                                    u16 tclass,
+                                    u32 requested,
+                                    struct av_decision *avd);
 
 /*
  * Return the boolean value of a constraint expression
@@ -259,12 +279,180 @@ mls_ops:
 }
 
 /*
+ * security_dump_masked_av - dumps masked permissions during
+ * security_compute_av due to RBAC, MLS/Constraint and Type bounds.
+ */
+static int dump_masked_av_helper(void *k, void *d, void *args)
+{
+    struct perm_datum *pdatum = d;
+    char **permission_names = args;
+
+    BUG_ON(pdatum->value < 1 || pdatum->value > 32);
+
+    permission_names[pdatum->value - 1] = (char *)k;
+
+    return 0;
+}
+
+static void security_dump_masked_av(struct context *scontext,
+                                   struct context *tcontext,
+                                   u16 tclass,
+                                   u32 permissions,
+                                   const char *reason)
+{
+    struct common_datum *common_dat;
+    struct class_datum *tclass_dat;
+    char *tclass_name;
+    char *scontext_name = NULL;
+    char *tcontext_name = NULL;
+    char *permission_names[32];
+    int index;
+    u32 length;
+    unsigned char need_comma = 0;
+
+    if ( !permissions )
+        return;
+
+    tclass_name = policydb.p_class_val_to_name[tclass - 1];
+    tclass_dat = policydb.class_val_to_struct[tclass - 1];
+    common_dat = tclass_dat->comdatum;
+
+    /* init permission_names */
+    if ( common_dat &&
+         hashtab_map(common_dat->permissions.table,
+                     dump_masked_av_helper, permission_names) < 0 )
+        goto out;
+
+    if ( hashtab_map(tclass_dat->permissions.table,
+                    dump_masked_av_helper, permission_names) < 0 )
+        goto out;
+
+       /* get scontext/tcontext in text form */
+    if ( context_struct_to_string(scontext,
+                                 &scontext_name, &length) < 0 )
+        goto out;
+
+    if ( context_struct_to_string(tcontext,
+                                 &tcontext_name, &length) < 0 )
+        goto out;
+
+    printk("Flask: op=security_compute_av reason=%s "
+           "scontext=%s tcontext=%s tclass=%s perms=",
+           reason, scontext_name, tcontext_name, tclass_name);
+
+    for ( index = 0; index < 32; index++ )
+    {
+        u32 mask = (1 << index);
+
+        if ( (mask & permissions) == 0 )
+            continue;
+
+        printk("%s%s",
+               need_comma ? "," : "",
+               permission_names[index]
+               ? permission_names[index] : "????");
+        need_comma = 1;
+    }
+    printk("\n");
+out:
+    /* release scontext/tcontext */
+    xfree(tcontext_name);
+    xfree(scontext_name);
+
+    return;
+}
+
+/*
+ * security_boundary_permission - drops violated permissions
+ * on boundary constraint.
+ */
+static void type_attribute_bounds_av(struct context *scontext,
+                                     struct context *tcontext,
+                                     u16 tclass,
+                                     u32 requested,
+                                     struct av_decision *avd)
+{
+    struct context lo_scontext;
+    struct context lo_tcontext;
+    struct av_decision lo_avd;
+    struct type_datum *source
+        = policydb.type_val_to_struct[scontext->type - 1];
+    struct type_datum *target
+        = policydb.type_val_to_struct[tcontext->type - 1];
+    u32 masked = 0;
+
+    if ( source->bounds )
+    {
+        memset(&lo_avd, 0, sizeof(lo_avd));
+
+        memcpy(&lo_scontext, scontext, sizeof(lo_scontext));
+        lo_scontext.type = source->bounds;
+
+        context_struct_compute_av(&lo_scontext,
+                                  tcontext,
+                                  tclass,
+                                  requested,
+                                  &lo_avd);
+        if ( (lo_avd.allowed & avd->allowed) == avd->allowed )
+            return;            /* no masked permission */
+        masked = ~lo_avd.allowed & avd->allowed;
+    }
+
+    if ( target->bounds )
+    {
+        memset(&lo_avd, 0, sizeof(lo_avd));
+
+        memcpy(&lo_tcontext, tcontext, sizeof(lo_tcontext));
+        lo_tcontext.type = target->bounds;
+
+        context_struct_compute_av(scontext,
+                                  &lo_tcontext,
+                                  tclass,
+                                  requested,
+                                  &lo_avd);
+        if ( (lo_avd.allowed & avd->allowed) == avd->allowed )
+            return;            /* no masked permission */
+        masked = ~lo_avd.allowed & avd->allowed;
+    }
+
+    if ( source->bounds && target->bounds )
+    {
+        memset(&lo_avd, 0, sizeof(lo_avd));
+        /*
+         * lo_scontext and lo_tcontext are already
+         * set up.
+         */
+
+        context_struct_compute_av(&lo_scontext,
+                                  &lo_tcontext,
+                                  tclass,
+                                  requested,
+                                  &lo_avd);
+        if ( (lo_avd.allowed & avd->allowed) == avd->allowed )
+            return;            /* no masked permission */
+        masked = ~lo_avd.allowed & avd->allowed;
+    }
+
+    if ( masked )
+    {
+        /* mask violated permissions */
+        avd->allowed &= ~masked;
+
+        /* audit masked permissions */
+        security_dump_masked_av(scontext, tcontext,
+                                tclass, masked, "bounds");
+    }
+}
+
+/*
  * 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 context *tcontext,
+                                    u16 tclass,
+                                    u32 requested,
+                                    struct av_decision *avd)
 {
     struct constraint_node *constraint;
     struct role_allow *ra;
@@ -275,22 +463,22 @@ static int context_struct_compute_av(str
     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;
+    avd->flags = 0;
+
+    /*
+     * We do not presently support policydb.handle_unknown == allow in Xen.
+     */
+    if ( !tclass || tclass > policydb.p_classes.nprim )
+        return -EINVAL;
+
+    tclass_datum = policydb.class_val_to_struct[tclass - 1];
 
     /*
      * If a specific type enforcement rule was defined for
@@ -300,14 +488,10 @@ static int context_struct_compute_av(str
     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;
+    ebitmap_for_each_positive_bit(sattr, snode, i)
+    {
+        ebitmap_for_each_positive_bit(tattr, tnode, j)
+        {
             avkey.source_type = i + 1;
             avkey.target_type = j + 1;
             for ( node = avtab_search_node(&policydb.te_avtab, &avkey);
@@ -338,7 +522,7 @@ static int context_struct_compute_av(str
         if ( (constraint->permissions & (avd->allowed) ) &&
             !constraint_expr_eval(scontext, tcontext, NULL, constraint->expr))
         {
-            avd->allowed = (avd->allowed) & ~(constraint->permissions);
+           avd->allowed &= ~(constraint->permissions);
         }
         constraint = constraint->next;
     }
@@ -349,23 +533,25 @@ static int context_struct_compute_av(str
      * pair.
      */
     if ( tclass == SECCLASS_DOMAIN &&
-/* removed until future dynamic domain capability
-        (avd->allowed & (DOMAIN__TRANSITION | DOMAIN__DYNTRANSITION)) &&
-*/
-                                            scontext->role != tcontext->role )
-        {
+         (avd->allowed & DOMAIN__TRANSITION) &&
+         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);
-*/
-    }
-
+            avd->allowed &= ~DOMAIN__TRANSITION;
+    }
+
+    /*
+     * If the given source and target types have boundary
+     * constraint, lazy checks have to mask any violated
+     * permission and notice it to userspace via audit.
+     */
+    type_attribute_bounds_av(scontext, tcontext,
+                            tclass, requested, avd);
     return 0;
 }
 
@@ -477,7 +663,7 @@ out:
  * 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 av_decision *avd)
 {
     struct context *scontext = NULL, *tcontext = NULL;
     int rc = 0;
@@ -485,7 +671,6 @@ int security_compute_av(u32 ssid, u32 ts
     if ( !ss_initialized )
     {
         avd->allowed = 0xffffffff;
-        avd->decided = 0xffffffff;
         avd->auditallow = 0;
         avd->auditdeny = 0xffffffff;
         avd->seqno = latest_granting;
@@ -510,6 +695,10 @@ int security_compute_av(u32 ssid, u32 ts
     }
 
     rc = context_struct_compute_av(scontext, tcontext, tclass, requested, avd);
+
+    /* permissive domain? */
+    if ( ebitmap_get_bit(&policydb.permissive_map, scontext->type) )
+        avd->flags |= AVD_FLAGS_PERMISSIVE;
 out:
     POLICY_RDUNLOCK;
     return rc;
@@ -611,7 +800,18 @@ out:
 
 }
 
-static int security_context_to_sid_core(char *scontext, u32 scontext_len, u32 
*sid, u32 def_sid)
+/**
+ * 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)
 {
     char *scontext2;
     struct context context;
@@ -701,12 +901,12 @@ static int security_context_to_sid_core(
     *p++ = 0;
 
     typdatum = hashtab_search(policydb.p_types.table, scontextp);
-    if ( !typdatum )
+    if ( !typdatum || typdatum->attribute )
         goto out_unlock;
 
     context.type = typdatum->value;
 
-    rc = mls_context_to_sid(oldc, &p, &context, &sidtab, def_sid);
+    rc = mls_context_to_sid(oldc, &p, &context, &sidtab);
     if ( rc )
         goto out_unlock;
 
@@ -730,45 +930,6 @@ out_unlock:
     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(
@@ -1001,88 +1162,128 @@ int security_change_sid(u32 ssid, u32 ts
 }
 
 /*
- * Verify that each permission that is defined under the
- * existing policy is still defined with the same value
- * in the new policy.
- */
-static int validate_perm(void *key, void *datum, void *p)
-{
-    struct hashtab *h;
-    struct perm_datum *perdatum, *perdatum2;
-    int rc = 0;
-
-    h = p;
-    perdatum = datum;
-
-    perdatum2 = hashtab_search(h, key);
-    if ( !perdatum2 )
-    {
-        printk(KERN_ERR "security:  permission %s disappeared", (char *)key);
-        rc = -ENOENT;
-        goto out;
-    }
-    if ( perdatum->value != perdatum2->value )
-    {
-        printk(KERN_ERR "security:  the value of permission %s changed",
-                                                                (char *)key);
-        rc = -EINVAL;
-    }
-out:
-    return rc;
-}
-
-/*
- * Verify that each class that is defined under the
- * existing policy is still defined with the same
- * attributes in the new policy.
- */
-static int validate_class(void *key, void *datum, void *p)
-{
-    struct policydb *newp;
-    struct class_datum *cladatum, *cladatum2;
-    int rc;
-
-    newp = p;
-    cladatum = datum;
-
-    cladatum2 = hashtab_search(newp->p_classes.table, key);
-    if ( !cladatum2 )
-    {
-        printk(KERN_ERR "security:  class %s disappeared\n", (char *)key);
-        rc = -ENOENT;
-        goto out;
-    }
-    if (cladatum->value != cladatum2->value) {
-        printk(KERN_ERR "security:  the value of class %s changed\n",
-                                                                (char *)key);
-        rc = -EINVAL;
-        goto out;
-    }
-    if ( (cladatum->comdatum && !cladatum2->comdatum) ||
-                                (!cladatum->comdatum && cladatum2->comdatum) )
-    {
-        printk(KERN_ERR "security:  the inherits clause for the access "
-               "vector definition for class %s changed\n", (char *)key);
-        rc = -EINVAL;
-        goto out;
-    }
-    if ( cladatum->comdatum )
-    {
-        rc = hashtab_map(cladatum->comdatum->permissions.table, validate_perm,
-                                     cladatum2->comdatum->permissions.table);
-        if ( rc )
-        {
-            printk(" in the access vector definition for class %s\n", 
-                                                                (char *)key);
-            goto out;
-        }
-    }
-    rc = hashtab_map(cladatum->permissions.table, validate_perm,
-                                                cladatum2->permissions.table);
-    if ( rc )
-        printk(" in access vector definition for class %s\n", (char *)key);
-out:
-    return rc;
+ * Verify that each kernel class that is defined in the
+ * policy is correct
+ */
+static int validate_classes(struct policydb *p)
+{
+    int i, j;
+    struct class_datum *cladatum;
+    struct perm_datum *perdatum;
+    u32 nprim, tmp, common_pts_len, perm_val, pol_val;
+    u16 class_val;
+    const struct selinux_class_perm *kdefs = &selinux_class_perm;
+    const char *def_class, *def_perm, *pol_class;
+    struct symtab *perms;
+
+    for ( i = 1; i < kdefs->cts_len; i++ )
+    {
+        def_class = kdefs->class_to_string[i];
+        if ( !def_class )
+            continue;
+        if ( i > p->p_classes.nprim )
+        {
+            printk(KERN_INFO
+                   "Flask:  class %s not defined in policy\n",
+                   def_class);
+            return -EINVAL;
+        }
+        pol_class = p->p_class_val_to_name[i-1];
+        if ( strcmp(pol_class, def_class) )
+        {
+            printk(KERN_ERR
+                   "Flask:  class %d is incorrect, found %s but should be 
%s\n",
+                   i, pol_class, def_class);
+            return -EINVAL;
+        }
+    }
+    for ( i = 0; i < kdefs->av_pts_len; i++ )
+    {
+        class_val = kdefs->av_perm_to_string[i].tclass;
+        perm_val = kdefs->av_perm_to_string[i].value;
+        def_perm = kdefs->av_perm_to_string[i].name;
+        if ( class_val > p->p_classes.nprim )
+            continue;
+        pol_class = p->p_class_val_to_name[class_val-1];
+        cladatum = hashtab_search(p->p_classes.table, pol_class);
+        BUG_ON( !cladatum );
+        perms = &cladatum->permissions;
+        nprim = 1 << (perms->nprim - 1);
+        if ( perm_val > nprim )
+        {
+            printk(KERN_INFO
+                   "Flask:  permission %s in class %s not defined in policy\n",
+                   def_perm, pol_class);
+            return -EINVAL;
+        }
+        perdatum = hashtab_search(perms->table, def_perm);
+        if ( perdatum == NULL )
+        {
+            printk(KERN_ERR
+                   "Flask:  permission %s in class %s not found in policy\n",
+                   def_perm, pol_class);
+            return -EINVAL;
+        }
+        pol_val = 1 << (perdatum->value - 1);
+        if ( pol_val != perm_val )
+        {
+            printk(KERN_ERR
+                   "Flask:  permission %s in class %s has incorrect value\n",
+                   def_perm, pol_class);
+            return -EINVAL;
+        }
+    }
+    for ( i = 0; i < kdefs->av_inherit_len; i++ )
+    {
+        class_val = kdefs->av_inherit[i].tclass;
+        if ( class_val > p->p_classes.nprim )
+            continue;
+        pol_class = p->p_class_val_to_name[class_val-1];
+        cladatum = hashtab_search(p->p_classes.table, pol_class);
+        BUG_ON( !cladatum );
+        if ( !cladatum->comdatum )
+        {
+            printk(KERN_ERR
+            "Flask:  class %s should have an inherits clause but does not\n",
+                   pol_class);
+            return -EINVAL;
+        }
+        tmp = kdefs->av_inherit[i].common_base;
+        common_pts_len = 0;
+        while ( !(tmp & 0x01) )
+        {
+            common_pts_len++;
+            tmp >>= 1;
+        }
+        perms = &cladatum->comdatum->permissions;
+        for ( j = 0; j < common_pts_len; j++ )
+        {
+            def_perm = kdefs->av_inherit[i].common_pts[j];
+            if ( j >= perms->nprim )
+            {
+                printk(KERN_INFO
+                "Flask:  permission %s in class %s not defined in policy\n",
+                       def_perm, pol_class);
+                return -EINVAL;
+            }
+            perdatum = hashtab_search(perms->table, def_perm);
+            if ( perdatum == NULL )
+            {
+                printk(KERN_ERR
+                       "Flask:  permission %s in class %s not found in 
policy\n",
+                       def_perm, pol_class);
+                return -EINVAL;
+            }
+            if ( perdatum->value != j + 1 )
+            {
+                printk(KERN_ERR
+                      "Flask:  permission %s in class %s has incorrect 
value\n",
+                       def_perm, pol_class);
+                return -EINVAL;
+            }
+        }
+    }
+    return 0;
 }
 
 /* Clone the SID into the new SID table. */
@@ -1105,7 +1306,7 @@ static inline int convert_context_handle
         u32 len;
 
         context_struct_to_string(context, &s, &len);
-        printk(KERN_ERR "security:  context %s is invalid\n", s);
+        printk(KERN_ERR "Flask:  context %s is invalid\n", s);
         xfree(s);
     }
     return rc;
@@ -1184,12 +1385,12 @@ bad:
 bad:
     context_struct_to_string(&oldc, &s, &len);
     context_destroy(&oldc);
-    printk(KERN_ERR "security:  invalidating context %s\n", s);
+    printk(KERN_ERR "Flask:  invalidating context %s\n", s);
     xfree(s);
     goto out;
 }
 
-extern void flask_complete_init(void);
+static int security_preserve_bools(struct policydb *p);
 
 /**
  * security_load_policy - Load a security policy configuration.
@@ -1225,6 +1426,14 @@ int security_load_policy(void *data, siz
             policydb_destroy(&policydb);
             return -EINVAL;
         }
+        if ( validate_classes(&policydb) )
+        {
+            printk(KERN_ERR
+                   "Flask:  the definition of a class is incorrect\n");
+            sidtab_destroy(&sidtab);
+            policydb_destroy(&policydb);
+            return -EINVAL;
+        }
         policydb_loaded_version = policydb.policyvers;
         ss_initialized = 1;
         seqno = ++latest_granting;
@@ -1245,12 +1454,19 @@ int security_load_policy(void *data, siz
 
     sidtab_init(&newsidtab);
 
-    /* Verify that the existing classes did not change. */
-    if ( hashtab_map(policydb.p_classes.table, validate_class, &newpolicydb) )
-    {
-        printk(KERN_ERR "security:  the definition of an existing "
-                                                            "class changed\n");
+    /* Verify that the kernel defined classes are correct. */
+    if ( validate_classes(&newpolicydb) )
+    {
+        printk(KERN_ERR
+               "Flask:  the definition of a class is incorrect\n");
         rc = -EINVAL;
+        goto err;
+    }
+
+    rc = security_preserve_bools(&newpolicydb);
+    if ( rc )
+    {
+        printk(KERN_ERR "Flask:  unable to preserve booleans\n");
         goto err;
     }
 
@@ -1517,15 +1733,11 @@ int security_get_user_sids(u32 fromsid, 
     }
     memset(mysids, 0, maxnel*sizeof(*mysids));
 
-    ebitmap_for_each_bit(&user->roles, rnode, i)
-    {
-        if ( !ebitmap_node_get_bit(rnode, i) )
-            continue;
+    ebitmap_for_each_positive_bit(&user->roles, rnode, i)
+    {
         role = policydb.role_val_to_struct[i];
         usercon.role = i+1;
-        ebitmap_for_each_bit(&role->types, tnode, j) {
-            if ( !ebitmap_node_get_bit(tnode, j) )
-                continue;
+        ebitmap_for_each_positive_bit(&role->types, tnode, j) {
             usercon.type = j+1;
 
             if ( mls_setup_user_range(fromcon, user, &usercon) )
@@ -1640,7 +1852,7 @@ int security_set_bools(int len, int *val
         goto out;
     }
 
-    printk(KERN_INFO "security: committed booleans { ");
+    printk(KERN_INFO "Flask: committed booleans { ");
     for ( i = 0; i < len; i++ )
     {
         if ( values[i] )
@@ -1695,3 +1907,37 @@ out:
     POLICY_RDUNLOCK;
     return rc;
 }
+
+static int security_preserve_bools(struct policydb *p)
+{
+    int rc, nbools = 0, *bvalues = NULL, i;
+    char **bnames = NULL;
+    struct cond_bool_datum *booldatum;
+    struct cond_node *cur;
+
+    rc = security_get_bools(&nbools, &bnames, &bvalues);
+    if ( rc )
+        goto out;
+    for ( i = 0; i < nbools; i++ )
+    {
+        booldatum = hashtab_search(p->p_bools.table, bnames[i]);
+        if ( booldatum )
+            booldatum->state = bvalues[i];
+    }
+    for ( cur = p->cond_list; cur; cur = cur->next )
+    {
+        rc = evaluate_cond_node(p, cur);
+        if ( rc )
+            goto out;
+    }
+
+out:
+    if ( bnames )
+    {
+        for ( i = 0; i < nbools; i++ )
+            xfree(bnames[i]);
+    }
+    xfree(bnames);
+    xfree(bvalues);
+    return rc;
+}
diff -r b79da5f5ffe7 -r 001a99da1294 xen/xsm/flask/ss/sidtab.c
--- a/xen/xsm/flask/ss/sidtab.c Wed Aug 19 14:22:15 2009 +0100
+++ b/xen/xsm/flask/ss/sidtab.c Wed Aug 19 14:22:52 2009 +0100
@@ -24,7 +24,7 @@ int sidtab_init(struct sidtab *s)
 {
     int i;
 
-    s->htable = (void *)xmalloc_array(struct sidtab_node, SIDTAB_SIZE);
+    s->htable = xmalloc_array(struct sidtab_node *, SIDTAB_SIZE);
     if ( !s->htable )
         return -ENOMEM;
     for ( i = 0; i < SIDTAB_SIZE; i++ )
diff -r b79da5f5ffe7 -r 001a99da1294 xen/xsm/flask/ss/symtab.c
--- a/xen/xsm/flask/ss/symtab.c Wed Aug 19 14:22:15 2009 +0100
+++ b/xen/xsm/flask/ss/symtab.c Wed Aug 19 14:22:52 2009 +0100
@@ -12,9 +12,9 @@
 #include <xen/errno.h>
 #include "symtab.h"
 
-static unsigned int symhash(struct hashtab *h, void *key)
+static unsigned int symhash(struct hashtab *h, const void *key)
 {
-    char *p, *keyp;
+    const char *p, *keyp;
     unsigned int size;
     unsigned int val;
 
@@ -26,9 +26,9 @@ static unsigned int symhash(struct hasht
     return val & (h->size - 1);
 }
 
-static int symcmp(struct hashtab *h, void *key1, void *key2)
+static int symcmp(struct hashtab *h, const void *key1, const void *key2)
 {
-    char *keyp1, *keyp2;
+    const char *keyp1, *keyp2;
 
     keyp1 = key1;
     keyp2 = key2;

_______________________________________________
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®.