diff options
Diffstat (limited to 'security/selinux/ss/services.c')
-rw-r--r-- | security/selinux/ss/services.c | 203 |
1 files changed, 124 insertions, 79 deletions
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index bfe122764c9..408820486af 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c @@ -17,9 +17,13 @@ * * 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) 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> * 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 @@ -53,6 +57,11 @@ extern void selnl_notify_policyload(u32 seqno); 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); #define POLICY_RDLOCK read_lock(&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. */ @@ -1243,6 +1278,16 @@ int security_load_policy(void *data, size_t len) avtab_cache_destroy(); 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; ss_initialized = 1; seqno = ++latest_granting; @@ -1265,10 +1310,10 @@ int security_load_policy(void *data, size_t len) 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; goto err; } |