Merge branch 'x86/for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip...
[pandora-kernel.git] / security / selinux / ss / services.c
index e8ec54d..8e42da1 100644 (file)
@@ -72,10 +72,6 @@ extern const struct selinux_class_perm selinux_class_perm;
 
 static DEFINE_RWLOCK(policy_rwlock);
 
-static DEFINE_MUTEX(load_mutex);
-#define LOAD_LOCK mutex_lock(&load_mutex)
-#define LOAD_UNLOCK mutex_unlock(&load_mutex)
-
 static struct sidtab sidtab;
 struct policydb policydb;
 int ss_initialized;
@@ -328,7 +324,7 @@ static int context_struct_compute_av(struct context *scontext,
                goto inval_class;
        if (unlikely(tclass > policydb.p_classes.nprim))
                if (tclass > kdefs->cts_len ||
-                   !kdefs->class_to_string[tclass - 1] ||
+                   !kdefs->class_to_string[tclass] ||
                    !policydb.allow_unknown)
                        goto inval_class;
 
@@ -411,9 +407,19 @@ static int context_struct_compute_av(struct context *scontext,
        return 0;
 
 inval_class:
-       printk(KERN_ERR "SELinux: %s:  unrecognized class %d\n", __func__,
-               tclass);
-       return -EINVAL;
+       if (!tclass || tclass > kdefs->cts_len ||
+           !kdefs->class_to_string[tclass]) {
+               if (printk_ratelimit())
+                       printk(KERN_ERR "SELinux: %s:  unrecognized class %d\n",
+                              __func__, tclass);
+               return -EINVAL;
+       }
+
+       /*
+        * Known to the kernel, but not to the policy.
+        * Handle as a denial (allowed is 0).
+        */
+       return 0;
 }
 
 /*
@@ -1165,6 +1171,7 @@ static int validate_classes(struct policydb *p)
        const struct selinux_class_perm *kdefs = &selinux_class_perm;
        const char *def_class, *def_perm, *pol_class;
        struct symtab *perms;
+       bool print_unknown_handle = 0;
 
        if (p->allow_unknown) {
                u32 num_classes = kdefs->cts_len;
@@ -1185,6 +1192,7 @@ static int validate_classes(struct policydb *p)
                                return -EINVAL;
                        if (p->allow_unknown)
                                p->undefined_perms[i-1] = ~0U;
+                       print_unknown_handle = 1;
                        continue;
                }
                pol_class = p->p_class_val_to_name[i-1];
@@ -1214,6 +1222,7 @@ static int validate_classes(struct policydb *p)
                                return -EINVAL;
                        if (p->allow_unknown)
                                p->undefined_perms[class_val-1] |= perm_val;
+                       print_unknown_handle = 1;
                        continue;
                }
                perdatum = hashtab_search(perms->table, def_perm);
@@ -1261,6 +1270,7 @@ static int validate_classes(struct policydb *p)
                                        return -EINVAL;
                                if (p->allow_unknown)
                                        p->undefined_perms[class_val-1] |= (1 << j);
+                               print_unknown_handle = 1;
                                continue;
                        }
                        perdatum = hashtab_search(perms->table, def_perm);
@@ -1278,6 +1288,9 @@ static int validate_classes(struct policydb *p)
                        }
                }
        }
+       if (print_unknown_handle)
+               printk(KERN_INFO "SELinux: the above unknown classes and permissions will be %s\n",
+                       (security_get_allow_unknown() ? "allowed" : "denied"));
        return 0;
 }
 
@@ -1456,17 +1469,13 @@ int security_load_policy(void *data, size_t len)
        int rc = 0;
        struct policy_file file = { data, len }, *fp = &file;
 
-       LOAD_LOCK;
-
        if (!ss_initialized) {
                avtab_cache_init();
                if (policydb_read(&policydb, fp)) {
-                       LOAD_UNLOCK;
                        avtab_cache_destroy();
                        return -EINVAL;
                }
                if (policydb_load_isids(&policydb, &sidtab)) {
-                       LOAD_UNLOCK;
                        policydb_destroy(&policydb);
                        avtab_cache_destroy();
                        return -EINVAL;
@@ -1475,7 +1484,6 @@ int security_load_policy(void *data, size_t len)
                if (validate_classes(&policydb)) {
                        printk(KERN_ERR
                               "SELinux:  the definition of a class is incorrect\n");
-                       LOAD_UNLOCK;
                        sidtab_destroy(&sidtab);
                        policydb_destroy(&policydb);
                        avtab_cache_destroy();
@@ -1485,7 +1493,6 @@ int security_load_policy(void *data, size_t len)
                policydb_loaded_version = policydb.policyvers;
                ss_initialized = 1;
                seqno = ++latest_granting;
-               LOAD_UNLOCK;
                selinux_complete_init();
                avc_ss_reset(seqno);
                selnl_notify_policyload(seqno);
@@ -1498,13 +1505,10 @@ int security_load_policy(void *data, size_t len)
        sidtab_hash_eval(&sidtab, "sids");
 #endif
 
-       if (policydb_read(&newpolicydb, fp)) {
-               LOAD_UNLOCK;
+       if (policydb_read(&newpolicydb, fp))
                return -EINVAL;
-       }
 
        if (sidtab_init(&newsidtab)) {
-               LOAD_UNLOCK;
                policydb_destroy(&newpolicydb);
                return -ENOMEM;
        }
@@ -1552,7 +1556,6 @@ int security_load_policy(void *data, size_t len)
        seqno = ++latest_granting;
        policydb_loaded_version = policydb.policyvers;
        write_unlock_irq(&policy_rwlock);
-       LOAD_UNLOCK;
 
        /* Free the old policydb and SID table. */
        policydb_destroy(&oldpolicydb);
@@ -1566,7 +1569,6 @@ int security_load_policy(void *data, size_t len)
        return 0;
 
 err:
-       LOAD_UNLOCK;
        sidtab_destroy(&newsidtab);
        policydb_destroy(&newpolicydb);
        return rc;
@@ -1932,7 +1934,8 @@ out:
 int security_fs_use(
        const char *fstype,
        unsigned int *behavior,
-       u32 *sid)
+       u32 *sid,
+       bool can_xattr)
 {
        int rc = 0;
        struct ocontext *c;
@@ -1946,6 +1949,7 @@ int security_fs_use(
                c = c->next;
        }
 
+       /* look for labeling behavior defined in policy */
        if (c) {
                *behavior = c->v.behavior;
                if (!c->sid[0]) {
@@ -1956,14 +1960,23 @@ int security_fs_use(
                                goto out;
                }
                *sid = c->sid[0];
+               goto out;
+       }
+
+       /* labeling behavior not in policy, use xattrs if possible */
+       if (can_xattr) {
+               *behavior = SECURITY_FS_USE_XATTR;
+               *sid = SECINITSID_FS;
+               goto out;
+       }
+
+       /* no behavior in policy and can't use xattrs, try GENFS */
+       rc = security_genfs_sid(fstype, "/", SECCLASS_DIR, sid);
+       if (rc) {
+               *behavior = SECURITY_FS_USE_NONE;
+               rc = 0;
        } else {
-               rc = security_genfs_sid(fstype, "/", SECCLASS_DIR, sid);
-               if (rc) {
-                       *behavior = SECURITY_FS_USE_NONE;
-                       rc = 0;
-               } else {
-                       *behavior = SECURITY_FS_USE_GENFS;
-               }
+               *behavior = SECURITY_FS_USE_GENFS;
        }
 
 out: