selinux: allow MLS->non-MLS and vice versa upon policy reload
Guido Trentalancia [Wed, 3 Feb 2010 15:40:20 +0000 (16:40 +0100)]
Allow runtime switching between different policy types (e.g. from a MLS/MCS
policy to a non-MLS/non-MCS policy or viceversa).

Signed-off-by: Guido Trentalancia <guido@trentalancia.com>
Acked-by: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: James Morris <jmorris@namei.org>

security/selinux/include/security.h
security/selinux/selinuxfs.c
security/selinux/ss/context.h
security/selinux/ss/mls.c
security/selinux/ss/mls.h
security/selinux/ss/mls_types.h
security/selinux/ss/policydb.c
security/selinux/ss/policydb.h
security/selinux/ss/services.c

index 022cf06..1f7c249 100644 (file)
@@ -57,7 +57,6 @@
 struct netlbl_lsm_secattr;
 
 extern int selinux_enabled;
-extern int selinux_mls_enabled;
 
 /* Policy capabilities */
 enum {
@@ -80,6 +79,8 @@ extern int selinux_policycap_openperm;
 /* limitation of boundary depth  */
 #define POLICYDB_BOUNDS_MAXDEPTH       4
 
+int security_mls_enabled(void);
+
 int security_load_policy(void *data, size_t len);
 
 int security_policycap_supported(unsigned int req_cap);
index b7bb0f5..a1cfc46 100644 (file)
@@ -282,7 +282,8 @@ static ssize_t sel_read_mls(struct file *filp, char __user *buf,
        char tmpbuf[TMPBUFLEN];
        ssize_t length;
 
-       length = scnprintf(tmpbuf, TMPBUFLEN, "%d", selinux_mls_enabled);
+       length = scnprintf(tmpbuf, TMPBUFLEN, "%d",
+                          security_mls_enabled());
        return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
 }
 
index d9dd7a2..45e8fb0 100644 (file)
@@ -41,9 +41,6 @@ static inline int mls_context_cpy(struct context *dst, struct context *src)
 {
        int rc;
 
-       if (!selinux_mls_enabled)
-               return 0;
-
        dst->range.level[0].sens = src->range.level[0].sens;
        rc = ebitmap_cpy(&dst->range.level[0].cat, &src->range.level[0].cat);
        if (rc)
@@ -64,9 +61,6 @@ static inline int mls_context_cpy_low(struct context *dst, struct context *src)
 {
        int rc;
 
-       if (!selinux_mls_enabled)
-               return 0;
-
        dst->range.level[0].sens = src->range.level[0].sens;
        rc = ebitmap_cpy(&dst->range.level[0].cat, &src->range.level[0].cat);
        if (rc)
@@ -82,9 +76,6 @@ out:
 
 static inline int mls_context_cmp(struct context *c1, struct context *c2)
 {
-       if (!selinux_mls_enabled)
-               return 1;
-
        return ((c1->range.level[0].sens == c2->range.level[0].sens) &&
                ebitmap_cmp(&c1->range.level[0].cat, &c2->range.level[0].cat) &&
                (c1->range.level[1].sens == c2->range.level[1].sens) &&
@@ -93,9 +84,6 @@ static inline int mls_context_cmp(struct context *c1, struct context *c2)
 
 static inline void mls_context_destroy(struct context *c)
 {
-       if (!selinux_mls_enabled)
-               return;
-
        ebitmap_destroy(&c->range.level[0].cat);
        ebitmap_destroy(&c->range.level[1].cat);
        mls_context_init(c);
index 443ae73..372b773 100644 (file)
@@ -39,7 +39,7 @@ int mls_compute_context_len(struct context *context)
        struct ebitmap *e;
        struct ebitmap_node *node;
 
-       if (!selinux_mls_enabled)
+       if (!policydb.mls_enabled)
                return 0;
 
        len = 1; /* for the beginning ":" */
@@ -93,7 +93,7 @@ void mls_sid_to_context(struct context *context,
        struct ebitmap *e;
        struct ebitmap_node *node;
 
-       if (!selinux_mls_enabled)
+       if (!policydb.mls_enabled)
                return;
 
        scontextp = *scontext;
@@ -200,7 +200,7 @@ int mls_context_isvalid(struct policydb *p, struct context *c)
 {
        struct user_datum *usrdatum;
 
-       if (!selinux_mls_enabled)
+       if (!p->mls_enabled)
                return 1;
 
        if (!mls_range_isvalid(p, &c->range))
@@ -253,7 +253,7 @@ int mls_context_to_sid(struct policydb *pol,
        struct cat_datum *catdatum, *rngdatum;
        int l, rc = -EINVAL;
 
-       if (!selinux_mls_enabled) {
+       if (!pol->mls_enabled) {
                if (def_sid != SECSID_NULL && oldc)
                        *scontext += strlen(*scontext)+1;
                return 0;
@@ -387,7 +387,7 @@ int mls_from_string(char *str, struct context *context, gfp_t gfp_mask)
        char *tmpstr, *freestr;
        int rc;
 
-       if (!selinux_mls_enabled)
+       if (!policydb.mls_enabled)
                return -EINVAL;
 
        /* we need freestr because mls_context_to_sid will change
@@ -407,7 +407,7 @@ int mls_from_string(char *str, struct context *context, gfp_t gfp_mask)
 /*
  * Copies the MLS range `range' into `context'.
  */
-static inline int mls_range_set(struct context *context,
+int mls_range_set(struct context *context,
                                struct mls_range *range)
 {
        int l, rc = 0;
@@ -427,7 +427,7 @@ static inline int mls_range_set(struct context *context,
 int mls_setup_user_range(struct context *fromcon, struct user_datum *user,
                         struct context *usercon)
 {
-       if (selinux_mls_enabled) {
+       if (policydb.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]);
@@ -477,7 +477,7 @@ int mls_convert_context(struct policydb *oldp,
        struct ebitmap_node *node;
        int l, i;
 
-       if (!selinux_mls_enabled)
+       if (!policydb.mls_enabled)
                return 0;
 
        for (l = 0; l < 2; l++) {
@@ -516,7 +516,7 @@ int mls_compute_sid(struct context *scontext,
        struct range_trans rtr;
        struct mls_range *r;
 
-       if (!selinux_mls_enabled)
+       if (!policydb.mls_enabled)
                return 0;
 
        switch (specified) {
@@ -559,7 +559,7 @@ int mls_compute_sid(struct context *scontext,
 void mls_export_netlbl_lvl(struct context *context,
                           struct netlbl_lsm_secattr *secattr)
 {
-       if (!selinux_mls_enabled)
+       if (!policydb.mls_enabled)
                return;
 
        secattr->attr.mls.lvl = context->range.level[0].sens - 1;
@@ -579,7 +579,7 @@ void mls_export_netlbl_lvl(struct context *context,
 void mls_import_netlbl_lvl(struct context *context,
                           struct netlbl_lsm_secattr *secattr)
 {
-       if (!selinux_mls_enabled)
+       if (!policydb.mls_enabled)
                return;
 
        context->range.level[0].sens = secattr->attr.mls.lvl + 1;
@@ -601,7 +601,7 @@ int mls_export_netlbl_cat(struct context *context,
 {
        int rc;
 
-       if (!selinux_mls_enabled)
+       if (!policydb.mls_enabled)
                return 0;
 
        rc = ebitmap_netlbl_export(&context->range.level[0].cat,
@@ -629,7 +629,7 @@ int mls_import_netlbl_cat(struct context *context,
 {
        int rc;
 
-       if (!selinux_mls_enabled)
+       if (!policydb.mls_enabled)
                return 0;
 
        rc = ebitmap_netlbl_import(&context->range.level[0].cat,
index 1276715..cd91526 100644 (file)
@@ -39,6 +39,8 @@ int mls_context_to_sid(struct policydb *p,
 
 int mls_from_string(char *str, struct context *context, gfp_t gfp_mask);
 
+int mls_range_set(struct context *context, struct mls_range *range);
+
 int mls_convert_context(struct policydb *oldp,
                        struct policydb *newp,
                        struct context *context);
index b6e943a..03bed52 100644 (file)
@@ -15,6 +15,7 @@
 #define _SS_MLS_TYPES_H_
 
 #include "security.h"
+#include "ebitmap.h"
 
 struct mls_level {
        u32 sens;               /* sensitivity */
@@ -27,18 +28,12 @@ struct mls_range {
 
 static inline int mls_level_eq(struct mls_level *l1, struct mls_level *l2)
 {
-       if (!selinux_mls_enabled)
-               return 1;
-
        return ((l1->sens == l2->sens) &&
                ebitmap_cmp(&l1->cat, &l2->cat));
 }
 
 static inline int mls_level_dom(struct mls_level *l1, struct mls_level *l2)
 {
-       if (!selinux_mls_enabled)
-               return 1;
-
        return ((l1->sens >= l2->sens) &&
                ebitmap_contains(&l1->cat, &l2->cat));
 }
index 5b92c02..23c6e53 100644 (file)
@@ -52,8 +52,6 @@ static char *symtab_name[SYM_NUM] = {
 };
 #endif
 
-int selinux_mls_enabled;
-
 static unsigned int symtab_sizes[SYM_NUM] = {
        2,
        32,
@@ -455,7 +453,7 @@ static int policydb_index_others(struct policydb *p)
 
        printk(KERN_DEBUG "SELinux:  %d users, %d roles, %d types, %d bools",
               p->p_users.nprim, p->p_roles.nprim, p->p_types.nprim, p->p_bools.nprim);
-       if (selinux_mls_enabled)
+       if (p->mls_enabled)
                printk(", %d sens, %d cats", p->p_levels.nprim,
                       p->p_cats.nprim);
        printk("\n");
@@ -1717,14 +1715,12 @@ int policydb_read(struct policydb *p, void *fp)
        int i, j, rc;
        __le32 buf[4];
        u32 nodebuf[8];
-       u32 len, len2, config, nprim, nel, nel2;
+       u32 len, len2, nprim, nel, nel2;
        char *policydb_str;
        struct policydb_compat_info *info;
        struct range_trans *rt;
        struct mls_range *r;
 
-       config = 0;
-
        rc = policydb_init(p);
        if (rc)
                goto out;
@@ -1772,7 +1768,7 @@ int policydb_read(struct policydb *p, void *fp)
        kfree(policydb_str);
        policydb_str = NULL;
 
-       /* Read the version, config, and table sizes. */
+       /* Read the version and table sizes. */
        rc = next_entry(buf, fp, sizeof(u32)*4);
        if (rc < 0)
                goto bad;
@@ -1787,13 +1783,7 @@ int policydb_read(struct policydb *p, void *fp)
        }
 
        if ((le32_to_cpu(buf[1]) & POLICYDB_CONFIG_MLS)) {
-               if (ss_initialized && !selinux_mls_enabled) {
-                       printk(KERN_ERR "SELinux: Cannot switch between non-MLS"
-                               " and MLS policies\n");
-                       goto bad;
-               }
-               selinux_mls_enabled = 1;
-               config |= POLICYDB_CONFIG_MLS;
+               p->mls_enabled = 1;
 
                if (p->policyvers < POLICYDB_VERSION_MLS) {
                        printk(KERN_ERR "SELinux: security policydb version %d "
@@ -1801,12 +1791,6 @@ int policydb_read(struct policydb *p, void *fp)
                                p->policyvers);
                        goto bad;
                }
-       } else {
-               if (ss_initialized && selinux_mls_enabled) {
-                       printk(KERN_ERR "SELinux: Cannot switch between MLS and"
-                               " non-MLS policies\n");
-                       goto bad;
-               }
        }
        p->reject_unknown = !!(le32_to_cpu(buf[1]) & REJECT_UNKNOWN);
        p->allow_unknown = !!(le32_to_cpu(buf[1]) & ALLOW_UNKNOWN);
index 193736b..26d9adf 100644 (file)
@@ -27,6 +27,8 @@
 #include "symtab.h"
 #include "avtab.h"
 #include "sidtab.h"
+#include "ebitmap.h"
+#include "mls_types.h"
 #include "context.h"
 #include "constraint.h"
 
@@ -185,6 +187,8 @@ struct genfs {
 
 /* The policy database */
 struct policydb {
+       int mls_enabled;
+
        /* symbol tables */
        struct symtab symtab[SYM_NUM];
 #define p_commons symtab[SYM_COMMONS]
index 2abbc49..4e976f5 100644 (file)
  *
  *  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.
@@ -232,6 +236,10 @@ static void map_decision(u16 tclass, struct av_decision *avd,
        }
 }
 
+int security_mls_enabled(void)
+{
+       return policydb.mls_enabled;
+}
 
 /*
  * Return the boolean value of a constraint expression
@@ -1550,6 +1558,8 @@ 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;
@@ -1620,9 +1630,39 @@ static int convert_context(u32 key,
                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;
+               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)) {
@@ -1718,6 +1758,12 @@ int security_load_policy(void *data, size_t len)
        if (policydb_read(&newpolicydb, fp))
                return -EINVAL;
 
+       /* 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");
+
        rc = policydb_load_isids(&newpolicydb, &newsidtab);
        if (rc) {
                printk(KERN_ERR "SELinux:  unable to load the initial SIDs\n");
@@ -1749,8 +1795,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);
@@ -2346,7 +2396,7 @@ int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid)
        u32 len;
        int rc = 0;
 
-       if (!ss_initialized || !selinux_mls_enabled) {
+       if (!ss_initialized || !policydb.mls_enabled) {
                *new_sid = sid;
                goto out;
        }
@@ -2447,7 +2497,7 @@ 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) {
+       if (!policydb.mls_enabled) {
                *peer_sid = SECSID_NULL;
                return 0;
        }