Merge branch 'for-2.6.20' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/selinux-2.6
* 'for-2.6.20' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/selinux-2.6: SELinux: validate kernel object classes and permissions SELinux: ensure keys constant in hashtab_search SELinux: export object class and permission definitions SELinux: remove current object class and permission validation mechanism
This commit is contained in:
commit
b07e3c3a1d
6 changed files with 172 additions and 104 deletions
|
@ -32,12 +32,7 @@
|
|||
#include "avc.h"
|
||||
#include "avc_ss.h"
|
||||
|
||||
static const struct av_perm_to_string
|
||||
{
|
||||
u16 tclass;
|
||||
u32 value;
|
||||
const char *name;
|
||||
} av_perm_to_string[] = {
|
||||
static const struct av_perm_to_string av_perm_to_string[] = {
|
||||
#define S_(c, v, s) { c, v, s },
|
||||
#include "av_perm_to_string.h"
|
||||
#undef S_
|
||||
|
@ -57,17 +52,21 @@ static const char *class_to_string[] = {
|
|||
#undef TE_
|
||||
#undef S_
|
||||
|
||||
static const struct av_inherit
|
||||
{
|
||||
u16 tclass;
|
||||
const char **common_pts;
|
||||
u32 common_base;
|
||||
} av_inherit[] = {
|
||||
static const struct av_inherit av_inherit[] = {
|
||||
#define S_(c, i, b) { c, common_##i##_perm_to_string, b },
|
||||
#include "av_inherit.h"
|
||||
#undef S_
|
||||
};
|
||||
|
||||
const struct selinux_class_perm selinux_class_perm = {
|
||||
av_perm_to_string,
|
||||
ARRAY_SIZE(av_perm_to_string),
|
||||
class_to_string,
|
||||
ARRAY_SIZE(class_to_string),
|
||||
av_inherit,
|
||||
ARRAY_SIZE(av_inherit)
|
||||
};
|
||||
|
||||
#define AVC_CACHE_SLOTS 512
|
||||
#define AVC_DEF_CACHE_THRESHOLD 512
|
||||
#define AVC_CACHE_RECLAIM 16
|
||||
|
|
|
@ -10,5 +10,29 @@
|
|||
|
||||
int avc_ss_reset(u32 seqno);
|
||||
|
||||
struct av_perm_to_string
|
||||
{
|
||||
u16 tclass;
|
||||
u32 value;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
struct av_inherit
|
||||
{
|
||||
u16 tclass;
|
||||
const char **common_pts;
|
||||
u32 common_base;
|
||||
};
|
||||
|
||||
struct selinux_class_perm
|
||||
{
|
||||
const struct av_perm_to_string *av_perm_to_string;
|
||||
u32 av_pts_len;
|
||||
const char **class_to_string;
|
||||
u32 cts_len;
|
||||
const struct av_inherit *av_inherit;
|
||||
u32 av_inherit_len;
|
||||
};
|
||||
|
||||
#endif /* _SELINUX_AVC_SS_H_ */
|
||||
|
||||
|
|
|
@ -8,8 +8,8 @@
|
|||
#include <linux/errno.h>
|
||||
#include "hashtab.h"
|
||||
|
||||
struct hashtab *hashtab_create(u32 (*hash_value)(struct hashtab *h, void *key),
|
||||
int (*keycmp)(struct hashtab *h, void *key1, void *key2),
|
||||
struct hashtab *hashtab_create(u32 (*hash_value)(struct hashtab *h, const void *key),
|
||||
int (*keycmp)(struct hashtab *h, const void *key1, const void *key2),
|
||||
u32 size)
|
||||
{
|
||||
struct hashtab *p;
|
||||
|
@ -71,7 +71,7 @@ int hashtab_insert(struct hashtab *h, void *key, void *datum)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void *hashtab_search(struct hashtab *h, void *key)
|
||||
void *hashtab_search(struct hashtab *h, const void *key)
|
||||
{
|
||||
u32 hvalue;
|
||||
struct hashtab_node *cur;
|
||||
|
|
|
@ -22,9 +22,9 @@ struct hashtab {
|
|||
struct hashtab_node **htable; /* hash table */
|
||||
u32 size; /* number of slots in hash table */
|
||||
u32 nel; /* number of elements in hash table */
|
||||
u32 (*hash_value)(struct hashtab *h, void *key);
|
||||
u32 (*hash_value)(struct hashtab *h, const void *key);
|
||||
/* hash function */
|
||||
int (*keycmp)(struct hashtab *h, void *key1, void *key2);
|
||||
int (*keycmp)(struct hashtab *h, const void *key1, const void *key2);
|
||||
/* key comparison function */
|
||||
};
|
||||
|
||||
|
@ -39,8 +39,8 @@ struct hashtab_info {
|
|||
* Returns NULL if insufficent space is available or
|
||||
* the new hash table otherwise.
|
||||
*/
|
||||
struct hashtab *hashtab_create(u32 (*hash_value)(struct hashtab *h, void *key),
|
||||
int (*keycmp)(struct hashtab *h, void *key1, void *key2),
|
||||
struct hashtab *hashtab_create(u32 (*hash_value)(struct hashtab *h, const void *key),
|
||||
int (*keycmp)(struct hashtab *h, const void *key1, const void *key2),
|
||||
u32 size);
|
||||
|
||||
/*
|
||||
|
@ -59,7 +59,7 @@ int hashtab_insert(struct hashtab *h, void *k, void *d);
|
|||
* Returns NULL if no entry has the specified key or
|
||||
* the datum of the entry otherwise.
|
||||
*/
|
||||
void *hashtab_search(struct hashtab *h, void *k);
|
||||
void *hashtab_search(struct hashtab *h, const void *k);
|
||||
|
||||
/*
|
||||
* Destroys the specified hash table.
|
||||
|
|
|
@ -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;
|
||||
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;
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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 = 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;
|
||||
}
|
||||
}
|
||||
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;
|
||||
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;
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -9,9 +9,9 @@
|
|||
#include <linux/errno.h>
|
||||
#include "symtab.h"
|
||||
|
||||
static unsigned int symhash(struct hashtab *h, void *key)
|
||||
static unsigned int symhash(struct hashtab *h, const void *key)
|
||||
{
|
||||
char *p, *keyp;
|
||||
const char *p, *keyp;
|
||||
unsigned int size;
|
||||
unsigned int val;
|
||||
|
||||
|
@ -23,9 +23,9 @@ static unsigned int symhash(struct hashtab *h, void *key)
|
|||
return val & (h->size - 1);
|
||||
}
|
||||
|
||||
static int symcmp(struct hashtab *h, void *key1, void *key2)
|
||||
static int symcmp(struct hashtab *h, const void *key1, const void *key2)
|
||||
{
|
||||
char *keyp1, *keyp2;
|
||||
const char *keyp1, *keyp2;
|
||||
|
||||
keyp1 = key1;
|
||||
keyp2 = key2;
|
||||
|
|
Loading…
Reference in a new issue