|
@@ -17,9 +17,13 @@
|
|
*
|
|
*
|
|
* Added support for NetLabel
|
|
* Added support for NetLabel
|
|
*
|
|
*
|
|
|
|
+ * 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 Hewlett-Packard Development Company, L.P.
|
|
* Copyright (C) 2004-2006 Trusted Computer Solutions, Inc.
|
|
* Copyright (C) 2004-2006 Trusted Computer Solutions, Inc.
|
|
- * Copyright (C) 2003 - 2004 Tresys Technology, LLC
|
|
|
|
|
|
+ * Copyright (C) 2003 - 2004, 2006 Tresys Technology, LLC
|
|
* Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com>
|
|
* Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com>
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* it under the terms of the GNU General Public License as published by
|
|
@@ -53,6 +57,11 @@
|
|
extern void selnl_notify_policyload(u32 seqno);
|
|
extern void selnl_notify_policyload(u32 seqno);
|
|
unsigned int policydb_loaded_version;
|
|
unsigned int policydb_loaded_version;
|
|
|
|
|
|
|
|
+/*
|
|
|
|
+ * This is declared in avc.c
|
|
|
|
+ */
|
|
|
|
+extern const struct selinux_class_perm selinux_class_perm;
|
|
|
|
+
|
|
static DEFINE_RWLOCK(policy_rwlock);
|
|
static DEFINE_RWLOCK(policy_rwlock);
|
|
#define POLICY_RDLOCK read_lock(&policy_rwlock)
|
|
#define POLICY_RDLOCK read_lock(&policy_rwlock)
|
|
#define POLICY_WRLOCK write_lock_irq(&policy_rwlock)
|
|
#define POLICY_WRLOCK write_lock_irq(&policy_rwlock)
|
|
@@ -1019,86 +1028,112 @@ int security_change_sid(u32 ssid,
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
/*
|
|
- * Verify that each permission that is defined under the
|
|
|
|
- * existing policy is still defined with the same value
|
|
|
|
- * in the new policy.
|
|
|
|
|
|
+ * Verify that each kernel class that is defined in the
|
|
|
|
+ * policy is correct
|
|
*/
|
|
*/
|
|
-static int validate_perm(void *key, void *datum, void *p)
|
|
|
|
|
|
+static int validate_classes(struct policydb *p)
|
|
{
|
|
{
|
|
- struct hashtab *h;
|
|
|
|
- struct perm_datum *perdatum, *perdatum2;
|
|
|
|
- int rc = 0;
|
|
|
|
-
|
|
|
|
-
|
|
|
|
- h = p;
|
|
|
|
- perdatum = datum;
|
|
|
|
-
|
|
|
|
- perdatum2 = hashtab_search(h, key);
|
|
|
|
- if (!perdatum2) {
|
|
|
|
- printk(KERN_ERR "security: permission %s disappeared",
|
|
|
|
- (char *)key);
|
|
|
|
- rc = -ENOENT;
|
|
|
|
- goto out;
|
|
|
|
- }
|
|
|
|
- if (perdatum->value != perdatum2->value) {
|
|
|
|
- printk(KERN_ERR "security: the value of permission %s changed",
|
|
|
|
- (char *)key);
|
|
|
|
- rc = -EINVAL;
|
|
|
|
- }
|
|
|
|
-out:
|
|
|
|
- return rc;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/*
|
|
|
|
- * Verify that each class that is defined under the
|
|
|
|
- * existing policy is still defined with the same
|
|
|
|
- * attributes in the new policy.
|
|
|
|
- */
|
|
|
|
-static int validate_class(void *key, void *datum, void *p)
|
|
|
|
-{
|
|
|
|
- struct policydb *newp;
|
|
|
|
- struct class_datum *cladatum, *cladatum2;
|
|
|
|
- int rc;
|
|
|
|
-
|
|
|
|
- newp = p;
|
|
|
|
- cladatum = datum;
|
|
|
|
-
|
|
|
|
- cladatum2 = hashtab_search(newp->p_classes.table, key);
|
|
|
|
- if (!cladatum2) {
|
|
|
|
- printk(KERN_ERR "security: class %s disappeared\n",
|
|
|
|
- (char *)key);
|
|
|
|
- rc = -ENOENT;
|
|
|
|
- goto out;
|
|
|
|
- }
|
|
|
|
- if (cladatum->value != cladatum2->value) {
|
|
|
|
- printk(KERN_ERR "security: the value of class %s changed\n",
|
|
|
|
- (char *)key);
|
|
|
|
- rc = -EINVAL;
|
|
|
|
- goto out;
|
|
|
|
|
|
+ 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;
|
|
|
|
+
|
|
|
|
+ for (i = 1; i < kdefs->cts_len; i++) {
|
|
|
|
+ def_class = kdefs->class_to_string[i];
|
|
|
|
+ if (i > p->p_classes.nprim) {
|
|
|
|
+ printk(KERN_INFO
|
|
|
|
+ "security: class %s not defined in policy\n",
|
|
|
|
+ def_class);
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+ pol_class = p->p_class_val_to_name[i-1];
|
|
|
|
+ if (strcmp(pol_class, def_class)) {
|
|
|
|
+ printk(KERN_ERR
|
|
|
|
+ "security: class %d is incorrect, found %s but should be %s\n",
|
|
|
|
+ i, pol_class, def_class);
|
|
|
|
+ return -EINVAL;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
- if ((cladatum->comdatum && !cladatum2->comdatum) ||
|
|
|
|
- (!cladatum->comdatum && cladatum2->comdatum)) {
|
|
|
|
- printk(KERN_ERR "security: the inherits clause for the access "
|
|
|
|
- "vector definition for class %s changed\n", (char *)key);
|
|
|
|
- rc = -EINVAL;
|
|
|
|
- goto out;
|
|
|
|
|
|
+ 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
|
|
|
|
+ "security: permission %s in class %s not defined in policy\n",
|
|
|
|
+ def_perm, pol_class);
|
|
|
|
+ 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",
|
|
|
|
+ def_perm, pol_class);
|
|
|
|
+ return -EINVAL;
|
|
|
|
+ }
|
|
|
|
+ pol_val = 1 << (perdatum->value - 1);
|
|
|
|
+ if (pol_val != perm_val) {
|
|
|
|
+ printk(KERN_ERR
|
|
|
|
+ "security: permission %s in class %s has incorrect value\n",
|
|
|
|
+ def_perm, pol_class);
|
|
|
|
+ return -EINVAL;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
- if (cladatum->comdatum) {
|
|
|
|
- rc = hashtab_map(cladatum->comdatum->permissions.table, validate_perm,
|
|
|
|
- cladatum2->comdatum->permissions.table);
|
|
|
|
- if (rc) {
|
|
|
|
- printk(" in the access vector definition for class "
|
|
|
|
- "%s\n", (char *)key);
|
|
|
|
- goto out;
|
|
|
|
|
|
+ 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
|
|
|
|
+ "security: 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
|
|
|
|
+ "security: permission %s in class %s not defined in policy\n",
|
|
|
|
+ def_perm, pol_class);
|
|
|
|
+ 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",
|
|
|
|
+ def_perm, pol_class);
|
|
|
|
+ return -EINVAL;
|
|
|
|
+ }
|
|
|
|
+ if (perdatum->value != j + 1) {
|
|
|
|
+ printk(KERN_ERR
|
|
|
|
+ "security: permission %s in class %s has incorrect value\n",
|
|
|
|
+ def_perm, pol_class);
|
|
|
|
+ return -EINVAL;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
- rc = hashtab_map(cladatum->permissions.table, validate_perm,
|
|
|
|
- cladatum2->permissions.table);
|
|
|
|
- if (rc)
|
|
|
|
- printk(" in access vector definition for class %s\n",
|
|
|
|
- (char *)key);
|
|
|
|
-out:
|
|
|
|
- return rc;
|
|
|
|
|
|
+ return 0;
|
|
}
|
|
}
|
|
|
|
|
|
/* Clone the SID into the new SID table. */
|
|
/* Clone the SID into the new SID table. */
|
|
@@ -1243,6 +1278,16 @@ int security_load_policy(void *data, size_t len)
|
|
avtab_cache_destroy();
|
|
avtab_cache_destroy();
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
|
|
+ /* Verify that the kernel defined classes are correct. */
|
|
|
|
+ if (validate_classes(&policydb)) {
|
|
|
|
+ printk(KERN_ERR
|
|
|
|
+ "security: the definition of a class is incorrect\n");
|
|
|
|
+ LOAD_UNLOCK;
|
|
|
|
+ sidtab_destroy(&sidtab);
|
|
|
|
+ policydb_destroy(&policydb);
|
|
|
|
+ avtab_cache_destroy();
|
|
|
|
+ return -EINVAL;
|
|
|
|
+ }
|
|
policydb_loaded_version = policydb.policyvers;
|
|
policydb_loaded_version = policydb.policyvers;
|
|
ss_initialized = 1;
|
|
ss_initialized = 1;
|
|
seqno = ++latest_granting;
|
|
seqno = ++latest_granting;
|
|
@@ -1265,10 +1310,10 @@ int security_load_policy(void *data, size_t len)
|
|
|
|
|
|
sidtab_init(&newsidtab);
|
|
sidtab_init(&newsidtab);
|
|
|
|
|
|
- /* Verify that the existing classes did not change. */
|
|
|
|
- if (hashtab_map(policydb.p_classes.table, validate_class, &newpolicydb)) {
|
|
|
|
- printk(KERN_ERR "security: the definition of an existing "
|
|
|
|
- "class changed\n");
|
|
|
|
|
|
+ /* Verify that the kernel defined classes are correct. */
|
|
|
|
+ if (validate_classes(&newpolicydb)) {
|
|
|
|
+ printk(KERN_ERR
|
|
|
|
+ "security: the definition of a class is incorrect\n");
|
|
rc = -EINVAL;
|
|
rc = -EINVAL;
|
|
goto err;
|
|
goto err;
|
|
}
|
|
}
|