vserver 2.0 rc7
[linux-2.6.git] / security / selinux / ss / mls.c
index 5ef5bd5..756036b 100644 (file)
@@ -3,6 +3,14 @@
  *
  * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
  */
+/*
+ * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
+ *
+ *     Support for enhanced MLS infrastructure.
+ *
+ * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
+ */
+
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/string.h>
 #include "policydb.h"
 #include "services.h"
 
-/*
- * Remove any permissions from `allowed' that are
- * denied by the MLS policy.
- */
-void mls_compute_av(struct context *scontext,
-                   struct context *tcontext,
-                   struct class_datum *tclass,
-                   u32 *allowed)
-{
-       unsigned int rel[2];
-       int l;
-
-       for (l = 0; l < 2; l++)
-               rel[l] = mls_level_relation(scontext->range.level[l],
-                                           tcontext->range.level[l]);
-
-       if (rel[1] != MLS_RELATION_EQ) {
-               if (rel[1] != MLS_RELATION_DOM &&
-                   !ebitmap_get_bit(&policydb.trustedreaders, scontext->type - 1) &&
-                   !ebitmap_get_bit(&policydb.trustedobjects, tcontext->type - 1)) {
-                       /* read(s,t) = (s.high >= t.high) = False */
-                       *allowed = (*allowed) & ~(tclass->mlsperms.read);
-               }
-               if (rel[1] != MLS_RELATION_DOMBY &&
-                   !ebitmap_get_bit(&policydb.trustedreaders, tcontext->type - 1) &&
-                   !ebitmap_get_bit(&policydb.trustedobjects, scontext->type - 1)) {
-                       /* readby(s,t) = read(t,s) = False */
-                       *allowed = (*allowed) & ~(tclass->mlsperms.readby);
-               }
-       }
-       if (((rel[0] != MLS_RELATION_DOMBY && rel[0] != MLS_RELATION_EQ) ||
-           ((!mls_level_eq(tcontext->range.level[0],
-                           tcontext->range.level[1])) &&
-            (rel[1] != MLS_RELATION_DOM && rel[1] != MLS_RELATION_EQ))) &&
-           !ebitmap_get_bit(&policydb.trustedwriters, scontext->type - 1) &&
-           !ebitmap_get_bit(&policydb.trustedobjects, tcontext->type - 1)) {
-               /*
-                * write(s,t) = ((s.low <= t.low = t.high) or (s.low
-                * <= t.low <= t.high <= s.high)) = False
-                */
-               *allowed = (*allowed) & ~(tclass->mlsperms.write);
-       }
-
-       if (((rel[0] != MLS_RELATION_DOM && rel[0] != MLS_RELATION_EQ) ||
-           ((!mls_level_eq(scontext->range.level[0],
-                           scontext->range.level[1])) &&
-            (rel[1] != MLS_RELATION_DOMBY && rel[1] != MLS_RELATION_EQ))) &&
-           !ebitmap_get_bit(&policydb.trustedwriters, tcontext->type - 1) &&
-           !ebitmap_get_bit(&policydb.trustedobjects, scontext->type - 1)) {
-               /* writeby(s,t) = write(t,s) = False */
-               *allowed = (*allowed) & ~(tclass->mlsperms.writeby);
-       }
-}
-
 /*
  * Return the length in bytes for the MLS fields of the
  * security context string representation of `context'.
  */
 int mls_compute_context_len(struct context * context)
 {
-       int i, l, len;
+       int i, l, len, range;
 
+       if (!selinux_mls_enabled)
+               return 0;
 
-       len = 0;
+       len = 1; /* for the beginning ":" */
        for (l = 0; l < 2; l++) {
-               len += strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1]) + 1;
+               range = 0;
+               len += strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
 
-               for (i = 1; i <= ebitmap_length(&context->range.level[l].cat); i++)
-                       if (ebitmap_get_bit(&context->range.level[l].cat, i - 1))
-                               len += strlen(policydb.p_cat_val_to_name[i - 1]) + 1;
+               for (i = 1; i <= ebitmap_length(&context->range.level[l].cat); i++) {
+                       if (ebitmap_get_bit(&context->range.level[l].cat, i - 1)) {
+                               if (range) {
+                                       range++;
+                                       continue;
+                               }
 
-               if (mls_level_relation(context->range.level[0], context->range.level[1])
-                               == MLS_RELATION_EQ)
-                       break;
+                               len += strlen(policydb.p_cat_val_to_name[i - 1]) + 1;
+                               range++;
+                       } else {
+                               if (range > 1)
+                                       len += strlen(policydb.p_cat_val_to_name[i - 2]) + 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 - 2]) + 1;
+
+               if (l == 0) {
+                       if (mls_level_eq(&context->range.level[0],
+                                        &context->range.level[1]))
+                               break;
+                       else
+                               len++;
+               }
        }
 
        return len;
@@ -95,40 +71,81 @@ int mls_compute_context_len(struct context * context)
  * the MLS fields of `context' into the string `*scontext'.
  * Update `*scontext' to point to the end of the MLS fields.
  */
-int mls_sid_to_context(struct context *context,
-                      char **scontext)
+void mls_sid_to_context(struct context *context,
+                        char **scontext)
 {
        char *scontextp;
-       int i, l;
+       int i, l, range, wrote_sep;
+
+       if (!selinux_mls_enabled)
+               return;
 
        scontextp = *scontext;
 
+       *scontextp = ':';
+       scontextp++;
+
        for (l = 0; l < 2; l++) {
+               range = 0;
+               wrote_sep = 0;
                strcpy(scontextp,
                       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 = ':';
-               scontextp++;
-               for (i = 1; i <= ebitmap_length(&context->range.level[l].cat); i++)
+
+               /* categories */
+               for (i = 1; i <= ebitmap_length(&context->range.level[l].cat); i++) {
                        if (ebitmap_get_bit(&context->range.level[l].cat, i - 1)) {
+                               if (range) {
+                                       range++;
+                                       continue;
+                               }
+
+                               if (!wrote_sep) {
+                                       *scontextp++ = ':';
+                                       wrote_sep = 1;
+                               } else
+                                       *scontextp++ = ',';
                                strcpy(scontextp, policydb.p_cat_val_to_name[i - 1]);
                                scontextp += strlen(policydb.p_cat_val_to_name[i - 1]);
-                               *scontextp = ',';
-                               scontextp++;
+                               range++;
+                       } else {
+                               if (range > 1) {
+                                       if (range > 2)
+                                               *scontextp++ = '.';
+                                       else
+                                               *scontextp++ = ',';
+
+                                       strcpy(scontextp, policydb.p_cat_val_to_name[i - 2]);
+                                       scontextp += strlen(policydb.p_cat_val_to_name[i - 2]);
+                               }
+                               range = 0;
                        }
-               if (mls_level_relation(context->range.level[0], context->range.level[1])
-                               != MLS_RELATION_EQ) {
-                       scontextp--;
-                       sprintf(scontextp, "-");
-                       scontextp++;
+               }
 
-               } else {
-                       break;
+               /* Handle case where last category is the end of range */
+               if (range > 1) {
+                       if (range > 2)
+                               *scontextp++ = '.';
+                       else
+                               *scontextp++ = ',';
+
+                       strcpy(scontextp, policydb.p_cat_val_to_name[i - 2]);
+                       scontextp += strlen(policydb.p_cat_val_to_name[i - 2]);
+               }
+
+               if (l == 0) {
+                       if (mls_level_eq(&context->range.level[0],
+                                        &context->range.level[1]))
+                               break;
+                       else {
+                               *scontextp = '-';
+                               scontextp++;
+                       }
                }
        }
 
        *scontext = scontextp;
-       return 0;
+       return;
 }
 
 /*
@@ -137,20 +154,19 @@ int mls_sid_to_context(struct context *context,
  */
 int mls_context_isvalid(struct policydb *p, struct context *c)
 {
-       unsigned int relation;
        struct level_datum *levdatum;
        struct user_datum *usrdatum;
-       struct mls_range_list *rnode;
        int i, l;
 
+       if (!selinux_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)
         */
-       relation = mls_level_relation(c->range.level[1],
-                                     c->range.level[0]);
-       if (!(relation & (MLS_RELATION_DOM | MLS_RELATION_EQ)))
+       if (!mls_level_dom(&c->range.level[1], &c->range.level[0]))
                /* High does not dominate low. */
                return 0;
 
@@ -185,18 +201,12 @@ int mls_context_isvalid(struct policydb *p, struct context *c)
        if (!c->user || c->user > p->p_users.nprim)
                return 0;
        usrdatum = p->user_val_to_struct[c->user - 1];
-       for (rnode = usrdatum->ranges; rnode; rnode = rnode->next) {
-               if (mls_range_contains(rnode->range, c->range))
-                       break;
-       }
-       if (!rnode)
-               /* user may not be associated with range */
-               return 0;
+       if (!mls_range_contains(usrdatum->range, c->range))
+               return 0; /* user may not be associated with range */
 
        return 1;
 }
 
-
 /*
  * Set the MLS fields in the security context structure
  * `context' based on the string representation in
@@ -213,23 +223,17 @@ int mls_context_to_sid(char oldc,
 {
 
        char delim;
-       char *scontextp, *p;
+       char *scontextp, *p, *rngptr;
        struct level_datum *levdatum;
-       struct cat_datum *catdatum;
+       struct cat_datum *catdatum, *rngdatum;
        int l, rc = -EINVAL;
 
-       if (!oldc) {
-               /* No MLS component to the security context.  Try
-                  to use a default 'unclassified' value. */
-               levdatum = hashtab_search(policydb.p_levels.table,
-                                         "unclassified");
-               if (!levdatum)
-                       goto out;
-               context->range.level[0].sens = levdatum->level->sens;
-               context->range.level[1].sens = context->range.level[0].sens;
-               rc = 0;
+       if (!selinux_mls_enabled)
+               return 0;
+
+       /* No MLS component to the security context. */
+       if (!oldc)
                goto out;
-       }
 
        /* Extract low sensitivity. */
        scontextp = p = *scontext;
@@ -242,13 +246,15 @@ int mls_context_to_sid(char oldc,
 
        for (l = 0; l < 2; l++) {
                levdatum = hashtab_search(policydb.p_levels.table, scontextp);
-               if (!levdatum)
+               if (!levdatum) {
+                       rc = -EINVAL;
                        goto out;
+               }
 
                context->range.level[l].sens = levdatum->level->sens;
 
                if (delim == ':') {
-                       /* Extract low category set. */
+                       /* Extract category set. */
                        while (1) {
                                scontextp = p;
                                while (*p && *p != ',' && *p != '-')
@@ -257,15 +263,46 @@ int mls_context_to_sid(char oldc,
                                if (delim != 0)
                                        *p++ = 0;
 
+                               /* Separate into range if exists */
+                               if ((rngptr = strchr(scontextp, '.')) != NULL) {
+                                       /* Remove '.' */
+                                       *rngptr++ = 0;
+                               }
+
                                catdatum = hashtab_search(policydb.p_cats.table,
                                                          scontextp);
-                               if (!catdatum)
+                               if (!catdatum) {
+                                       rc = -EINVAL;
                                        goto out;
+                               }
 
                                rc = ebitmap_set_bit(&context->range.level[l].cat,
                                                     catdatum->value - 1, 1);
                                if (rc)
                                        goto out;
+
+                               /* If range, set all categories in range */
+                               if (rngptr) {
+                                       int i;
+
+                                       rngdatum = hashtab_search(policydb.p_cats.table, rngptr);
+                                       if (!rngdatum) {
+                                               rc = -EINVAL;
+                                               goto out;
+                                       }
+
+                                       if (catdatum->value >= rngdatum->value) {
+                                               rc = -EINVAL;
+                                               goto out;
+                                       }
+
+                                       for (i = catdatum->value; i < rngdatum->value; i++) {
+                                               rc = ebitmap_set_bit(&context->range.level[l].cat, i, 1);
+                                               if (rc)
+                                                       goto out;
+                                       }
+                               }
+
                                if (delim != ',')
                                        break;
                        }
@@ -306,7 +343,6 @@ static inline int mls_copy_context(struct context *dst,
 
        /* 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);
@@ -317,6 +353,84 @@ static inline int mls_copy_context(struct context *dst,
        return rc;
 }
 
+/*
+ * Copies the effective MLS range from `src' into `dst'.
+ */
+static inline int mls_scopy_context(struct context *dst,
+                                    struct context *src)
+{
+       int l, rc = 0;
+
+       /* Copy the MLS range from the source context */
+       for (l = 0; l < 2; l++) {
+               dst->range.level[l].sens = src->range.level[0].sens;
+               rc = ebitmap_cpy(&dst->range.level[l].cat,
+                                &src->range.level[0].cat);
+               if (rc)
+                       break;
+       }
+
+       return rc;
+}
+
+/*
+ * Copies the MLS range `range' into `context'.
+ */
+static inline int mls_range_set(struct context *context,
+                                struct mls_range *range)
+{
+       int l, rc = 0;
+
+       /* Copy the MLS range into the  context */
+       for (l = 0; l < 2; l++) {
+               context->range.level[l].sens = range->level[l].sens;
+               rc = ebitmap_cpy(&context->range.level[l].cat,
+                                &range->level[l].cat);
+               if (rc)
+                       break;
+       }
+
+       return rc;
+}
+
+int mls_setup_user_range(struct context *fromcon, struct user_datum *user,
+                         struct context *usercon)
+{
+       if (selinux_mls_enabled) {
+               struct mls_level *fromcon_sen = &(fromcon->range.level[0]);
+               struct mls_level *fromcon_clr = &(fromcon->range.level[1]);
+               struct mls_level *user_low = &(user->range.level[0]);
+               struct mls_level *user_clr = &(user->range.level[1]);
+               struct mls_level *user_def = &(user->dfltlevel);
+               struct mls_level *usercon_sen = &(usercon->range.level[0]);
+               struct mls_level *usercon_clr = &(usercon->range.level[1]);
+
+               /* Honor the user's default level if we can */
+               if (mls_level_between(user_def, fromcon_sen, fromcon_clr)) {
+                       *usercon_sen = *user_def;
+               } else if (mls_level_between(fromcon_sen, user_def, user_clr)) {
+                       *usercon_sen = *fromcon_sen;
+               } else if (mls_level_between(fromcon_clr, user_low, user_def)) {
+                       *usercon_sen = *user_low;
+               } else
+                       return -EINVAL;
+
+               /* Lower the clearance of available contexts
+                  if the clearance of "fromcon" is lower than
+                  that of the user's default clearance (but
+                  only if the "fromcon" clearance dominates
+                  the user's computed sensitivity level) */
+               if (mls_level_dom(user_clr, fromcon_clr)) {
+                       *usercon_clr = *fromcon_clr;
+               } else if (mls_level_dom(fromcon_clr, user_clr)) {
+                       *usercon_clr = *user_clr;
+               } else
+                       return -EINVAL;
+       }
+
+       return 0;
+}
+
 /*
  * Convert the MLS fields in the security context
  * structure `c' from the values specified in the
@@ -331,6 +445,9 @@ int mls_convert_context(struct policydb *oldp,
        struct ebitmap bitmap;
        int l, i;
 
+       if (!selinux_mls_enabled)
+               return 0;
+
        for (l = 0; l < 2; l++) {
                levdatum = hashtab_search(newp->p_levels.table,
                        oldp->p_sens_val_to_name[c->range.level[l].sens - 1]);
@@ -366,17 +483,38 @@ int mls_compute_sid(struct context *scontext,
                    u32 specified,
                    struct context *newcontext)
 {
+       if (!selinux_mls_enabled)
+               return 0;
+
        switch (specified) {
        case AVTAB_TRANSITION:
+               if (tclass == SECCLASS_PROCESS) {
+                       struct range_trans *rangetr;
+                       /* Look for a range transition rule. */
+                       for (rangetr = policydb.range_tr; rangetr;
+                            rangetr = rangetr->next) {
+                               if (rangetr->dom == scontext->type &&
+                                   rangetr->type == tcontext->type) {
+                                       /* Set the range from the rule */
+                                       return mls_range_set(newcontext,
+                                                            &rangetr->range);
+                               }
+                       }
+               }
+               /* Fallthrough */
        case AVTAB_CHANGE:
-               /* Use the process MLS attributes. */
-               return mls_copy_context(newcontext, scontext);
+               if (tclass == SECCLASS_PROCESS)
+                       /* Use the process MLS attributes. */
+                       return mls_copy_context(newcontext, scontext);
+               else
+                       /* Use the process effective MLS attributes. */
+                       return mls_scopy_context(newcontext, scontext);
        case AVTAB_MEMBER:
                /* Only polyinstantiate the MLS attributes if
                   the type is being polyinstantiated */
                if (newcontext->type != tcontext->type) {
-                       /* Use the process MLS attributes. */
-                       return mls_copy_context(newcontext, scontext);
+                       /* 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);
@@ -387,365 +525,3 @@ int mls_compute_sid(struct context *scontext,
        return -EINVAL;
 }
 
-void mls_user_destroy(struct user_datum *usrdatum)
-{
-       struct mls_range_list *rnode, *rtmp;
-       rnode = usrdatum->ranges;
-       while (rnode) {
-               rtmp = rnode;
-               rnode = rnode->next;
-               ebitmap_destroy(&rtmp->range.level[0].cat);
-               ebitmap_destroy(&rtmp->range.level[1].cat);
-               kfree(rtmp);
-       }
-}
-
-int mls_read_perm(struct perm_datum *perdatum, void *fp)
-{
-       u32 buf[1];
-       int rc;
-
-       rc = next_entry(buf, fp, sizeof buf);
-       if (rc < 0)
-               return -EINVAL;
-       perdatum->base_perms = le32_to_cpu(buf[0]);
-       return 0;
-}
-
-/*
- * Read a MLS level structure from a policydb binary
- * representation file.
- */
-struct mls_level *mls_read_level(void *fp)
-{
-       struct mls_level *l;
-       u32 buf[1];
-       int rc;
-
-       l = kmalloc(sizeof(*l), GFP_ATOMIC);
-       if (!l) {
-               printk(KERN_ERR "security: mls: out of memory\n");
-               return NULL;
-       }
-       memset(l, 0, sizeof(*l));
-
-       rc = next_entry(buf, fp, sizeof buf);
-       if (rc < 0) {
-               printk(KERN_ERR "security: mls: truncated level\n");
-               goto bad;
-       }
-       l->sens = cpu_to_le32(buf[0]);
-
-       if (ebitmap_read(&l->cat, fp)) {
-               printk(KERN_ERR "security: mls:  error reading level "
-                      "categories\n");
-               goto bad;
-       }
-       return l;
-
-bad:
-       kfree(l);
-       return NULL;
-}
-
-
-/*
- * Read a MLS range structure from a policydb binary
- * representation file.
- */
-static int mls_read_range_helper(struct mls_range *r, void *fp)
-{
-       u32 buf[2], items;
-       int rc;
-
-       rc = next_entry(buf, fp, sizeof(u32));
-       if (rc < 0)
-               goto out;
-
-       items = le32_to_cpu(buf[0]);
-       if (items > ARRAY_SIZE(buf)) {
-               printk(KERN_ERR "security: mls:  range overflow\n");
-               rc = -EINVAL;
-               goto out;
-       }
-       rc = next_entry(buf, fp, sizeof(u32) * items);
-       if (rc < 0) {
-               printk(KERN_ERR "security: mls:  truncated range\n");
-               goto out;
-       }
-       r->level[0].sens = le32_to_cpu(buf[0]);
-       if (items > 1) {
-               r->level[1].sens = le32_to_cpu(buf[1]);
-       } else {
-               r->level[1].sens = r->level[0].sens;
-       }
-
-       rc = ebitmap_read(&r->level[0].cat, fp);
-       if (rc) {
-               printk(KERN_ERR "security: mls:  error reading low "
-                      "categories\n");
-               goto out;
-       }
-       if (items > 1) {
-               rc = ebitmap_read(&r->level[1].cat, fp);
-               if (rc) {
-                       printk(KERN_ERR "security: mls:  error reading high "
-                              "categories\n");
-                       goto bad_high;
-               }
-       } else {
-               rc = ebitmap_cpy(&r->level[1].cat, &r->level[0].cat);
-               if (rc) {
-                       printk(KERN_ERR "security: mls:  out of memory\n");
-                       goto bad_high;
-               }
-       }
-
-       rc = 0;
-out:
-       return rc;
-bad_high:
-       ebitmap_destroy(&r->level[0].cat);
-       goto out;
-}
-
-int mls_read_range(struct context *c, void *fp)
-{
-       return mls_read_range_helper(&c->range, fp);
-}
-
-
-/*
- * Read a MLS perms structure from a policydb binary
- * representation file.
- */
-int mls_read_class(struct class_datum *cladatum, void *fp)
-{
-       struct mls_perms *p = &cladatum->mlsperms;
-       u32 buf[4];
-       int rc;
-
-       rc = next_entry(buf, fp, sizeof buf);
-       if (rc < 0) {
-               printk(KERN_ERR "security: mls:  truncated mls permissions\n");
-               return -EINVAL;
-       }
-       p->read = le32_to_cpu(buf[0]);
-       p->readby = le32_to_cpu(buf[1]);
-       p->write = le32_to_cpu(buf[2]);
-       p->writeby = le32_to_cpu(buf[3]);
-       return 0;
-}
-
-int mls_read_user(struct user_datum *usrdatum, void *fp)
-{
-       struct mls_range_list *r, *l;
-       int rc;
-       u32 nel, i;
-       u32 buf[1];
-
-       rc = next_entry(buf, fp, sizeof buf);
-       if (rc < 0)
-               goto out;
-       nel = le32_to_cpu(buf[0]);
-       l = NULL;
-       for (i = 0; i < nel; i++) {
-               r = kmalloc(sizeof(*r), GFP_ATOMIC);
-               if (!r) {
-                       rc = -ENOMEM;
-                       goto out;
-               }
-               memset(r, 0, sizeof(*r));
-
-               rc = mls_read_range_helper(&r->range, fp);
-               if (rc) {
-                       kfree(r);
-                       goto out;
-               }
-
-               if (l)
-                       l->next = r;
-               else
-                       usrdatum->ranges = r;
-               l = r;
-       }
-out:
-       return rc;
-}
-
-int mls_read_nlevels(struct policydb *p, void *fp)
-{
-       u32 buf[1];
-       int rc;
-
-       rc = next_entry(buf, fp, sizeof buf);
-       if (rc < 0)
-               return -EINVAL;
-       p->nlevels = le32_to_cpu(buf[0]);
-       return 0;
-}
-
-int mls_read_trusted(struct policydb *p, void *fp)
-{
-       int rc = 0;
-
-       rc = ebitmap_read(&p->trustedreaders, fp);
-       if (rc)
-               goto out;
-       rc = ebitmap_read(&p->trustedwriters, fp);
-       if (rc)
-               goto bad;
-       rc = ebitmap_read(&p->trustedobjects, fp);
-       if (rc)
-               goto bad2;
-out:
-       return rc;
-bad2:
-       ebitmap_destroy(&p->trustedwriters);
-bad:
-       ebitmap_destroy(&p->trustedreaders);
-       goto out;
-}
-
-int sens_index(void *key, void *datum, void *datap)
-{
-       struct policydb *p;
-       struct level_datum *levdatum;
-
-
-       levdatum = datum;
-       p = datap;
-
-       if (!levdatum->isalias)
-               p->p_sens_val_to_name[levdatum->level->sens - 1] = key;
-
-       return 0;
-}
-
-int cat_index(void *key, void *datum, void *datap)
-{
-       struct policydb *p;
-       struct cat_datum *catdatum;
-
-
-       catdatum = datum;
-       p = datap;
-
-
-       if (!catdatum->isalias)
-               p->p_cat_val_to_name[catdatum->value - 1] = key;
-
-       return 0;
-}
-
-int sens_destroy(void *key, void *datum, void *p)
-{
-       struct level_datum *levdatum;
-
-       kfree(key);
-       levdatum = datum;
-       if (!levdatum->isalias) {
-               ebitmap_destroy(&levdatum->level->cat);
-               kfree(levdatum->level);
-       }
-       kfree(datum);
-       return 0;
-}
-
-int cat_destroy(void *key, void *datum, void *p)
-{
-       kfree(key);
-       kfree(datum);
-       return 0;
-}
-
-int sens_read(struct policydb *p, struct hashtab *h, void *fp)
-{
-       char *key = NULL;
-       struct level_datum *levdatum;
-       int rc;
-       u32 buf[2], len;
-
-       levdatum = kmalloc(sizeof(*levdatum), GFP_ATOMIC);
-       if (!levdatum) {
-               rc = -ENOMEM;
-               goto out;
-       }
-       memset(levdatum, 0, sizeof(*levdatum));
-
-       rc = next_entry(buf, fp, sizeof buf);
-       if (rc < 0)
-               goto bad;
-
-       len = le32_to_cpu(buf[0]);
-       levdatum->isalias = le32_to_cpu(buf[1]);
-
-       key = kmalloc(len + 1,GFP_ATOMIC);
-       if (!key) {
-               rc = -ENOMEM;
-               goto bad;
-       }
-       rc = next_entry(key, fp, len);
-       if (rc < 0)
-               goto bad;
-       key[len] = 0;
-
-       levdatum->level = mls_read_level(fp);
-       if (!levdatum->level) {
-               rc = -EINVAL;
-               goto bad;
-       }
-
-       rc = hashtab_insert(h, key, levdatum);
-       if (rc)
-               goto bad;
-out:
-       return rc;
-bad:
-       sens_destroy(key, levdatum, NULL);
-       goto out;
-}
-
-
-int cat_read(struct policydb *p, struct hashtab *h, void *fp)
-{
-       char *key = NULL;
-       struct cat_datum *catdatum;
-       int rc;
-       u32 buf[3], len;
-
-       catdatum = kmalloc(sizeof(*catdatum), GFP_ATOMIC);
-       if (!catdatum) {
-               rc = -ENOMEM;
-               goto out;
-       }
-       memset(catdatum, 0, sizeof(*catdatum));
-
-       rc = next_entry(buf, fp, sizeof buf);
-       if (rc < 0)
-               goto bad;
-
-       len = le32_to_cpu(buf[0]);
-       catdatum->value = le32_to_cpu(buf[1]);
-       catdatum->isalias = le32_to_cpu(buf[2]);
-
-       key = kmalloc(len + 1,GFP_ATOMIC);
-       if (!key) {
-               rc = -ENOMEM;
-               goto bad;
-       }
-       rc = next_entry(key, fp, len);
-       if (rc < 0)
-               goto bad;
-       key[len] = 0;
-
-       rc = hashtab_insert(h, key, catdatum);
-       if (rc)
-               goto bad;
-out:
-       return rc;
-
-bad:
-       cat_destroy(key, catdatum, NULL);
-       goto out;
-}