selinux: convert type_val_to_struct to flex_array
[linux-flexiantxendom0-natty.git] / security / selinux / ss / services.c
index f26a8ca..afcbc19 100644 (file)
  *
  *  Added validation of kernel classes and permissions
  *
+ * Updated: KaiGai Kohei <kaigai@ak.jp.nec.com>
+ *
+ *  Added support for bounds domain and audit messaged on masked permissions
+ *
+ * Updated: Guido Trentalancia <guido@trentalancia.com>
+ *
+ *  Added support for runtime switching of the policy type
+ *
+ * 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
@@ -41,6 +50,8 @@
 #include <linux/audit.h>
 #include <linux/mutex.h>
 #include <linux/selinux.h>
+#include <linux/flex_array.h>
+#include <linux/vmalloc.h>
 #include <net/netlabel.h>
 
 #include "flask.h"
 #include "audit.h"
 
 extern void selnl_notify_policyload(u32 seqno);
-unsigned int policydb_loaded_version;
 
 int selinux_policycap_netpeer;
 int selinux_policycap_openperm;
 
-/*
- * This is declared in avc.c
- */
-extern const struct selinux_class_perm selinux_class_perm;
-
 static DEFINE_RWLOCK(policy_rwlock);
-static DEFINE_MUTEX(load_mutex);
 
 static struct sidtab sidtab;
 struct policydb policydb;
@@ -89,6 +93,156 @@ static u32 latest_granting;
 static int context_struct_to_string(struct context *context, char **scontext,
                                    u32 *scontext_len);
 
+static void context_struct_compute_av(struct context *scontext,
+                                     struct context *tcontext,
+                                     u16 tclass,
+                                     struct av_decision *avd);
+
+struct selinux_mapping {
+       u16 value; /* policy value */
+       unsigned num_perms;
+       u32 perms[sizeof(u32) * 8];
+};
+
+static struct selinux_mapping *current_mapping;
+static u16 current_mapping_size;
+
+static int selinux_set_mapping(struct policydb *pol,
+                              struct security_class_mapping *map,
+                              struct selinux_mapping **out_map_p,
+                              u16 *out_map_size)
+{
+       struct selinux_mapping *out_map = NULL;
+       size_t size = sizeof(struct selinux_mapping);
+       u16 i, j;
+       unsigned k;
+       bool print_unknown_handle = false;
+
+       /* Find number of classes in the input mapping */
+       if (!map)
+               return -EINVAL;
+       i = 0;
+       while (map[i].name)
+               i++;
+
+       /* Allocate space for the class records, plus one for class zero */
+       out_map = kcalloc(++i, size, GFP_ATOMIC);
+       if (!out_map)
+               return -ENOMEM;
+
+       /* Store the raw class and permission values */
+       j = 0;
+       while (map[j].name) {
+               struct security_class_mapping *p_in = map + (j++);
+               struct selinux_mapping *p_out = out_map + j;
+
+               /* An empty class string skips ahead */
+               if (!strcmp(p_in->name, "")) {
+                       p_out->num_perms = 0;
+                       continue;
+               }
+
+               p_out->value = string_to_security_class(pol, p_in->name);
+               if (!p_out->value) {
+                       printk(KERN_INFO
+                              "SELinux:  Class %s not defined in policy.\n",
+                              p_in->name);
+                       if (pol->reject_unknown)
+                               goto err;
+                       p_out->num_perms = 0;
+                       print_unknown_handle = true;
+                       continue;
+               }
+
+               k = 0;
+               while (p_in->perms && p_in->perms[k]) {
+                       /* An empty permission string skips ahead */
+                       if (!*p_in->perms[k]) {
+                               k++;
+                               continue;
+                       }
+                       p_out->perms[k] = string_to_av_perm(pol, p_out->value,
+                                                           p_in->perms[k]);
+                       if (!p_out->perms[k]) {
+                               printk(KERN_INFO
+                                      "SELinux:  Permission %s in class %s not defined in policy.\n",
+                                      p_in->perms[k], p_in->name);
+                               if (pol->reject_unknown)
+                                       goto err;
+                               print_unknown_handle = true;
+                       }
+
+                       k++;
+               }
+               p_out->num_perms = k;
+       }
+
+       if (print_unknown_handle)
+               printk(KERN_INFO "SELinux: the above unknown classes and permissions will be %s\n",
+                      pol->allow_unknown ? "allowed" : "denied");
+
+       *out_map_p = out_map;
+       *out_map_size = i;
+       return 0;
+err:
+       kfree(out_map);
+       return -EINVAL;
+}
+
+/*
+ * Get real, policy values from mapped values
+ */
+
+static u16 unmap_class(u16 tclass)
+{
+       if (tclass < current_mapping_size)
+               return current_mapping[tclass].value;
+
+       return tclass;
+}
+
+static void map_decision(u16 tclass, struct av_decision *avd,
+                        int allow_unknown)
+{
+       if (tclass < current_mapping_size) {
+               unsigned i, n = current_mapping[tclass].num_perms;
+               u32 result;
+
+               for (i = 0, result = 0; i < n; i++) {
+                       if (avd->allowed & current_mapping[tclass].perms[i])
+                               result |= 1<<i;
+                       if (allow_unknown && !current_mapping[tclass].perms[i])
+                               result |= 1<<i;
+               }
+               avd->allowed = result;
+
+               for (i = 0, result = 0; i < n; i++)
+                       if (avd->auditallow & current_mapping[tclass].perms[i])
+                               result |= 1<<i;
+               avd->auditallow = result;
+
+               for (i = 0, result = 0; i < n; i++) {
+                       if (avd->auditdeny & current_mapping[tclass].perms[i])
+                               result |= 1<<i;
+                       if (!allow_unknown && !current_mapping[tclass].perms[i])
+                               result |= 1<<i;
+               }
+               /*
+                * In case the kernel has a bug and requests a permission
+                * between num_perms and the maximum permission number, we
+                * should audit that denial
+                */
+               for (; i < (sizeof(u32)*8); i++)
+                       result |= 1<<i;
+               avd->auditdeny = result;
+       }
+}
+
+int security_mls_enabled(void)
+{
+       return policydb.mls_enabled;
+}
+
 /*
  * Return the boolean value of a constraint expression
  * when it is applied to the specified source and target
@@ -122,15 +276,15 @@ static int constraint_expr_eval(struct context *scontext,
                case CEXPR_AND:
                        BUG_ON(sp < 1);
                        sp--;
-                       s[sp] &= s[sp+1];
+                       s[sp] &= s[sp + 1];
                        break;
                case CEXPR_OR:
                        BUG_ON(sp < 1);
                        sp--;
-                       s[sp] |= s[sp+1];
+                       s[sp] |= s[sp + 1];
                        break;
                case CEXPR_ATTR:
-                       if (sp == (CEXPR_MAXDEPTH-1))
+                       if (sp == (CEXPR_MAXDEPTH - 1))
                                return 0;
                        switch (e->attr) {
                        case CEXPR_USER:
@@ -275,15 +429,184 @@ mls_ops:
 }
 
 /*
- * Compute access vectors based on a context structure pair for
- * the permissions in a particular class.
+ * 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;
+       struct audit_buffer *ab;
+       char *tclass_name;
+       char *scontext_name = NULL;
+       char *tcontext_name = NULL;
+       char *permission_names[32];
+       int index;
+       u32 length;
+       bool need_comma = false;
+
+       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;
+
+       /* audit a message */
+       ab = audit_log_start(current->audit_context,
+                            GFP_ATOMIC, AUDIT_SELINUX_ERR);
+       if (!ab)
+               goto out;
+
+       audit_log_format(ab, "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;
+
+               audit_log_format(ab, "%s%s",
+                                need_comma ? "," : "",
+                                permission_names[index]
+                                ? permission_names[index] : "????");
+               need_comma = true;
+       }
+       audit_log_end(ab);
+out:
+       /* release scontext/tcontext */
+       kfree(tcontext_name);
+       kfree(scontext_name);
+
+       return;
+}
+
+/*
+ * security_boundary_permission - drops violated permissions
+ * on boundary constraint.
  */
-static int context_struct_compute_av(struct context *scontext,
+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;
+       struct type_datum *target;
+       u32 masked = 0;
+
+       source = flex_array_get_ptr(policydb.type_val_to_struct_array,
+                                   scontext->type - 1);
+       BUG_ON(!source);
+
+       target = flex_array_get_ptr(policydb.type_val_to_struct_array,
+                                   tcontext->type - 1);
+       BUG_ON(!target);
+
+       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,
+                                         &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,
+                                         &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,
+                                         &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 void context_struct_compute_av(struct context *scontext,
+                                     struct context *tcontext,
+                                     u16 tclass,
+                                     struct av_decision *avd)
+{
        struct constraint_node *constraint;
        struct role_allow *ra;
        struct avtab_key avkey;
@@ -291,56 +614,17 @@ static int context_struct_compute_av(struct context *scontext,
        struct class_datum *tclass_datum;
        struct ebitmap *sattr, *tattr;
        struct ebitmap_node *snode, *tnode;
-       const struct selinux_class_perm *kdefs = &selinux_class_perm;
        unsigned int i, j;
 
-       /*
-        * Remap extended Netlink classes for old policy versions.
-        * Do this here rather than socket_type_to_security_class()
-        * in case a newer policy version is loaded, allowing sockets
-        * to remain in the correct class.
-        */
-       if (policydb_loaded_version < POLICYDB_VERSION_NLCLASS)
-               if (tclass >= SECCLASS_NETLINK_ROUTE_SOCKET &&
-                   tclass <= SECCLASS_NETLINK_DNRT_SOCKET)
-                       tclass = SECCLASS_NETLINK_SOCKET;
-
-       /*
-        * Initialize the access vectors to the default values.
-        */
        avd->allowed = 0;
-       avd->decided = 0xffffffff;
        avd->auditallow = 0;
        avd->auditdeny = 0xffffffff;
-       avd->seqno = latest_granting;
 
-       /*
-        * Check for all the invalid cases.
-        * - tclass 0
-        * - tclass > policy and > kernel
-        * - tclass > policy but is a userspace class
-        * - tclass > policy but we do not allow unknowns
-        */
-       if (unlikely(!tclass))
-               goto inval_class;
-       if (unlikely(tclass > policydb.p_classes.nprim))
-               if (tclass > kdefs->cts_len ||
-                   !kdefs->class_to_string[tclass] ||
-                   !policydb.allow_unknown)
-                       goto inval_class;
-
-       /*
-        * Kernel class and we allow unknown so pad the allow decision
-        * the pad will be all 1 for unknown classes.
-        */
-       if (tclass <= kdefs->cts_len && policydb.allow_unknown)
-               avd->allowed = policydb.undefined_perms[tclass - 1];
-
-       /*
-        * Not in policy. Since decision is completed (all 1 or all 0) return.
-        */
-       if (unlikely(tclass > policydb.p_classes.nprim))
-               return 0;
+       if (unlikely(!tclass || tclass > policydb.p_classes.nprim)) {
+               if (printk_ratelimit())
+                       printk(KERN_WARNING "SELinux:  Invalid class %hu\n", tclass);
+               return;
+       }
 
        tclass_datum = policydb.class_val_to_struct[tclass - 1];
 
@@ -350,14 +634,16 @@ static int context_struct_compute_av(struct context *scontext,
         */
        avkey.target_class = tclass;
        avkey.specified = AVTAB_AV;
-       sattr = &policydb.type_attr_map[scontext->type - 1];
-       tattr = &policydb.type_attr_map[tcontext->type - 1];
+       sattr = flex_array_get(policydb.type_attr_map_array, scontext->type - 1);
+       BUG_ON(!sattr);
+       tattr = flex_array_get(policydb.type_attr_map_array, tcontext->type - 1);
+       BUG_ON(!tattr);
        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);
-                            node != NULL;
+                            node;
                             node = avtab_search_node_next(node, avkey.specified)) {
                                if (node->key.specified == AVTAB_ALLOWED)
                                        avd->allowed |= node->datum.data;
@@ -382,7 +668,7 @@ static int context_struct_compute_av(struct context *scontext,
                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;
        }
@@ -392,8 +678,8 @@ static int context_struct_compute_av(struct context *scontext,
         * role is changing, then check the (current_role, new_role)
         * pair.
         */
-       if (tclass == SECCLASS_PROCESS &&
-           (avd->allowed & (PROCESS__TRANSITION | PROCESS__DYNTRANSITION)) &&
+       if (tclass == policydb.process_class &&
+           (avd->allowed & policydb.process_trans_perms) &&
            scontext->role != tcontext->role) {
                for (ra = policydb.role_allow; ra; ra = ra->next) {
                        if (scontext->role == ra->role &&
@@ -401,41 +687,16 @@ static int context_struct_compute_av(struct context *scontext,
                                break;
                }
                if (!ra)
-                       avd->allowed = (avd->allowed) & ~(PROCESS__TRANSITION |
-                                                       PROCESS__DYNTRANSITION);
+                       avd->allowed &= ~policydb.process_trans_perms;
        }
 
-       return 0;
-
-inval_class:
-       printk(KERN_ERR "SELinux: %s:  unrecognized class %d\n", __func__,
-               tclass);
-       return -EINVAL;
-}
-
-/*
- * Given a sid find if the type has the permissive flag set
- */
-int security_permissive_sid(u32 sid)
-{
-       struct context *context;
-       u32 type;
-       int rc;
-
-       read_lock(&policy_rwlock);
-
-       context = sidtab_search(&sidtab, sid);
-       BUG_ON(!context);
-
-       type = context->type;
        /*
-        * we are intentionally using type here, not type-1, the 0th bit may
-        * someday indicate that we are globally setting permissive in policy.
+        * 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.
         */
-       rc = ebitmap_get_bit(&policydb.permissive_map, type);
-
-       read_unlock(&policy_rwlock);
-       return rc;
+       type_attribute_bounds_av(scontext, tcontext,
+                                tclass, avd);
 }
 
 static int security_validtrans_handle_fail(struct context *ocontext,
@@ -446,11 +707,11 @@ static int security_validtrans_handle_fail(struct context *ocontext,
        char *o = NULL, *n = NULL, *t = NULL;
        u32 olen, nlen, tlen;
 
-       if (context_struct_to_string(ocontext, &o, &olen) < 0)
+       if (context_struct_to_string(ocontext, &o, &olen))
                goto out;
-       if (context_struct_to_string(ncontext, &n, &nlen) < 0)
+       if (context_struct_to_string(ncontext, &n, &nlen))
                goto out;
-       if (context_struct_to_string(tcontext, &t, &tlen) < 0)
+       if (context_struct_to_string(tcontext, &t, &tlen))
                goto out;
        audit_log(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR,
                  "security_validate_transition:  denied for"
@@ -467,13 +728,14 @@ out:
 }
 
 int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid,
-                                u16 tclass)
+                                u16 orig_tclass)
 {
        struct context *ocontext;
        struct context *ncontext;
        struct context *tcontext;
        struct class_datum *tclass_datum;
        struct constraint_node *constraint;
+       u16 tclass;
        int rc = 0;
 
        if (!ss_initialized)
@@ -481,16 +743,7 @@ int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid,
 
        read_lock(&policy_rwlock);
 
-       /*
-        * Remap extended Netlink classes for old policy versions.
-        * Do this here rather than socket_type_to_security_class()
-        * in case a newer policy version is loaded, allowing sockets
-        * to remain in the correct class.
-        */
-       if (policydb_loaded_version < POLICYDB_VERSION_NLCLASS)
-               if (tclass >= SECCLASS_NETLINK_ROUTE_SOCKET &&
-                   tclass <= SECCLASS_NETLINK_DNRT_SOCKET)
-                       tclass = SECCLASS_NETLINK_SOCKET;
+       tclass = unmap_class(orig_tclass);
 
        if (!tclass || tclass > policydb.p_classes.nprim) {
                printk(KERN_ERR "SELinux: %s:  unrecognized class %d\n",
@@ -540,59 +793,199 @@ out:
        return rc;
 }
 
+/*
+ * security_bounded_transition - check whether the given
+ * transition is directed to bounded, or not.
+ * It returns 0, if @newsid is bounded by @oldsid.
+ * Otherwise, it returns error code.
+ *
+ * @oldsid : current security identifier
+ * @newsid : destinated security identifier
+ */
+int security_bounded_transition(u32 old_sid, u32 new_sid)
+{
+       struct context *old_context, *new_context;
+       struct type_datum *type;
+       int index;
+       int rc;
+
+       read_lock(&policy_rwlock);
+
+       rc = -EINVAL;
+       old_context = sidtab_search(&sidtab, old_sid);
+       if (!old_context) {
+               printk(KERN_ERR "SELinux: %s: unrecognized SID %u\n",
+                      __func__, old_sid);
+               goto out;
+       }
+
+       rc = -EINVAL;
+       new_context = sidtab_search(&sidtab, new_sid);
+       if (!new_context) {
+               printk(KERN_ERR "SELinux: %s: unrecognized SID %u\n",
+                      __func__, new_sid);
+               goto out;
+       }
+
+       rc = 0;
+       /* type/domain unchanged */
+       if (old_context->type == new_context->type)
+               goto out;
+
+       index = new_context->type;
+       while (true) {
+               type = flex_array_get_ptr(policydb.type_val_to_struct_array,
+                                         index - 1);
+               BUG_ON(!type);
+
+               /* not bounded anymore */
+               rc = -EPERM;
+               if (!type->bounds)
+                       break;
+
+               /* @newsid is bounded by @oldsid */
+               rc = 0;
+               if (type->bounds == old_context->type)
+                       break;
+
+               index = type->bounds;
+       }
+
+       if (rc) {
+               char *old_name = NULL;
+               char *new_name = NULL;
+               u32 length;
+
+               if (!context_struct_to_string(old_context,
+                                             &old_name, &length) &&
+                   !context_struct_to_string(new_context,
+                                             &new_name, &length)) {
+                       audit_log(current->audit_context,
+                                 GFP_ATOMIC, AUDIT_SELINUX_ERR,
+                                 "op=security_bounded_transition "
+                                 "result=denied "
+                                 "oldcontext=%s newcontext=%s",
+                                 old_name, new_name);
+               }
+               kfree(new_name);
+               kfree(old_name);
+       }
+out:
+       read_unlock(&policy_rwlock);
+
+       return rc;
+}
+
+static void avd_init(struct av_decision *avd)
+{
+       avd->allowed = 0;
+       avd->auditallow = 0;
+       avd->auditdeny = 0xffffffff;
+       avd->seqno = latest_granting;
+       avd->flags = 0;
+}
+
+
 /**
  * security_compute_av - Compute access vector decisions.
  * @ssid: source security identifier
  * @tsid: target security identifier
  * @tclass: target security class
- * @requested: requested permissions
  * @avd: access vector decisions
  *
  * Compute a set of access vector decisions based on the
  * SID pair (@ssid, @tsid) for the permissions in @tclass.
- * Return -%EINVAL if any of the parameters are invalid or %0
- * if the access vector decisions were computed successfully.
  */
-int security_compute_av(u32 ssid,
-                       u32 tsid,
-                       u16 tclass,
-                       u32 requested,
-                       struct av_decision *avd)
+void security_compute_av(u32 ssid,
+                        u32 tsid,
+                        u16 orig_tclass,
+                        struct av_decision *avd)
 {
+       u16 tclass;
        struct context *scontext = NULL, *tcontext = NULL;
-       int rc = 0;
 
-       if (!ss_initialized) {
-               avd->allowed = 0xffffffff;
-               avd->decided = 0xffffffff;
-               avd->auditallow = 0;
-               avd->auditdeny = 0xffffffff;
-               avd->seqno = latest_granting;
-               return 0;
+       read_lock(&policy_rwlock);
+       avd_init(avd);
+       if (!ss_initialized)
+               goto allow;
+
+       scontext = sidtab_search(&sidtab, ssid);
+       if (!scontext) {
+               printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",
+                      __func__, ssid);
+               goto out;
+       }
+
+       /* permissive domain? */
+       if (ebitmap_get_bit(&policydb.permissive_map, scontext->type))
+               avd->flags |= AVD_FLAGS_PERMISSIVE;
+
+       tcontext = sidtab_search(&sidtab, tsid);
+       if (!tcontext) {
+               printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",
+                      __func__, tsid);
+               goto out;
+       }
+
+       tclass = unmap_class(orig_tclass);
+       if (unlikely(orig_tclass && !tclass)) {
+               if (policydb.allow_unknown)
+                       goto allow;
+               goto out;
        }
+       context_struct_compute_av(scontext, tcontext, tclass, avd);
+       map_decision(orig_tclass, avd, policydb.allow_unknown);
+out:
+       read_unlock(&policy_rwlock);
+       return;
+allow:
+       avd->allowed = 0xffffffff;
+       goto out;
+}
+
+void security_compute_av_user(u32 ssid,
+                             u32 tsid,
+                             u16 tclass,
+                             struct av_decision *avd)
+{
+       struct context *scontext = NULL, *tcontext = NULL;
 
        read_lock(&policy_rwlock);
+       avd_init(avd);
+       if (!ss_initialized)
+               goto allow;
 
        scontext = sidtab_search(&sidtab, ssid);
        if (!scontext) {
                printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",
                       __func__, ssid);
-               rc = -EINVAL;
                goto out;
        }
+
+       /* permissive domain? */
+       if (ebitmap_get_bit(&policydb.permissive_map, scontext->type))
+               avd->flags |= AVD_FLAGS_PERMISSIVE;
+
        tcontext = sidtab_search(&sidtab, tsid);
        if (!tcontext) {
                printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",
                       __func__, tsid);
-               rc = -EINVAL;
                goto out;
        }
 
-       rc = context_struct_compute_av(scontext, tcontext, tclass,
-                                      requested, avd);
-out:
+       if (unlikely(!tclass)) {
+               if (policydb.allow_unknown)
+                       goto allow;
+               goto out;
+       }
+
+       context_struct_compute_av(scontext, tcontext, tclass, avd);
+ out:
        read_unlock(&policy_rwlock);
-       return rc;
+       return;
+allow:
+       avd->allowed = 0xffffffff;
+       goto out;
 }
 
 /*
@@ -606,7 +999,8 @@ static int context_struct_to_string(struct context *context, char **scontext, u3
 {
        char *scontextp;
 
-       *scontext = NULL;
+       if (scontext)
+               *scontext = NULL;
        *scontext_len = 0;
 
        if (context->len) {
@@ -623,6 +1017,9 @@ static int context_struct_to_string(struct context *context, char **scontext, u3
        *scontext_len += strlen(policydb.p_type_val_to_name[context->type - 1]) + 1;
        *scontext_len += mls_compute_context_len(context);
 
+       if (!scontext)
+               return 0;
+
        /* Allocate space for the context; caller must free this space. */
        scontextp = kmalloc(*scontext_len, GFP_ATOMIC);
        if (!scontextp)
@@ -662,7 +1059,8 @@ static int security_sid_to_context_core(u32 sid, char **scontext,
        struct context *context;
        int rc = 0;
 
-       *scontext = NULL;
+       if (scontext)
+               *scontext = NULL;
        *scontext_len  = 0;
 
        if (!ss_initialized) {
@@ -670,6 +1068,8 @@ static int security_sid_to_context_core(u32 sid, char **scontext,
                        char *scontextp;
 
                        *scontext_len = strlen(initial_sid_to_string[sid]) + 1;
+                       if (!scontext)
+                               goto out;
                        scontextp = kmalloc(*scontext_len, GFP_ATOMIC);
                        if (!scontextp) {
                                rc = -ENOMEM;
@@ -785,7 +1185,7 @@ static int string_to_context_struct(struct policydb *pol,
        *p++ = 0;
 
        typdatum = hashtab_search(pol->p_types.table, scontextp);
-       if (!typdatum)
+       if (!typdatum || typdatum->attribute)
                goto out;
 
        ctx->type = typdatum->value;
@@ -794,19 +1194,17 @@ static int string_to_context_struct(struct policydb *pol,
        if (rc)
                goto out;
 
-       if ((p - scontext) < scontext_len) {
-               rc = -EINVAL;
+       rc = -EINVAL;
+       if ((p - scontext) < scontext_len)
                goto out;
-       }
 
        /* Check the validity of the new context. */
-       if (!policydb_context_isvalid(pol, ctx)) {
-               rc = -EINVAL;
-               context_destroy(ctx);
+       if (!policydb_context_isvalid(pol, ctx))
                goto out;
-       }
        rc = 0;
 out:
+       if (rc)
+               context_destroy(ctx);
        return rc;
 }
 
@@ -833,7 +1231,7 @@ static int security_context_to_sid_core(const char *scontext, u32 scontext_len,
        *sid = SECSID_NULL;
 
        /* Copy the string so that we can modify the copy as we parse it. */
-       scontext2 = kmalloc(scontext_len+1, gfp_flags);
+       scontext2 = kmalloc(scontext_len + 1, gfp_flags);
        if (!scontext2)
                return -ENOMEM;
        memcpy(scontext2, scontext, scontext_len);
@@ -841,28 +1239,26 @@ static int security_context_to_sid_core(const char *scontext, u32 scontext_len,
 
        if (force) {
                /* Save another copy for storing in uninterpreted form */
+               rc = -ENOMEM;
                str = kstrdup(scontext2, gfp_flags);
-               if (!str) {
-                       kfree(scontext2);
-                       return -ENOMEM;
-               }
+               if (!str)
+                       goto out;
        }
 
        read_lock(&policy_rwlock);
-       rc = string_to_context_struct(&policydb, &sidtab,
-                                     scontext2, scontext_len,
-                                     &context, def_sid);
+       rc = string_to_context_struct(&policydb, &sidtab, scontext2,
+                                     scontext_len, &context, def_sid);
        if (rc == -EINVAL && force) {
                context.str = str;
                context.len = scontext_len;
                str = NULL;
        } else if (rc)
-               goto out;
+               goto out_unlock;
        rc = sidtab_context_to_sid(&sidtab, &context, sid);
-       if (rc)
-               context_destroy(&context);
-out:
+       context_destroy(&context);
+out_unlock:
        read_unlock(&policy_rwlock);
+out:
        kfree(scontext2);
        kfree(str);
        return rc;
@@ -926,11 +1322,11 @@ static int compute_sid_handle_invalid_context(
        char *s = NULL, *t = NULL, *n = NULL;
        u32 slen, tlen, nlen;
 
-       if (context_struct_to_string(scontext, &s, &slen) < 0)
+       if (context_struct_to_string(scontext, &s, &slen))
                goto out;
-       if (context_struct_to_string(tcontext, &t, &tlen) < 0)
+       if (context_struct_to_string(tcontext, &t, &tlen))
                goto out;
-       if (context_struct_to_string(newcontext, &n, &nlen) < 0)
+       if (context_struct_to_string(newcontext, &n, &nlen))
                goto out;
        audit_log(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR,
                  "security_compute_sid:  invalid context %s"
@@ -949,20 +1345,22 @@ out:
 
 static int security_compute_sid(u32 ssid,
                                u32 tsid,
-                               u16 tclass,
+                               u16 orig_tclass,
                                u32 specified,
-                               u32 *out_sid)
+                               u32 *out_sid,
+                               bool kern)
 {
        struct context *scontext = NULL, *tcontext = NULL, newcontext;
        struct role_trans *roletr = NULL;
        struct avtab_key avkey;
        struct avtab_datum *avdatum;
        struct avtab_node *node;
+       u16 tclass;
        int rc = 0;
 
        if (!ss_initialized) {
-               switch (tclass) {
-               case SECCLASS_PROCESS:
+               switch (orig_tclass) {
+               case SECCLASS_PROCESS: /* kernel value */
                        *out_sid = ssid;
                        break;
                default:
@@ -976,6 +1374,11 @@ static int security_compute_sid(u32 ssid,
 
        read_lock(&policy_rwlock);
 
+       if (kern)
+               tclass = unmap_class(orig_tclass);
+       else
+               tclass = orig_tclass;
+
        scontext = sidtab_search(&sidtab, ssid);
        if (!scontext) {
                printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",
@@ -1005,13 +1408,11 @@ static int security_compute_sid(u32 ssid,
        }
 
        /* Set the role and type to default values. */
-       switch (tclass) {
-       case SECCLASS_PROCESS:
+       if (tclass == policydb.process_class) {
                /* Use the current role and type of process. */
                newcontext.role = scontext->role;
                newcontext.type = scontext->type;
-               break;
-       default:
+       } else {
                /* Use the well-defined object role. */
                newcontext.role = OBJECT_R_VAL;
                /* Use the type of the related object. */
@@ -1028,7 +1429,7 @@ static int security_compute_sid(u32 ssid,
        /* If no permanent rule, also check for enabled conditional rules */
        if (!avdatum) {
                node = avtab_search_node(&policydb.te_cond_avtab, &avkey);
-               for (; node != NULL; node = avtab_search_node_next(node, specified)) {
+               for (; node; node = avtab_search_node_next(node, specified)) {
                        if (node->key.specified & AVTAB_ENABLED) {
                                avdatum = &node->datum;
                                break;
@@ -1042,8 +1443,7 @@ static int security_compute_sid(u32 ssid,
        }
 
        /* Check for class-specific changes. */
-       switch (tclass) {
-       case SECCLASS_PROCESS:
+       if  (tclass == policydb.process_class) {
                if (specified & AVTAB_TRANSITION) {
                        /* Look for a role transition rule. */
                        for (roletr = policydb.role_tr; roletr;
@@ -1056,9 +1456,6 @@ static int security_compute_sid(u32 ssid,
                                }
                        }
                }
-               break;
-       default:
-               break;
        }
 
        /* Set the MLS attributes.
@@ -1103,7 +1500,17 @@ int security_transition_sid(u32 ssid,
                            u16 tclass,
                            u32 *out_sid)
 {
-       return security_compute_sid(ssid, tsid, tclass, AVTAB_TRANSITION, out_sid);
+       return security_compute_sid(ssid, tsid, tclass, AVTAB_TRANSITION,
+                                   out_sid, true);
+}
+
+int security_transition_sid_user(u32 ssid,
+                                u32 tsid,
+                                u16 tclass,
+                                u32 *out_sid)
+{
+       return security_compute_sid(ssid, tsid, tclass, AVTAB_TRANSITION,
+                                   out_sid, false);
 }
 
 /**
@@ -1124,7 +1531,8 @@ int security_member_sid(u32 ssid,
                        u16 tclass,
                        u32 *out_sid)
 {
-       return security_compute_sid(ssid, tsid, tclass, AVTAB_MEMBER, out_sid);
+       return security_compute_sid(ssid, tsid, tclass, AVTAB_MEMBER, out_sid,
+                                   false);
 }
 
 /**
@@ -1145,137 +1553,8 @@ int security_change_sid(u32 ssid,
                        u16 tclass,
                        u32 *out_sid)
 {
-       return security_compute_sid(ssid, tsid, tclass, AVTAB_CHANGE, out_sid);
-}
-
-/*
- * 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;
-
-       if (p->allow_unknown) {
-               u32 num_classes = kdefs->cts_len;
-               p->undefined_perms = kcalloc(num_classes, sizeof(u32), GFP_KERNEL);
-               if (!p->undefined_perms)
-                       return -ENOMEM;
-       }
-
-       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
-                              "SELinux:  class %s not defined in policy\n",
-                              def_class);
-                       if (p->reject_unknown)
-                               return -EINVAL;
-                       if (p->allow_unknown)
-                               p->undefined_perms[i-1] = ~0U;
-                       continue;
-               }
-               pol_class = p->p_class_val_to_name[i-1];
-               if (strcmp(pol_class, def_class)) {
-                       printk(KERN_ERR
-                              "SELinux:  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
-                              "SELinux:  permission %s in class %s not defined in policy\n",
-                              def_perm, pol_class);
-                       if (p->reject_unknown)
-                               return -EINVAL;
-                       if (p->allow_unknown)
-                               p->undefined_perms[class_val-1] |= perm_val;
-                       continue;
-               }
-               perdatum = hashtab_search(perms->table, def_perm);
-               if (perdatum == NULL) {
-                       printk(KERN_ERR
-                              "SELinux:  permission %s in class %s not found in policy, bad policy\n",
-                              def_perm, pol_class);
-                       return -EINVAL;
-               }
-               pol_val = 1 << (perdatum->value - 1);
-               if (pol_val != perm_val) {
-                       printk(KERN_ERR
-                              "SELinux:  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
-                              "SELinux:  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
-                                      "SELinux:  permission %s in class %s not defined in policy\n",
-                                      def_perm, pol_class);
-                               if (p->reject_unknown)
-                                       return -EINVAL;
-                               if (p->allow_unknown)
-                                       p->undefined_perms[class_val-1] |= (1 << j);
-                               continue;
-                       }
-                       perdatum = hashtab_search(perms->table, def_perm);
-                       if (perdatum == NULL) {
-                               printk(KERN_ERR
-                                      "SELinux:  permission %s in class %s not found in policy, bad policy\n",
-                                      def_perm, pol_class);
-                               return -EINVAL;
-                       }
-                       if (perdatum->value != j + 1) {
-                               printk(KERN_ERR
-                                      "SELinux:  permission %s in class %s has incorrect value\n",
-                                      def_perm, pol_class);
-                               return -EINVAL;
-                       }
-               }
-       }
-       return 0;
+       return security_compute_sid(ssid, tsid, tclass, AVTAB_CHANGE, out_sid,
+                                   false);
 }
 
 /* Clone the SID into the new SID table. */
@@ -1285,27 +1564,25 @@ static int clone_sid(u32 sid,
 {
        struct sidtab *s = arg;
 
-       return sidtab_insert(s, sid, context);
+       if (sid > SECINITSID_NUM)
+               return sidtab_insert(s, sid, context);
+       else
+               return 0;
 }
 
 static inline int convert_context_handle_invalid_context(struct context *context)
 {
-       int rc = 0;
+       char *s;
+       u32 len;
 
-       if (selinux_enforcing) {
-               rc = -EINVAL;
-       } else {
-               char *s;
-               u32 len;
-
-               if (!context_struct_to_string(context, &s, &len)) {
-                       printk(KERN_WARNING
-                      "SELinux:  Context %s would be invalid if enforcing\n",
-                              s);
-                       kfree(s);
-               }
+       if (selinux_enforcing)
+               return -EINVAL;
+
+       if (!context_struct_to_string(context, &s, &len)) {
+               printk(KERN_WARNING "SELinux:  Context %s would be invalid if enforcing\n", s);
+               kfree(s);
        }
-       return rc;
+       return 0;
 }
 
 struct convert_context_args {
@@ -1326,28 +1603,33 @@ static int convert_context(u32 key,
 {
        struct convert_context_args *args;
        struct context oldc;
+       struct ocontext *oc;
+       struct mls_range *range;
        struct role_datum *role;
        struct type_datum *typdatum;
        struct user_datum *usrdatum;
        char *s;
        u32 len;
-       int rc;
+       int rc = 0;
+
+       if (key <= SECINITSID_NUM)
+               goto out;
 
        args = p;
 
        if (c->str) {
                struct context ctx;
+
+               rc = -ENOMEM;
                s = kstrdup(c->str, GFP_KERNEL);
-               if (!s) {
-                       rc = -ENOMEM;
+               if (!s)
                        goto out;
-               }
+
                rc = string_to_context_struct(args->newp, NULL, s,
                                              c->len, &ctx, SECSID_NULL);
                kfree(s);
                if (!rc) {
-                       printk(KERN_INFO
-                      "SELinux:  Context %s became valid (mapped).\n",
+                       printk(KERN_INFO "SELinux:  Context %s became valid (mapped).\n",
                               c->str);
                        /* Replace string with mapped representation. */
                        kfree(c->str);
@@ -1359,8 +1641,7 @@ static int convert_context(u32 key,
                        goto out;
                } else {
                        /* Other error condition, e.g. ENOMEM. */
-                       printk(KERN_ERR
-                      "SELinux:   Unable to map context %s, rc = %d.\n",
+                       printk(KERN_ERR "SELinux:   Unable to map context %s, rc = %d.\n",
                               c->str, -rc);
                        goto out;
                }
@@ -1370,9 +1651,8 @@ static int convert_context(u32 key,
        if (rc)
                goto out;
 
-       rc = -EINVAL;
-
        /* Convert the user. */
+       rc = -EINVAL;
        usrdatum = hashtab_search(args->newp->p_users.table,
                                  args->oldp->p_user_val_to_name[c->user - 1]);
        if (!usrdatum)
@@ -1380,6 +1660,7 @@ static int convert_context(u32 key,
        c->user = usrdatum->value;
 
        /* Convert the role. */
+       rc = -EINVAL;
        role = hashtab_search(args->newp->p_roles.table,
                              args->oldp->p_role_val_to_name[c->role - 1]);
        if (!role)
@@ -1387,15 +1668,47 @@ static int convert_context(u32 key,
        c->role = role->value;
 
        /* Convert the type. */
+       rc = -EINVAL;
        typdatum = hashtab_search(args->newp->p_types.table,
                                  args->oldp->p_type_val_to_name[c->type - 1]);
        if (!typdatum)
                goto bad;
        c->type = typdatum->value;
 
-       rc = mls_convert_context(args->oldp, args->newp, c);
-       if (rc)
-               goto bad;
+       /* Convert the MLS fields if dealing with MLS policies */
+       if (args->oldp->mls_enabled && args->newp->mls_enabled) {
+               rc = mls_convert_context(args->oldp, args->newp, c);
+               if (rc)
+                       goto bad;
+       } else if (args->oldp->mls_enabled && !args->newp->mls_enabled) {
+               /*
+                * Switching between MLS and non-MLS policy:
+                * free any storage used by the MLS fields in the
+                * context for all existing entries in the sidtab.
+                */
+               mls_context_destroy(c);
+       } else if (!args->oldp->mls_enabled && args->newp->mls_enabled) {
+               /*
+                * Switching between non-MLS and MLS policy:
+                * ensure that the MLS fields of the context for all
+                * existing entries in the sidtab are filled in with a
+                * suitable default value, likely taken from one of the
+                * initial SIDs.
+                */
+               oc = args->newp->ocontexts[OCON_ISID];
+               while (oc && oc->sid[0] != SECINITSID_UNLABELED)
+                       oc = oc->next;
+               rc = -EINVAL;
+               if (!oc) {
+                       printk(KERN_ERR "SELinux:  unable to look up"
+                               " the initial SIDs list\n");
+                       goto bad;
+               }
+               range = &oc->context[0].range;
+               rc = mls_range_set(c, range);
+               if (rc)
+                       goto bad;
+       }
 
        /* Check the validity of the new context. */
        if (!policydb_context_isvalid(args->newp, c)) {
@@ -1405,19 +1718,20 @@ static int convert_context(u32 key,
        }
 
        context_destroy(&oldc);
+
        rc = 0;
 out:
        return rc;
 bad:
        /* Map old representation to string and save it. */
-       if (context_struct_to_string(&oldc, &s, &len))
-               return -ENOMEM;
+       rc = context_struct_to_string(&oldc, &s, &len);
+       if (rc)
+               return rc;
        context_destroy(&oldc);
        context_destroy(c);
        c->str = s;
        c->len = len;
-       printk(KERN_INFO
-              "SELinux:  Context %s became invalid (unmapped).\n",
+       printk(KERN_INFO "SELinux:  Context %s became invalid (unmapped).\n",
               c->str);
        rc = 0;
        goto out;
@@ -1448,44 +1762,45 @@ int security_load_policy(void *data, size_t len)
 {
        struct policydb oldpolicydb, newpolicydb;
        struct sidtab oldsidtab, newsidtab;
+       struct selinux_mapping *oldmap, *map = NULL;
        struct convert_context_args args;
        u32 seqno;
+       u16 map_size;
        int rc = 0;
        struct policy_file file = { data, len }, *fp = &file;
 
-       mutex_lock(&load_mutex);
-
        if (!ss_initialized) {
                avtab_cache_init();
-               if (policydb_read(&policydb, fp)) {
-                       mutex_unlock(&load_mutex);
+               rc = policydb_read(&policydb, fp);
+               if (rc) {
                        avtab_cache_destroy();
-                       return -EINVAL;
+                       return rc;
                }
-               if (policydb_load_isids(&policydb, &sidtab)) {
-                       mutex_unlock(&load_mutex);
+
+               policydb.len = len;
+               rc = selinux_set_mapping(&policydb, secclass_map,
+                                        &current_mapping,
+                                        &current_mapping_size);
+               if (rc) {
                        policydb_destroy(&policydb);
                        avtab_cache_destroy();
-                       return -EINVAL;
+                       return rc;
                }
-               /* Verify that the kernel defined classes are correct. */
-               if (validate_classes(&policydb)) {
-                       printk(KERN_ERR
-                              "SELinux:  the definition of a class is incorrect\n");
-                       mutex_unlock(&load_mutex);
-                       sidtab_destroy(&sidtab);
+
+               rc = policydb_load_isids(&policydb, &sidtab);
+               if (rc) {
                        policydb_destroy(&policydb);
                        avtab_cache_destroy();
-                       return -EINVAL;
+                       return rc;
                }
+
                security_load_policycaps();
-               policydb_loaded_version = policydb.policyvers;
                ss_initialized = 1;
                seqno = ++latest_granting;
-               mutex_unlock(&load_mutex);
                selinux_complete_init();
                avc_ss_reset(seqno);
                selnl_notify_policyload(seqno);
+               selinux_status_update_policyload(seqno);
                selinux_netlbl_cache_invalidate();
                selinux_xfrm_notify_policyload();
                return 0;
@@ -1495,24 +1810,27 @@ int security_load_policy(void *data, size_t len)
        sidtab_hash_eval(&sidtab, "sids");
 #endif
 
-       if (policydb_read(&newpolicydb, fp)) {
-               mutex_unlock(&load_mutex);
-               return -EINVAL;
-       }
+       rc = policydb_read(&newpolicydb, fp);
+       if (rc)
+               return rc;
+
+       newpolicydb.len = len;
+       /* If switching between different policy types, log MLS status */
+       if (policydb.mls_enabled && !newpolicydb.mls_enabled)
+               printk(KERN_INFO "SELinux: Disabling MLS support...\n");
+       else if (!policydb.mls_enabled && newpolicydb.mls_enabled)
+               printk(KERN_INFO "SELinux: Enabling MLS support...\n");
 
-       if (sidtab_init(&newsidtab)) {
-               mutex_unlock(&load_mutex);
+       rc = policydb_load_isids(&newpolicydb, &newsidtab);
+       if (rc) {
+               printk(KERN_ERR "SELinux:  unable to load the initial SIDs\n");
                policydb_destroy(&newpolicydb);
-               return -ENOMEM;
+               return rc;
        }
 
-       /* Verify that the kernel defined classes are correct. */
-       if (validate_classes(&newpolicydb)) {
-               printk(KERN_ERR
-                      "SELinux:  the definition of a class is incorrect\n");
-               rc = -EINVAL;
+       rc = selinux_set_mapping(&newpolicydb, secclass_map, &map, &map_size);
+       if (rc)
                goto err;
-       }
 
        rc = security_preserve_bools(&newpolicydb);
        if (rc) {
@@ -1522,10 +1840,10 @@ int security_load_policy(void *data, size_t len)
 
        /* Clone the SID table. */
        sidtab_shutdown(&sidtab);
-       if (sidtab_map(&sidtab, clone_sid, &newsidtab)) {
-               rc = -ENOMEM;
+
+       rc = sidtab_map(&sidtab, clone_sid, &newsidtab);
+       if (rc)
                goto err;
-       }
 
        /*
         * Convert the internal representations of contexts
@@ -1534,8 +1852,12 @@ int security_load_policy(void *data, size_t len)
        args.oldp = &policydb;
        args.newp = &newpolicydb;
        rc = sidtab_map(&newsidtab, convert_context, &args);
-       if (rc)
+       if (rc) {
+               printk(KERN_ERR "SELinux:  unable to convert the internal"
+                       " representation of contexts in the new SID"
+                       " table\n");
                goto err;
+       }
 
        /* Save the old policydb and SID table to free later. */
        memcpy(&oldpolicydb, &policydb, sizeof policydb);
@@ -1546,30 +1868,44 @@ int security_load_policy(void *data, size_t len)
        memcpy(&policydb, &newpolicydb, sizeof policydb);
        sidtab_set(&sidtab, &newsidtab);
        security_load_policycaps();
+       oldmap = current_mapping;
+       current_mapping = map;
+       current_mapping_size = map_size;
        seqno = ++latest_granting;
-       policydb_loaded_version = policydb.policyvers;
        write_unlock_irq(&policy_rwlock);
-       mutex_unlock(&load_mutex);
 
        /* Free the old policydb and SID table. */
        policydb_destroy(&oldpolicydb);
        sidtab_destroy(&oldsidtab);
+       kfree(oldmap);
 
        avc_ss_reset(seqno);
        selnl_notify_policyload(seqno);
+       selinux_status_update_policyload(seqno);
        selinux_netlbl_cache_invalidate();
        selinux_xfrm_notify_policyload();
 
        return 0;
 
 err:
-       mutex_unlock(&load_mutex);
+       kfree(map);
        sidtab_destroy(&newsidtab);
        policydb_destroy(&newpolicydb);
        return rc;
 
 }
 
+size_t security_policydb_len(void)
+{
+       size_t len;
+
+       read_lock(&policy_rwlock);
+       len = policydb.len;
+       read_unlock(&policy_rwlock);
+
+       return len;
+}
+
 /**
  * security_port_sid - Obtain the SID for a port.
  * @protocol: protocol number
@@ -1676,7 +2012,7 @@ int security_node_sid(u16 domain,
                      u32 addrlen,
                      u32 *out_sid)
 {
-       int rc = 0;
+       int rc;
        struct ocontext *c;
 
        read_lock(&policy_rwlock);
@@ -1685,10 +2021,9 @@ int security_node_sid(u16 domain,
        case AF_INET: {
                u32 addr;
 
-               if (addrlen != sizeof(u32)) {
-                       rc = -EINVAL;
+               rc = -EINVAL;
+               if (addrlen != sizeof(u32))
                        goto out;
-               }
 
                addr = *((u32 *)addrp);
 
@@ -1702,10 +2037,9 @@ int security_node_sid(u16 domain,
        }
 
        case AF_INET6:
-               if (addrlen != sizeof(u64) * 2) {
-                       rc = -EINVAL;
+               rc = -EINVAL;
+               if (addrlen != sizeof(u64) * 2)
                        goto out;
-               }
                c = policydb.ocontexts[OCON_NODE6];
                while (c) {
                        if (match_ipv6_addrmask(addrp, c->u.node6.addr,
@@ -1716,6 +2050,7 @@ int security_node_sid(u16 domain,
                break;
 
        default:
+               rc = 0;
                *out_sid = SECINITSID_NODE;
                goto out;
        }
@@ -1733,6 +2068,7 @@ int security_node_sid(u16 domain,
                *out_sid = SECINITSID_NODE;
        }
 
+       rc = 0;
 out:
        read_unlock(&policy_rwlock);
        return rc;
@@ -1777,30 +2113,28 @@ int security_get_user_sids(u32 fromsid,
 
        context_init(&usercon);
 
+       rc = -EINVAL;
        fromcon = sidtab_search(&sidtab, fromsid);
-       if (!fromcon) {
-               rc = -EINVAL;
+       if (!fromcon)
                goto out_unlock;
-       }
 
+       rc = -EINVAL;
        user = hashtab_search(policydb.p_users.table, username);
-       if (!user) {
-               rc = -EINVAL;
+       if (!user)
                goto out_unlock;
-       }
+
        usercon.user = user->value;
 
+       rc = -ENOMEM;
        mysids = kcalloc(maxnel, sizeof(*mysids), GFP_ATOMIC);
-       if (!mysids) {
-               rc = -ENOMEM;
+       if (!mysids)
                goto out_unlock;
-       }
 
        ebitmap_for_each_positive_bit(&user->roles, rnode, i) {
                role = policydb.role_val_to_struct[i];
-               usercon.role = i+1;
+               usercon.role = i + 1;
                ebitmap_for_each_positive_bit(&role->types, tnode, j) {
-                       usercon.type = j+1;
+                       usercon.type = j + 1;
 
                        if (mls_setup_user_range(fromcon, user, &usercon))
                                continue;
@@ -1811,12 +2145,11 @@ int security_get_user_sids(u32 fromsid,
                        if (mynel < maxnel) {
                                mysids[mynel++] = sid;
                        } else {
+                               rc = -ENOMEM;
                                maxnel += SIDS_NEL;
                                mysids2 = kcalloc(maxnel, sizeof(*mysids2), GFP_ATOMIC);
-                               if (!mysids2) {
-                                       rc = -ENOMEM;
+                               if (!mysids2)
                                        goto out_unlock;
-                               }
                                memcpy(mysids2, mysids, mynel * sizeof(*mysids2));
                                kfree(mysids);
                                mysids = mysids2;
@@ -1824,7 +2157,7 @@ int security_get_user_sids(u32 fromsid,
                        }
                }
        }
-
+       rc = 0;
 out_unlock:
        read_unlock(&policy_rwlock);
        if (rc || !mynel) {
@@ -1832,15 +2165,15 @@ out_unlock:
                goto out;
        }
 
+       rc = -ENOMEM;
        mysids2 = kcalloc(mynel, sizeof(*mysids2), GFP_KERNEL);
        if (!mysids2) {
-               rc = -ENOMEM;
                kfree(mysids);
                goto out;
        }
        for (i = 0, j = 0; i < mynel; i++) {
                rc = avc_has_perm_noaudit(fromsid, mysids[i],
-                                         SECCLASS_PROCESS,
+                                         SECCLASS_PROCESS, /* kernel value */
                                          PROCESS__TRANSITION, AVC_STRICT,
                                          NULL);
                if (!rc)
@@ -1868,30 +2201,32 @@ out:
  */
 int security_genfs_sid(const char *fstype,
                       char *path,
-                      u16 sclass,
+                      u16 orig_sclass,
                       u32 *sid)
 {
        int len;
+       u16 sclass;
        struct genfs *genfs;
        struct ocontext *c;
-       int rc = 0, cmp = 0;
+       int rc, cmp = 0;
 
        while (path[0] == '/' && path[1] == '/')
                path++;
 
        read_lock(&policy_rwlock);
 
+       sclass = unmap_class(orig_sclass);
+       *sid = SECINITSID_UNLABELED;
+
        for (genfs = policydb.genfs; genfs; genfs = genfs->next) {
                cmp = strcmp(fstype, genfs->fstype);
                if (cmp <= 0)
                        break;
        }
 
-       if (!genfs || cmp) {
-               *sid = SECINITSID_UNLABELED;
-               rc = -ENOENT;
+       rc = -ENOENT;
+       if (!genfs || cmp)
                goto out;
-       }
 
        for (c = genfs->head; c; c = c->next) {
                len = strlen(c->u.name);
@@ -1900,21 +2235,18 @@ int security_genfs_sid(const char *fstype,
                        break;
        }
 
-       if (!c) {
-               *sid = SECINITSID_UNLABELED;
-               rc = -ENOENT;
+       rc = -ENOENT;
+       if (!c)
                goto out;
-       }
 
        if (!c->sid[0]) {
-               rc = sidtab_context_to_sid(&sidtab,
-                                          &c->context[0],
-                                          &c->sid[0]);
+               rc = sidtab_context_to_sid(&sidtab, &c->context[0], &c->sid[0]);
                if (rc)
                        goto out;
        }
 
        *sid = c->sid[0];
+       rc = 0;
 out:
        read_unlock(&policy_rwlock);
        return rc;
@@ -1946,8 +2278,7 @@ int security_fs_use(
        if (c) {
                *behavior = c->v.behavior;
                if (!c->sid[0]) {
-                       rc = sidtab_context_to_sid(&sidtab,
-                                                  &c->context[0],
+                       rc = sidtab_context_to_sid(&sidtab, &c->context[0],
                                                   &c->sid[0]);
                        if (rc)
                                goto out;
@@ -1970,33 +2301,38 @@ out:
 
 int security_get_bools(int *len, char ***names, int **values)
 {
-       int i, rc = -ENOMEM;
+       int i, rc;
 
        read_lock(&policy_rwlock);
        *names = NULL;
        *values = NULL;
 
+       rc = 0;
        *len = policydb.p_bools.nprim;
-       if (!*len) {
-               rc = 0;
+       if (!*len)
                goto out;
-       }
 
-       *names = kcalloc(*len, sizeof(char *), GFP_ATOMIC);
+       rc = -ENOMEM;
+       *names = kcalloc(*len, sizeof(char *), GFP_ATOMIC);
        if (!*names)
                goto err;
 
-       *values = kcalloc(*len, sizeof(int), GFP_ATOMIC);
+       rc = -ENOMEM;
+       *values = kcalloc(*len, sizeof(int), GFP_ATOMIC);
        if (!*values)
                goto err;
 
        for (i = 0; i < *len; i++) {
                size_t name_len;
+
                (*values)[i] = policydb.bool_val_to_struct[i]->state;
                name_len = strlen(policydb.p_bool_val_to_name[i]) + 1;
-              (*names)[i] = kmalloc(sizeof(char) * name_len, GFP_ATOMIC);
+
+               rc = -ENOMEM;
+               (*names)[i] = kmalloc(sizeof(char) * name_len, GFP_ATOMIC);
                if (!(*names)[i])
                        goto err;
+
                strncpy((*names)[i], policydb.p_bool_val_to_name[i], name_len);
                (*names)[i][name_len - 1] = 0;
        }
@@ -2016,17 +2352,16 @@ err:
 
 int security_set_bools(int len, int *values)
 {
-       int i, rc = 0;
+       int i, rc;
        int lenp, seqno = 0;
        struct cond_node *cur;
 
        write_lock_irq(&policy_rwlock);
 
+       rc = -EFAULT;
        lenp = policydb.p_bools.nprim;
-       if (len != lenp) {
-               rc = -EFAULT;
+       if (len != lenp)
                goto out;
-       }
 
        for (i = 0; i < len; i++) {
                if (!!values[i] != policydb.bool_val_to_struct[i]->state) {
@@ -2045,19 +2380,20 @@ int security_set_bools(int len, int *values)
                        policydb.bool_val_to_struct[i]->state = 0;
        }
 
-       for (cur = policydb.cond_list; cur != NULL; cur = cur->next) {
+       for (cur = policydb.cond_list; cur; cur = cur->next) {
                rc = evaluate_cond_node(&policydb, cur);
                if (rc)
                        goto out;
        }
 
        seqno = ++latest_granting;
-
+       rc = 0;
 out:
        write_unlock_irq(&policy_rwlock);
        if (!rc) {
                avc_ss_reset(seqno);
                selnl_notify_policyload(seqno);
+               selinux_status_update_policyload(seqno);
                selinux_xfrm_notify_policyload();
        }
        return rc;
@@ -2065,16 +2401,15 @@ out:
 
 int security_get_bool_value(int bool)
 {
-       int rc = 0;
+       int rc;
        int len;
 
        read_lock(&policy_rwlock);
 
+       rc = -EFAULT;
        len = policydb.p_bools.nprim;
-       if (bool >= len) {
-               rc = -EFAULT;
+       if (bool >= len)
                goto out;
-       }
 
        rc = policydb.bool_val_to_struct[bool]->state;
 out:
@@ -2097,7 +2432,7 @@ static int security_preserve_bools(struct policydb *p)
                if (booldatum)
                        booldatum->state = bvalues[i];
        }
-       for (cur = p->cond_list; cur != NULL; cur = cur->next) {
+       for (cur = p->cond_list; cur; cur = cur->next) {
                rc = evaluate_cond_node(p, cur);
                if (rc)
                        goto out;
@@ -2124,9 +2459,10 @@ int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid)
        struct context newcon;
        char *s;
        u32 len;
-       int rc = 0;
+       int rc;
 
-       if (!ss_initialized || !selinux_mls_enabled) {
+       rc = 0;
+       if (!ss_initialized || !policydb.mls_enabled) {
                *new_sid = sid;
                goto out;
        }
@@ -2134,19 +2470,20 @@ int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid)
        context_init(&newcon);
 
        read_lock(&policy_rwlock);
+
+       rc = -EINVAL;
        context1 = sidtab_search(&sidtab, sid);
        if (!context1) {
                printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",
                        __func__, sid);
-               rc = -EINVAL;
                goto out_unlock;
        }
 
+       rc = -EINVAL;
        context2 = sidtab_search(&sidtab, mls_sid);
        if (!context2) {
                printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",
                        __func__, mls_sid);
-               rc = -EINVAL;
                goto out_unlock;
        }
 
@@ -2160,20 +2497,17 @@ int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid)
        /* Check the validity of the new context. */
        if (!policydb_context_isvalid(&policydb, &newcon)) {
                rc = convert_context_handle_invalid_context(&newcon);
-               if (rc)
-                       goto bad;
+               if (rc) {
+                       if (!context_struct_to_string(&newcon, &s, &len)) {
+                               audit_log(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR,
+                                         "security_sid_mls_copy: invalid context %s", s);
+                               kfree(s);
+                       }
+                       goto out_unlock;
+               }
        }
 
        rc = sidtab_context_to_sid(&sidtab, &newcon, new_sid);
-       goto out_unlock;
-
-bad:
-       if (!context_struct_to_string(&newcon, &s, &len)) {
-               audit_log(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR,
-                         "security_sid_mls_copy: invalid context %s", s);
-               kfree(s);
-       }
-
 out_unlock:
        read_unlock(&policy_rwlock);
        context_destroy(&newcon);
@@ -2209,6 +2543,8 @@ int security_net_peersid_resolve(u32 nlbl_sid, u32 nlbl_type,
        struct context *nlbl_ctx;
        struct context *xfrm_ctx;
 
+       *peer_sid = SECSID_NULL;
+
        /* handle the common (which also happens to be the set of easy) cases
         * right away, these two if statements catch everything involving a
         * single or absent peer SID/label */
@@ -2227,40 +2563,37 @@ int security_net_peersid_resolve(u32 nlbl_sid, u32 nlbl_type,
        /* we don't need to check ss_initialized here since the only way both
         * nlbl_sid and xfrm_sid are not equal to SECSID_NULL would be if the
         * security server was initialized and ss_initialized was true */
-       if (!selinux_mls_enabled) {
-               *peer_sid = SECSID_NULL;
+       if (!policydb.mls_enabled)
                return 0;
-       }
 
        read_lock(&policy_rwlock);
 
+       rc = -EINVAL;
        nlbl_ctx = sidtab_search(&sidtab, nlbl_sid);
        if (!nlbl_ctx) {
                printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",
                       __func__, nlbl_sid);
-               rc = -EINVAL;
-               goto out_slowpath;
+               goto out;
        }
+       rc = -EINVAL;
        xfrm_ctx = sidtab_search(&sidtab, xfrm_sid);
        if (!xfrm_ctx) {
                printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",
                       __func__, xfrm_sid);
-               rc = -EINVAL;
-               goto out_slowpath;
+               goto out;
        }
        rc = (mls_context_cmp(nlbl_ctx, xfrm_ctx) ? 0 : -EACCES);
+       if (rc)
+               goto out;
 
-out_slowpath:
+       /* at present NetLabel SIDs/labels really only carry MLS
+        * information so if the MLS portion of the NetLabel SID
+        * matches the MLS portion of the labeled XFRM SID/label
+        * then pass along the XFRM SID as it is the most
+        * expressive */
+       *peer_sid = xfrm_sid;
+out:
        read_unlock(&policy_rwlock);
-       if (rc == 0)
-               /* at present NetLabel SIDs/labels really only carry MLS
-                * information so if the MLS portion of the NetLabel SID
-                * matches the MLS portion of the labeled XFRM SID/label
-                * then pass along the XFRM SID as it is the most
-                * expressive */
-               *peer_sid = xfrm_sid;
-       else
-               *peer_sid = SECSID_NULL;
        return rc;
 }
 
@@ -2279,18 +2612,19 @@ static int get_classes_callback(void *k, void *d, void *args)
 
 int security_get_classes(char ***classes, int *nclasses)
 {
-       int rc = -ENOMEM;
+       int rc;
 
        read_lock(&policy_rwlock);
 
+       rc = -ENOMEM;
        *nclasses = policydb.p_classes.nprim;
-       *classes = kcalloc(*nclasses, sizeof(*classes), GFP_ATOMIC);
+       *classes = kcalloc(*nclasses, sizeof(**classes), GFP_ATOMIC);
        if (!*classes)
                goto out;
 
        rc = hashtab_map(policydb.p_classes.table, get_classes_callback,
                        *classes);
-       if (rc < 0) {
+       if (rc) {
                int i;
                for (i = 0; i < *nclasses; i++)
                        kfree((*classes)[i]);
@@ -2317,34 +2651,35 @@ static int get_permissions_callback(void *k, void *d, void *args)
 
 int security_get_permissions(char *class, char ***perms, int *nperms)
 {
-       int rc = -ENOMEM, i;
+       int rc, i;
        struct class_datum *match;
 
        read_lock(&policy_rwlock);
 
+       rc = -EINVAL;
        match = hashtab_search(policydb.p_classes.table, class);
        if (!match) {
                printk(KERN_ERR "SELinux: %s:  unrecognized class %s\n",
                        __func__, class);
-               rc = -EINVAL;
                goto out;
        }
 
+       rc = -ENOMEM;
        *nperms = match->permissions.nprim;
-       *perms = kcalloc(*nperms, sizeof(*perms), GFP_ATOMIC);
+       *perms = kcalloc(*nperms, sizeof(**perms), GFP_ATOMIC);
        if (!*perms)
                goto out;
 
        if (match->comdatum) {
                rc = hashtab_map(match->comdatum->permissions.table,
                                get_permissions_callback, *perms);
-               if (rc < 0)
+               if (rc)
                        goto err;
        }
 
        rc = hashtab_map(match->permissions.table, get_permissions_callback,
                        *perms);
-       if (rc < 0)
+       if (rc)
                goto err;
 
 out:
@@ -2427,7 +2762,7 @@ int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
        case AUDIT_OBJ_ROLE:
        case AUDIT_OBJ_TYPE:
                /* only 'equals' and 'not equals' fit user, role, and type */
-               if (op != AUDIT_EQUAL && op != AUDIT_NOT_EQUAL)
+               if (op != Audit_equal && op != Audit_not_equal)
                        return -EINVAL;
                break;
        case AUDIT_SUBJ_SEN:
@@ -2456,36 +2791,39 @@ int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
        switch (field) {
        case AUDIT_SUBJ_USER:
        case AUDIT_OBJ_USER:
+               rc = -EINVAL;
                userdatum = hashtab_search(policydb.p_users.table, rulestr);
                if (!userdatum)
-                       rc = -EINVAL;
-               else
-                       tmprule->au_ctxt.user = userdatum->value;
+                       goto out;
+               tmprule->au_ctxt.user = userdatum->value;
                break;
        case AUDIT_SUBJ_ROLE:
        case AUDIT_OBJ_ROLE:
+               rc = -EINVAL;
                roledatum = hashtab_search(policydb.p_roles.table, rulestr);
                if (!roledatum)
-                       rc = -EINVAL;
-               else
-                       tmprule->au_ctxt.role = roledatum->value;
+                       goto out;
+               tmprule->au_ctxt.role = roledatum->value;
                break;
        case AUDIT_SUBJ_TYPE:
        case AUDIT_OBJ_TYPE:
+               rc = -EINVAL;
                typedatum = hashtab_search(policydb.p_types.table, rulestr);
                if (!typedatum)
-                       rc = -EINVAL;
-               else
-                       tmprule->au_ctxt.type = typedatum->value;
+                       goto out;
+               tmprule->au_ctxt.type = typedatum->value;
                break;
        case AUDIT_SUBJ_SEN:
        case AUDIT_SUBJ_CLR:
        case AUDIT_OBJ_LEV_LOW:
        case AUDIT_OBJ_LEV_HIGH:
                rc = mls_from_string(rulestr, &tmprule->au_ctxt, GFP_ATOMIC);
+               if (rc)
+                       goto out;
                break;
        }
-
+       rc = 0;
+out:
        read_unlock(&policy_rwlock);
 
        if (rc) {
@@ -2561,10 +2899,10 @@ int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule,
        case AUDIT_SUBJ_USER:
        case AUDIT_OBJ_USER:
                switch (op) {
-               case AUDIT_EQUAL:
+               case Audit_equal:
                        match = (ctxt->user == rule->au_ctxt.user);
                        break;
-               case AUDIT_NOT_EQUAL:
+               case Audit_not_equal:
                        match = (ctxt->user != rule->au_ctxt.user);
                        break;
                }
@@ -2572,10 +2910,10 @@ int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule,
        case AUDIT_SUBJ_ROLE:
        case AUDIT_OBJ_ROLE:
                switch (op) {
-               case AUDIT_EQUAL:
+               case Audit_equal:
                        match = (ctxt->role == rule->au_ctxt.role);
                        break;
-               case AUDIT_NOT_EQUAL:
+               case Audit_not_equal:
                        match = (ctxt->role != rule->au_ctxt.role);
                        break;
                }
@@ -2583,10 +2921,10 @@ int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule,
        case AUDIT_SUBJ_TYPE:
        case AUDIT_OBJ_TYPE:
                switch (op) {
-               case AUDIT_EQUAL:
+               case Audit_equal:
                        match = (ctxt->type == rule->au_ctxt.type);
                        break;
-               case AUDIT_NOT_EQUAL:
+               case Audit_not_equal:
                        match = (ctxt->type != rule->au_ctxt.type);
                        break;
                }
@@ -2599,31 +2937,31 @@ int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule,
                          field == AUDIT_OBJ_LEV_LOW) ?
                         &ctxt->range.level[0] : &ctxt->range.level[1]);
                switch (op) {
-               case AUDIT_EQUAL:
+               case Audit_equal:
                        match = mls_level_eq(&rule->au_ctxt.range.level[0],
                                             level);
                        break;
-               case AUDIT_NOT_EQUAL:
+               case Audit_not_equal:
                        match = !mls_level_eq(&rule->au_ctxt.range.level[0],
                                              level);
                        break;
-               case AUDIT_LESS_THAN:
+               case Audit_lt:
                        match = (mls_level_dom(&rule->au_ctxt.range.level[0],
                                               level) &&
                                 !mls_level_eq(&rule->au_ctxt.range.level[0],
                                               level));
                        break;
-               case AUDIT_LESS_THAN_OR_EQUAL:
+               case Audit_le:
                        match = mls_level_dom(&rule->au_ctxt.range.level[0],
                                              level);
                        break;
-               case AUDIT_GREATER_THAN:
+               case Audit_gt:
                        match = (mls_level_dom(level,
                                              &rule->au_ctxt.range.level[0]) &&
                                 !mls_level_eq(level,
                                               &rule->au_ctxt.range.level[0]));
                        break;
-               case AUDIT_GREATER_THAN_OR_EQUAL:
+               case Audit_ge:
                        match = mls_level_dom(level,
                                              &rule->au_ctxt.range.level[0]);
                        break;
@@ -2710,7 +3048,7 @@ static void security_netlbl_cache_add(struct netlbl_lsm_secattr *secattr,
 int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr,
                                   u32 *sid)
 {
-       int rc = -EIDRM;
+       int rc;
        struct context *ctx;
        struct context ctx_new;
 
@@ -2721,54 +3059,51 @@ int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr,
 
        read_lock(&policy_rwlock);
 
-       if (secattr->flags & NETLBL_SECATTR_CACHE) {
+       if (secattr->flags & NETLBL_SECATTR_CACHE)
                *sid = *(u32 *)secattr->cache->data;
-               rc = 0;
-       } else if (secattr->flags & NETLBL_SECATTR_SECID) {
+       else if (secattr->flags & NETLBL_SECATTR_SECID)
                *sid = secattr->attr.secid;
-               rc = 0;
-       } else if (secattr->flags & NETLBL_SECATTR_MLS_LVL) {
+       else if (secattr->flags & NETLBL_SECATTR_MLS_LVL) {
+               rc = -EIDRM;
                ctx = sidtab_search(&sidtab, SECINITSID_NETMSG);
                if (ctx == NULL)
-                       goto netlbl_secattr_to_sid_return;
+                       goto out;
 
+               context_init(&ctx_new);
                ctx_new.user = ctx->user;
                ctx_new.role = ctx->role;
                ctx_new.type = ctx->type;
                mls_import_netlbl_lvl(&ctx_new, secattr);
                if (secattr->flags & NETLBL_SECATTR_MLS_CAT) {
-                       if (ebitmap_netlbl_import(&ctx_new.range.level[0].cat,
-                                                 secattr->attr.mls.cat) != 0)
-                               goto netlbl_secattr_to_sid_return;
-                       ctx_new.range.level[1].cat.highbit =
-                               ctx_new.range.level[0].cat.highbit;
-                       ctx_new.range.level[1].cat.node =
-                               ctx_new.range.level[0].cat.node;
-               } else {
-                       ebitmap_init(&ctx_new.range.level[0].cat);
-                       ebitmap_init(&ctx_new.range.level[1].cat);
+                       rc = ebitmap_netlbl_import(&ctx_new.range.level[0].cat,
+                                                  secattr->attr.mls.cat);
+                       if (rc)
+                               goto out;
+                       memcpy(&ctx_new.range.level[1].cat,
+                              &ctx_new.range.level[0].cat,
+                              sizeof(ctx_new.range.level[0].cat));
                }
-               if (mls_context_isvalid(&policydb, &ctx_new) != 1)
-                       goto netlbl_secattr_to_sid_return_cleanup;
+               rc = -EIDRM;
+               if (!mls_context_isvalid(&policydb, &ctx_new))
+                       goto out_free;
 
                rc = sidtab_context_to_sid(&sidtab, &ctx_new, sid);
-               if (rc != 0)
-                       goto netlbl_secattr_to_sid_return_cleanup;
+               if (rc)
+                       goto out_free;
 
                security_netlbl_cache_add(secattr, *sid);
 
                ebitmap_destroy(&ctx_new.range.level[0].cat);
-       } else {
+       } else
                *sid = SECSID_NULL;
-               rc = 0;
-       }
 
-netlbl_secattr_to_sid_return:
        read_unlock(&policy_rwlock);
-       return rc;
-netlbl_secattr_to_sid_return_cleanup:
+       return 0;
+out_free:
        ebitmap_destroy(&ctx_new.range.level[0].cat);
-       goto netlbl_secattr_to_sid_return;
+out:
+       read_unlock(&policy_rwlock);
+       return rc;
 }
 
 /**
@@ -2783,29 +3118,66 @@ netlbl_secattr_to_sid_return_cleanup:
  */
 int security_netlbl_sid_to_secattr(u32 sid, struct netlbl_lsm_secattr *secattr)
 {
-       int rc = -ENOENT;
+       int rc;
        struct context *ctx;
 
        if (!ss_initialized)
                return 0;
 
        read_lock(&policy_rwlock);
+
+       rc = -ENOENT;
        ctx = sidtab_search(&sidtab, sid);
        if (ctx == NULL)
-               goto netlbl_sid_to_secattr_failure;
+               goto out;
+
+       rc = -ENOMEM;
        secattr->domain = kstrdup(policydb.p_type_val_to_name[ctx->type - 1],
                                  GFP_ATOMIC);
-       secattr->flags |= NETLBL_SECATTR_DOMAIN_CPY;
+       if (secattr->domain == NULL)
+               goto out;
+
+       secattr->attr.secid = sid;
+       secattr->flags |= NETLBL_SECATTR_DOMAIN_CPY | NETLBL_SECATTR_SECID;
        mls_export_netlbl_lvl(ctx, secattr);
        rc = mls_export_netlbl_cat(ctx, secattr);
-       if (rc != 0)
-               goto netlbl_sid_to_secattr_failure;
+out:
        read_unlock(&policy_rwlock);
+       return rc;
+}
+#endif /* CONFIG_NETLABEL */
 
-       return 0;
+/**
+ * security_read_policy - read the policy.
+ * @data: binary policy data
+ * @len: length of data in bytes
+ *
+ */
+int security_read_policy(void **data, ssize_t *len)
+{
+       int rc;
+       struct policy_file fp;
 
-netlbl_sid_to_secattr_failure:
+       if (!ss_initialized)
+               return -EINVAL;
+
+       *len = security_policydb_len();
+
+       *data = vmalloc_user(*len);
+       if (!*data)
+               return -ENOMEM;
+
+       fp.data = *data;
+       fp.len = *len;
+
+       read_lock(&policy_rwlock);
+       rc = policydb_write(&policydb, &fp);
        read_unlock(&policy_rwlock);
-       return rc;
+
+       if (rc)
+               return rc;
+
+       *len = (unsigned long)fp.data - (unsigned long)*data;
+       return 0;
+
 }
-#endif /* CONFIG_NETLABEL */