SELinux: Add a capabilities bitmap to SELinux policy version 22
[firefly-linux-kernel-4.4.55.git] / security / selinux / ss / services.c
index 6100fc023055c0b62e4d3d4691e0593424d38113..8ee04a424df7c31d5b62558e8a7796ecdb909e93 100644 (file)
  * Updated: Hewlett-Packard <paul.moore@hp.com>
  *
  *      Added support for NetLabel
+ *      Added support for the policy capability bitmap
  *
  * Updated: Chad Sellers <csellers@tresys.com>
  *
  *  Added validation of kernel classes and permissions
  *
- * Copyright (C) 2006 Hewlett-Packard Development Company, L.P.
+ * Copyright (C) 2006, 2007 Hewlett-Packard Development Company, L.P.
  * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc.
  * Copyright (C) 2003 - 2004, 2006 Tresys Technology, LLC
  * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com>
@@ -59,6 +60,8 @@
 extern void selnl_notify_policyload(u32 seqno);
 unsigned int policydb_loaded_version;
 
+int selinux_policycap_netpeer;
+
 /*
  * This is declared in avc.c
  */
@@ -292,6 +295,7 @@ 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;
 
        /*
@@ -305,13 +309,6 @@ static int context_struct_compute_av(struct context *scontext,
                    tclass <= SECCLASS_NETLINK_DNRT_SOCKET)
                        tclass = SECCLASS_NETLINK_SOCKET;
 
-       if (!tclass || tclass > policydb.p_classes.nprim) {
-               printk(KERN_ERR "security_compute_av:  unrecognized class %d\n",
-                      tclass);
-               return -EINVAL;
-       }
-       tclass_datum = policydb.class_val_to_struct[tclass - 1];
-
        /*
         * Initialize the access vectors to the default values.
         */
@@ -321,6 +318,36 @@ static int context_struct_compute_av(struct context *scontext,
        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 - 1] ||
+                   !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;
+
+       tclass_datum = policydb.class_val_to_struct[tclass - 1];
+
        /*
         * If a specific type enforcement rule was defined for
         * this permission check, then use it.
@@ -329,12 +356,8 @@ static int context_struct_compute_av(struct context *scontext,
        avkey.specified = AVTAB_AV;
        sattr = &policydb.type_attr_map[scontext->type - 1];
        tattr = &policydb.type_attr_map[tcontext->type - 1];
-       ebitmap_for_each_bit(sattr, snode, i) {
-               if (!ebitmap_node_get_bit(snode, i))
-                       continue;
-               ebitmap_for_each_bit(tattr, tnode, j) {
-                       if (!ebitmap_node_get_bit(tnode, j))
-                               continue;
+       ebitmap_for_each_positive_bit(sattr, snode, i) {
+               ebitmap_for_each_positive_bit(tattr, tnode, j) {
                        avkey.source_type = i + 1;
                        avkey.target_type = j + 1;
                        for (node = avtab_search_node(&policydb.te_avtab, &avkey);
@@ -387,6 +410,10 @@ static int context_struct_compute_av(struct context *scontext,
        }
 
        return 0;
+
+inval_class:
+       printk(KERN_ERR "%s:  unrecognized class %d\n", __FUNCTION__, tclass);
+       return -EINVAL;
 }
 
 static int security_validtrans_handle_fail(struct context *ocontext,
@@ -1054,6 +1081,13 @@ static int validate_classes(struct policydb *p)
        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)
@@ -1062,6 +1096,10 @@ static int validate_classes(struct policydb *p)
                        printk(KERN_INFO
                               "security:  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];
@@ -1087,12 +1125,16 @@ static int validate_classes(struct policydb *p)
                        printk(KERN_INFO
                               "security:  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
-                              "security:  permission %s in class %s not found in policy\n",
+                              "security:  permission %s in class %s not found in policy, bad policy\n",
                               def_perm, pol_class);
                        return -EINVAL;
                }
@@ -1130,12 +1172,16 @@ static int validate_classes(struct policydb *p)
                                printk(KERN_INFO
                                       "security:  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
-                                      "security:  permission %s in class %s not found in policy\n",
+                                      "security:  permission %s in class %s not found in policy, bad policy\n",
                                       def_perm, pol_class);
                                return -EINVAL;
                        }
@@ -1256,6 +1302,12 @@ bad:
        goto out;
 }
 
+static void security_load_policycaps(void)
+{
+       selinux_policycap_netpeer = ebitmap_get_bit(&policydb.policycaps,
+                                                 POLICYDB_CAPABILITY_NETPEER);
+}
+
 extern void selinux_complete_init(void);
 static int security_preserve_bools(struct policydb *p);
 
@@ -1303,6 +1355,7 @@ int security_load_policy(void *data, size_t len)
                        avtab_cache_destroy();
                        return -EINVAL;
                }
+               security_load_policycaps();
                policydb_loaded_version = policydb.policyvers;
                ss_initialized = 1;
                seqno = ++latest_granting;
@@ -1361,6 +1414,7 @@ int security_load_policy(void *data, size_t len)
        POLICY_WRLOCK;
        memcpy(&policydb, &newpolicydb, sizeof policydb);
        sidtab_set(&sidtab, &newsidtab);
+       security_load_policycaps();
        seqno = ++latest_granting;
        policydb_loaded_version = policydb.policyvers;
        POLICY_WRUNLOCK;
@@ -1435,11 +1489,8 @@ out:
  * security_netif_sid - Obtain the SID for a network interface.
  * @name: interface name
  * @if_sid: interface SID
- * @msg_sid: default SID for received packets
  */
-int security_netif_sid(char *name,
-                      u32 *if_sid,
-                      u32 *msg_sid)
+int security_netif_sid(char *name, u32 *if_sid)
 {
        int rc = 0;
        struct ocontext *c;
@@ -1467,11 +1518,8 @@ int security_netif_sid(char *name,
                                goto out;
                }
                *if_sid = c->sid[0];
-               *msg_sid = c->sid[1];
-       } else {
+       } else
                *if_sid = SECINITSID_NETIF;
-               *msg_sid = SECINITSID_NETMSG;
-       }
 
 out:
        POLICY_RDUNLOCK;
@@ -1621,14 +1669,10 @@ int security_get_user_sids(u32 fromsid,
                goto out_unlock;
        }
 
-       ebitmap_for_each_bit(&user->roles, rnode, i) {
-               if (!ebitmap_node_get_bit(rnode, i))
-                       continue;
+       ebitmap_for_each_positive_bit(&user->roles, rnode, i) {
                role = policydb.role_val_to_struct[i];
                usercon.role = i+1;
-               ebitmap_for_each_bit(&role->types, tnode, j) {
-                       if (!ebitmap_node_get_bit(tnode, j))
-                               continue;
+               ebitmap_for_each_positive_bit(&role->types, tnode, j) {
                        usercon.type = j+1;
 
                        if (mls_setup_user_range(fromcon, user, &usercon))
@@ -1705,6 +1749,9 @@ int security_genfs_sid(const char *fstype,
        struct ocontext *c;
        int rc = 0, cmp = 0;
 
+       while (path[0] == '/' && path[1] == '/')
+               path++;
+
        POLICY_RDLOCK;
 
        for (genfs = policydb.genfs; genfs; genfs = genfs->next) {
@@ -2102,6 +2149,70 @@ err:
        return rc;
 }
 
+int security_get_reject_unknown(void)
+{
+       return policydb.reject_unknown;
+}
+
+int security_get_allow_unknown(void)
+{
+       return policydb.allow_unknown;
+}
+
+/**
+ * security_get_policycaps - Query the loaded policy for its capabilities
+ * @len: the number of capability bits
+ * @values: the capability bit array
+ *
+ * Description:
+ * Get an array of the policy capabilities in @values where each entry in
+ * @values is either true (1) or false (0) depending the policy's support of
+ * that feature.  The policy capabilities are defined by the
+ * POLICYDB_CAPABILITY_* enums.  The size of the array is stored in @len and it
+ * is up to the caller to free the array in @values.  Returns zero on success,
+ * negative values on failure.
+ *
+ */
+int security_get_policycaps(int *len, int **values)
+{
+       int rc = -ENOMEM;
+       unsigned int iter;
+
+       POLICY_RDLOCK;
+
+       *values = kcalloc(POLICYDB_CAPABILITY_MAX, sizeof(int), GFP_ATOMIC);
+       if (*values == NULL)
+               goto out;
+       for (iter = 0; iter < POLICYDB_CAPABILITY_MAX; iter++)
+               (*values)[iter] = ebitmap_get_bit(&policydb.policycaps, iter);
+       *len = POLICYDB_CAPABILITY_MAX;
+
+out:
+       POLICY_RDUNLOCK;
+       return rc;
+}
+
+/**
+ * security_policycap_supported - Check for a specific policy capability
+ * @req_cap: capability
+ *
+ * Description:
+ * This function queries the currently loaded policy to see if it supports the
+ * capability specified by @req_cap.  Returns true (1) if the capability is
+ * supported, false (0) if it isn't supported.
+ *
+ */
+int security_policycap_supported(unsigned int req_cap)
+{
+       int rc;
+
+       POLICY_RDLOCK;
+       rc = ebitmap_get_bit(&policydb.policycaps, req_cap);
+       POLICY_RDUNLOCK;
+
+       return rc;
+}
+
 struct selinux_audit_rule {
        u32 au_seqno;
        struct context au_ctxt;
@@ -2498,6 +2609,9 @@ int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr,
                default:
                        goto netlbl_secattr_to_sid_return;
                }
+       } else if (secattr->flags & NETLBL_SECATTR_SECID) {
+               *sid = secattr->attr.secid;
+               rc = 0;
        } else if (secattr->flags & NETLBL_SECATTR_MLS_LVL) {
                ctx = sidtab_search(&sidtab, base_sid);
                if (ctx == NULL)
@@ -2509,7 +2623,7 @@ int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr,
                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->mls_cat) != 0)
+                                                 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;
@@ -2557,8 +2671,6 @@ int security_netlbl_sid_to_secattr(u32 sid, struct netlbl_lsm_secattr *secattr)
        int rc = -ENOENT;
        struct context *ctx;
 
-       netlbl_secattr_init(secattr);
-
        if (!ss_initialized)
                return 0;