]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - security/selinux/ss/services.c
SELinux: policy selectable handling of unknown classes and perms
[linux-2.6-omap-h63xx.git] / security / selinux / ss / services.c
index 6100fc023055c0b62e4d3d4691e0593424d38113..03140edf97a3d54229bca7f48b3fe62deb92bb49 100644 (file)
@@ -292,6 +292,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 +306,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 +315,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.
@@ -387,6 +411,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 +1082,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 +1097,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 +1126,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 +1173,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;
                        }
@@ -2102,6 +2149,16 @@ err:
        return rc;
 }
 
+int security_get_reject_unknown(void)
+{
+       return policydb.reject_unknown;
+}
+
+int security_get_allow_unknown(void)
+{
+       return policydb.allow_unknown;
+}
+
 struct selinux_audit_rule {
        u32 au_seqno;
        struct context au_ctxt;